Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/platform-command-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@druid-ui/plattform": minor
---

Add typed platform bindings for starting the deployment file service and
running or stopping deployment commands. Keep the example WIT contracts
aligned with the platform imports.
35 changes: 35 additions & 0 deletions examples/druid-plattform-no-sandbox/wit/druid-plattform.wit
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
package druid:ui;

interface plattform {
record mount {
path: string,
sub-path: string,
read-only: bool,
}

record expected-port {
name: string,
keep-alive-traffic: string,
}

record procedure {
procedure-type: string,
id: option<string>,
ignore-failure: bool,
image: string,
command: list<string>,
working-dir: string,
env: list<tuple<string, string>>,
expected-ports: list<expected-port>,
mounts: list<mount>,
target: string,
signal: string,
tty: bool,
}

record command-instruction {
procedures: list<procedure>,
needs: list<string>,
run: string,
}

request: func(url: string, method: string, body: string, header: tuple<string, string>) -> string;
load-file-from-deployment: func(path: string) -> string;
save-file-to-deployment: func(path: string, content: string) -> string;
ensure-file-service: func(watch: bool) -> string;
add-and-run-command: func(name: string, command: command-instruction) -> string;
stop-command: func(name: string) -> string;
}

world druid-plattform {
Expand Down
35 changes: 35 additions & 0 deletions examples/druid-plattform/wit/druid-plattform.wit
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
package druid:ui;

interface plattform {
record mount {
path: string,
sub-path: string,
read-only: bool,
}

record expected-port {
name: string,
keep-alive-traffic: string,
}

record procedure {
procedure-type: string,
id: option<string>,
ignore-failure: bool,
image: string,
command: list<string>,
working-dir: string,
env: list<tuple<string, string>>,
expected-ports: list<expected-port>,
mounts: list<mount>,
target: string,
signal: string,
tty: bool,
}

record command-instruction {
procedures: list<procedure>,
needs: list<string>,
run: string,
}

request: func(url: string, method: string, body: string, header: tuple<string, string>) -> string;
load-file-from-deployment: func(path: string) -> string;
save-file-to-deployment: func(path: string, content: string) -> string;
ensure-file-service: func(watch: bool) -> string;
add-and-run-command: func(name: string, command: command-instruction) -> string;
stop-command: func(name: string) -> string;
}

world druid-plattform {
Expand Down
35 changes: 35 additions & 0 deletions examples/starter-component-plattform/wit/druid-plattform.wit
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
package druid:ui;

interface plattform {
record mount {
path: string,
sub-path: string,
read-only: bool,
}

record expected-port {
name: string,
keep-alive-traffic: string,
}

record procedure {
procedure-type: string,
id: option<string>,
ignore-failure: bool,
image: string,
command: list<string>,
working-dir: string,
env: list<tuple<string, string>>,
expected-ports: list<expected-port>,
mounts: list<mount>,
target: string,
signal: string,
tty: bool,
}

record command-instruction {
procedures: list<procedure>,
needs: list<string>,
run: string,
}

request: func(url: string, method: string, body: string, header: tuple<string, string>) -> string;
load-file-from-deployment: func(path: string) -> string;
save-file-to-deployment: func(path: string, content: string) -> string;
ensure-file-service: func(watch: bool) -> string;
add-and-run-command: func(name: string, command: command-instruction) -> string;
stop-command: func(name: string) -> string;
}

world druid-plattform {
Expand Down
66 changes: 66 additions & 0 deletions packages/plattform/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import {
request as requestRaw,
loadFileFromDeployment as loadFileFromDeploymentRaw,
saveFileToDeployment as saveFileToDeploymentRaw,
ensureFileService as ensureFileServiceRaw,
addAndRunCommand as addAndRunCommandRaw,
stopCommand as stopCommandRaw,
} from "druid:ui/plattform";
import type { CommandInstruction as RawCommandInstruction } from "druid:ui/plattform";
// it is very imporant that this is external, as druid-ui/component contains
// functions that must be important and cannot just be copied in again
// otherwise promises defined here will not resolve
Expand All @@ -17,3 +21,65 @@ export const loadFileFromDeployment = rawAsyncToPromise(
);

export const saveFileToDeployment = rawAsyncToPromise(saveFileToDeploymentRaw);

export type CommandRunMode = "always" | "once" | "restart" | "persistent";
export type ProcedureType = "container" | "signal";

export interface CommandMount {
path: string;
subPath: string;
readOnly: boolean;
}

export interface CommandExpectedPort {
name: string;
keepAliveTraffic: string;
}

export interface CommandProcedure {
type?: ProcedureType;
id?: string;
ignoreFailure?: boolean;
image?: string;
command?: string[];
workingDir?: string;
env?: Record<string, string>;
expectedPorts?: CommandExpectedPort[];
mounts?: CommandMount[];
target?: string;
signal?: string;
tty?: boolean;
}

export interface CommandInstruction {
procedures: CommandProcedure[];
needs?: string[];
run?: CommandRunMode;
}

const toRawCommandInstruction = (command: CommandInstruction): RawCommandInstruction => ({
run: command.run ?? "always",
needs: command.needs ?? [],
procedures: command.procedures.map((procedure) => ({
procedureType: procedure.type ?? "container",
...(procedure.id === undefined ? {} : { id: procedure.id }),
ignoreFailure: procedure.ignoreFailure ?? false,
image: procedure.image ?? "",
command: procedure.command ?? [],
workingDir: procedure.workingDir ?? "",
env: Object.entries(procedure.env ?? {}),
expectedPorts: procedure.expectedPorts ?? [],
mounts: procedure.mounts ?? [],
target: procedure.target ?? "",
signal: procedure.signal ?? "",
tty: procedure.tty ?? false,
})),
});

export const ensureFileService = (watch = false): Promise<void> =>
rawAsyncToPromise(ensureFileServiceRaw)(watch).then(() => undefined);

export const addAndRunCommand = (name: string, command: CommandInstruction): Promise<void> =>
rawAsyncToPromise(addAndRunCommandRaw)(name, toRawCommandInstruction(command)).then(() => undefined);

export const stopCommand = (name: string): Promise<void> => rawAsyncToPromise(stopCommandRaw)(name).then(() => undefined);
35 changes: 35 additions & 0 deletions packages/plattform/wit/druid-plattform.wit
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
package druid:ui;

interface plattform {
record mount {
path: string,
sub-path: string,
read-only: bool,
}

record expected-port {
name: string,
keep-alive-traffic: string,
}

record procedure {
procedure-type: string,
id: option<string>,
ignore-failure: bool,
image: string,
command: list<string>,
working-dir: string,
env: list<tuple<string, string>>,
expected-ports: list<expected-port>,
mounts: list<mount>,
target: string,
signal: string,
tty: bool,
}

record command-instruction {
procedures: list<procedure>,
needs: list<string>,
run: string,
}

request: func(url: string, method: string, body: string, header: tuple<string, string>) -> string;
load-file-from-deployment: func(path: string) -> string;
save-file-to-deployment: func(path: string, content: string) -> string;
ensure-file-service: func(watch: bool) -> string;
add-and-run-command: func(name: string, command: command-instruction) -> string;
stop-command: func(name: string) -> string;
}

world druid-plattform {
Expand Down
9 changes: 9 additions & 0 deletions tests/async-wit-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import { readFile } from "node:fs/promises";
import { describe, expect, it } from "vitest";

describe("async WIT contract", () => {
it("keeps the platform command bindings aligned with shipped examples", async () => {
const source = await readFile("packages/plattform/wit/druid-plattform.wit", "utf8");
expect(source).toContain("ensure-file-service: func(watch: bool) -> string;");
expect(source).toContain("add-and-run-command: func(name: string, command: command-instruction) -> string;");
expect(source).toContain("stop-command: func(name: string) -> string;");
for (const example of ["druid-plattform", "druid-plattform-no-sandbox", "starter-component-plattform"]) {
expect(await readFile(`examples/${example}/wit/druid-plattform.wit`, "utf8")).toBe(source);
}
});
it.each(["wit/druid-component.wit", "packages/build/wit/druid-component.wit"])(
"%s transports error messages",
async (path) => {
Expand Down
Loading
Loading