@fungi.computer/oyster 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +396 -72
- package/dist/agents.d.ts +3 -2
- package/dist/agents.js +4 -2
- package/dist/app-builds.d.ts +81 -8
- package/dist/app-builds.js +213 -60
- package/dist/app-storage.d.ts +3 -3
- package/dist/approval-capability.d.ts +5 -0
- package/dist/approval-capability.js +46 -0
- package/dist/approval-home.d.ts +51 -0
- package/dist/approval-home.js +226 -0
- package/dist/apps/catalog.d.ts +335 -0
- package/dist/apps/catalog.js +46 -0
- package/dist/apps/gate.d.ts +20 -6
- package/dist/apps/gate.js +42 -16
- package/dist/apps/index.d.ts +3 -1
- package/dist/apps/index.js +3 -1
- package/dist/apps/installation.d.ts +132 -51
- package/dist/apps/installation.js +176 -70
- package/dist/apps/permissions.d.ts +247 -0
- package/dist/apps/permissions.js +255 -0
- package/dist/boot-capability-route.d.ts +15 -0
- package/dist/boot-capability-route.js +196 -0
- package/dist/boot-capability.d.ts +103 -0
- package/dist/boot-capability.js +141 -0
- package/dist/boot-construction.d.ts +12 -0
- package/dist/boot-construction.js +175 -0
- package/dist/boot-gate.d.ts +267 -0
- package/dist/boot-gate.js +236 -0
- package/dist/boot-host-script.d.ts +2 -0
- package/dist/boot-host-script.js +1 -0
- package/dist/boot-mount.d.ts +21 -0
- package/dist/boot-mount.js +65 -0
- package/dist/browser/boot.d.ts +73 -0
- package/dist/browser/boot.js +502 -0
- package/dist/browser/browser.d.ts +104 -0
- package/dist/browser/browser.js +374 -0
- package/dist/browser/capability-source.d.ts +76 -0
- package/dist/browser/capability-source.js +338 -0
- package/dist/browser/cdp-client.d.ts +56 -0
- package/dist/browser/cdp-client.js +184 -0
- package/dist/browser/errors.d.ts +79 -0
- package/dist/browser/errors.js +32 -0
- package/dist/browser/index.d.ts +16 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/lease-registry.d.ts +61 -0
- package/dist/browser/lease-registry.js +101 -0
- package/dist/browser/operations.d.ts +225 -0
- package/dist/browser/operations.js +137 -0
- package/dist/browser/page.d.ts +25 -0
- package/dist/browser/page.js +172 -0
- package/dist/browser/quick-reads.d.ts +29 -0
- package/dist/browser/quick-reads.js +160 -0
- package/dist/browser/sessions.d.ts +52 -0
- package/dist/browser/sessions.js +118 -0
- package/dist/browser/url-policy.d.ts +18 -0
- package/dist/browser/url-policy.js +58 -0
- package/dist/build/app-imports.d.ts +12 -0
- package/dist/build/app-imports.js +105 -0
- package/dist/build/build-policy.d.ts +5 -3
- package/dist/build/build-policy.js +5 -3
- package/dist/build/candidate-builder.d.ts +1 -1
- package/dist/build/candidate-cli.mjs +8375 -334
- package/dist/build/local-build.d.ts +2 -0
- package/dist/build/local-build.js +28 -6
- package/dist/build/snapshot-package-store.d.ts +1 -1
- package/dist/build/snapshot-package-store.js +7 -2
- package/dist/build/workspace-build.d.ts +92 -5
- package/dist/build/workspace-build.js +93 -19
- package/dist/build.d.ts +1 -1
- package/dist/build.js +1 -1
- package/dist/catalog-frame.js +1 -1
- package/dist/cloudflare.d.ts +13 -3
- package/dist/cloudflare.js +102 -4
- package/dist/frame-binding-wire-script.js +1 -1
- package/dist/frame-binding-wire.js +4 -2
- package/dist/git-auth.d.ts +0 -2
- package/dist/git-auth.js +0 -2
- package/dist/git.d.ts +0 -1
- package/dist/git.js +0 -2
- package/dist/host.d.ts +39 -13
- package/dist/host.js +268 -142
- package/dist/index.d.ts +25 -15
- package/dist/index.js +39 -16
- package/dist/install-release-cli.d.ts +2 -0
- package/dist/install-release-cli.js +46 -0
- package/dist/installation-client.d.ts +43 -0
- package/dist/installation-client.js +178 -0
- package/dist/installation-execution.d.ts +11 -0
- package/dist/installation-execution.js +184 -0
- package/dist/installation-operations.d.ts +1437 -0
- package/dist/installation-operations.js +664 -0
- package/dist/installation-store-generation.d.ts +3 -0
- package/dist/installation-store-generation.js +16 -0
- package/dist/instance-id.d.ts +10 -0
- package/dist/instance-id.js +10 -0
- package/dist/instance-refusal.d.ts +11 -0
- package/dist/instance-refusal.js +21 -0
- package/dist/internal/delivery.js +4 -2
- package/dist/internal/host-gate.js +7 -1
- package/dist/internal/registry-installations.js +4 -4
- package/dist/keys.d.ts +5 -1
- package/dist/keys.js +10 -2
- package/dist/machine-link/authority.d.ts +89 -0
- package/dist/machine-link/authority.js +37 -0
- package/dist/machine-link/client.d.ts +66 -0
- package/dist/machine-link/client.js +94 -0
- package/dist/machine-link/delivery.d.ts +18 -0
- package/dist/machine-link/delivery.js +55 -0
- package/dist/machine-link/enrollment.d.ts +111 -0
- package/dist/machine-link/enrollment.js +286 -0
- package/dist/machine-link/fences.d.ts +37 -0
- package/dist/machine-link/fences.js +166 -0
- package/dist/machine-link/home.d.ts +20 -0
- package/dist/machine-link/home.js +24 -0
- package/dist/machine-link/host.d.ts +43 -0
- package/dist/machine-link/host.js +189 -0
- package/dist/machine-link/index.d.ts +15 -0
- package/dist/machine-link/index.js +15 -0
- package/dist/machine-link/link.d.ts +48 -0
- package/dist/machine-link/link.js +223 -0
- package/dist/machine-link/presence.d.ts +10 -0
- package/dist/machine-link/presence.js +25 -0
- package/dist/machine-link/workers.d.ts +6 -0
- package/dist/machine-link/workers.js +6 -0
- package/dist/mcp-owner.d.ts +2 -2
- package/dist/mcp-owner.js +41 -33
- package/dist/mcp.d.ts +15 -3
- package/dist/mcp.js +146 -25
- package/dist/older-oyster-store-refusal.d.ts +4 -0
- package/dist/older-oyster-store-refusal.js +18 -0
- package/dist/older-oyster-store.d.ts +21 -0
- package/dist/older-oyster-store.js +43 -0
- package/dist/pack.d.ts +14 -3
- package/dist/pack.js +44 -19
- package/dist/page/app-access.d.ts +7 -0
- package/dist/page/app-access.js +75 -0
- package/dist/page/boot-host.js +57 -0
- package/dist/page/capabilities.d.ts +3 -3
- package/dist/page/capabilities.js +16 -12
- package/dist/page/computer-handles.d.ts +3 -3
- package/dist/page/computer-target.d.ts +3 -0
- package/dist/page/computer-target.js +9 -0
- package/dist/page/mount.d.ts +23 -3
- package/dist/page/mount.js +152 -16
- package/dist/page-assets.d.ts +22 -0
- package/dist/page-assets.js +28 -0
- package/dist/page-script.d.ts +3 -0
- package/dist/page-script.js +5 -4
- package/dist/release.d.ts +13 -6
- package/dist/release.js +10 -7
- package/dist/root-data.d.ts +16 -6
- package/dist/root-data.js +2 -2
- package/dist/source/index.d.ts +1 -1
- package/dist/source/team-source.d.ts +20 -8
- package/dist/source/team-source.js +39 -10
- package/dist/source/template-seed.d.ts +2 -2
- package/dist/standalone/agent-mail.d.ts +24 -0
- package/dist/standalone/agent-mail.js +62 -0
- package/dist/standalone/agent-store.d.ts +9 -0
- package/dist/standalone/agent-store.js +30 -0
- package/dist/standalone/agents.d.ts +68 -9
- package/dist/standalone/agents.js +428 -56
- package/dist/standalone/app-builds-binding.d.ts +20 -2
- package/dist/standalone/app-builds-binding.js +147 -23
- package/dist/standalone/app-set.d.ts +5 -2
- package/dist/standalone/app-set.js +186 -144
- package/dist/standalone/browser.d.ts +11 -0
- package/dist/standalone/browser.js +72 -0
- package/dist/standalone/builds.d.ts +13 -4
- package/dist/standalone/builds.js +28 -44
- package/dist/standalone/computer-egress.d.ts +2 -0
- package/dist/standalone/computer-egress.js +13 -4
- package/dist/standalone/computer-fleet.d.ts +43 -0
- package/dist/standalone/computer-fleet.js +200 -0
- package/dist/standalone/computer.d.ts +44 -9
- package/dist/standalone/computer.js +129 -22
- package/dist/standalone/install-apps-cli.js +43 -6
- package/dist/standalone/instance.d.ts +2 -2
- package/dist/standalone/instance.js +8 -11
- package/dist/standalone/machine-link.d.ts +354 -0
- package/dist/standalone/machine-link.js +368 -0
- package/dist/standalone/media.d.ts +2 -2
- package/dist/standalone/media.js +19 -16
- package/dist/standalone/preview.d.ts +2 -2
- package/dist/standalone/preview.js +37 -10
- package/dist/standalone/registry.d.ts +151 -9
- package/dist/standalone/registry.js +305 -8
- package/dist/standalone/worker.d.ts +19 -5
- package/dist/standalone/worker.js +90 -54
- package/dist/standalone/workflow-binding.d.ts +18 -22
- package/dist/standalone/workflow-binding.js +18 -18
- package/dist/standalone/workflow-control.d.ts +4 -0
- package/dist/standalone/workflow-control.js +40 -0
- package/dist/standalone/workflow-events.d.ts +2 -2
- package/dist/standalone/workflow-events.js +9 -10
- package/dist/standalone/workflow-git-capture.js +4 -3
- package/dist/standalone/workflow-host.d.ts +162 -161
- package/dist/standalone/workflow-host.js +101 -21
- package/dist/standalone/workflow-node-capture.js +11 -4
- package/dist/standalone/workflow-schedules.d.ts +5 -2
- package/dist/standalone/workflow-schedules.js +9 -10
- package/dist/standalone/workflow-trigger-host.d.ts +65 -5
- package/dist/standalone/workflow-trigger-host.js +2 -2
- package/dist/standalone/workflow-webhooks.d.ts +22 -0
- package/dist/standalone/workflow-webhooks.js +39 -0
- package/dist/standalone/workflows.d.ts +140 -43
- package/dist/standalone/workflows.js +198 -39
- package/dist/storage-frame.d.ts +6 -6
- package/dist/testing/capabilities.js +14 -3
- package/dist/testing/installation.js +26 -2
- package/dist/testing/worker.js +1 -1
- package/dist/testing/workers-runtime.d.ts +8 -2
- package/dist/testing/workers-runtime.js +20 -2
- package/dist/webhook-abuse.d.ts +25 -0
- package/dist/webhook-abuse.js +54 -0
- package/dist/webhook-custody.d.ts +144 -0
- package/dist/webhook-custody.js +222 -0
- package/dist/webhook-ingress.d.ts +36 -0
- package/dist/webhook-ingress.js +146 -0
- package/dist/webhooks.d.ts +111 -0
- package/dist/webhooks.js +189 -0
- package/dist/workers-git.d.ts +12 -17
- package/dist/workers-git.js +64 -52
- package/dist/workers.d.ts +226 -13
- package/dist/workers.js +363 -51
- package/dist/workflow-agent-authority.d.ts +8 -0
- package/dist/workflow-agent-authority.js +42 -0
- package/dist/workflows.d.ts +66 -0
- package/dist/workflows.js +97 -0
- package/docs/api/README.md +63 -37
- package/docs/api/agents.md +17 -0
- package/docs/api/app-storage.md +1 -1
- package/docs/api/apps.md +1394 -543
- package/docs/api/browser/boot.md +132 -0
- package/docs/api/browser.md +1440 -0
- package/docs/api/build-contract.md +38 -25
- package/docs/api/build.md +263 -84
- package/docs/api/cloudflare.md +93 -7
- package/docs/api/git.md +3 -13
- package/docs/api/host.md +944 -118
- package/docs/api/index.md +320 -18
- package/docs/api/keys.md +24 -1
- package/docs/api/mcp.md +59 -12
- package/docs/api/modules.md +33 -40
- package/docs/api/pack.md +57 -8
- package/docs/api/page/mount.md +92 -4
- package/docs/api/workers-git.md +103 -24
- package/docs/api/workers.md +1594 -244
- package/docs/site/agent-quickstart.mdx +28 -14
- package/examples/standalone/worker.ts +3 -1
- package/examples/standalone/wrangler.jsonc +2 -0
- package/package.json +73 -71
- package/dist/installation-consent.d.ts +0 -81
- package/dist/installation-consent.js +0 -84
- package/dist/shell/app-directory.d.ts +0 -542
- package/dist/shell/app-directory.js +0 -196
- package/dist/shell/browser-actions.d.ts +0 -7
- package/dist/shell/browser-actions.js +0 -56
- package/dist/shell/command-host.d.ts +0 -112
- package/dist/shell/command-host.js +0 -502
- package/dist/shell/commands.d.ts +0 -25
- package/dist/shell/commands.js +0 -78
- package/dist/shell/index.d.ts +0 -8
- package/dist/shell/index.js +0 -8
- package/dist/shell/keys.d.ts +0 -41
- package/dist/shell/keys.js +0 -134
- package/dist/shell/shell-module.d.ts +0 -55
- package/dist/shell/shell-module.js +0 -86
- package/dist/shell/window-manager.d.ts +0 -128
- package/dist/shell/window-manager.js +0 -730
- package/dist/shell/workbench-contract.d.ts +0 -68
- package/dist/shell/workbench-directory.d.ts +0 -332
- package/dist/shell/workbench-directory.js +0 -35
- package/dist/shell/workbench-host-types.d.ts +0 -96
- package/dist/shell/workbench-host-types.js +0 -1
- package/dist/shell/workbench-host.d.ts +0 -34
- package/dist/shell/workbench-host.js +0 -352
- package/dist/shell/workbench-model.d.ts +0 -194
- package/dist/shell/workbench-model.js +0 -53
- package/dist/shell/workbench.d.ts +0 -4
- package/dist/shell/workbench.js +0 -2
- package/docs/api/shell/app-directory.md +0 -599
- package/docs/api/shell/command-host.md +0 -224
- package/docs/api/shell/commands.md +0 -197
- package/docs/api/shell/keys.md +0 -183
- package/docs/api/shell/shell-module.md +0 -204
- package/docs/api/shell/window-manager.md +0 -267
- package/docs/api/shell/workbench-directory.md +0 -119
- package/docs/api/shell/workbench.md +0 -205
- package/docs/api/shell.md +0 -1915
- /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
|
@@ -7,9 +7,9 @@ import { createOysterGitWorker, createOysterGitMcpOwner, oysterGitRoot, } from "
|
|
|
7
7
|
import { defaultTenant, tenantScope } from "../tenant.js";
|
|
8
8
|
import { onBoxVmIngress } from "@fungi.computer/computer";
|
|
9
9
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
10
|
+
import { installationWorkerEntrypoint } from "../installation-execution.js";
|
|
10
11
|
import { putContentObject } from "../build-contract.js";
|
|
11
|
-
import {
|
|
12
|
-
import { z } from "zod";
|
|
12
|
+
import { workflowGitPassTokenSchema } from "@fungi.computer/braid/runtime";
|
|
13
13
|
import { standaloneComputerCapabilities, standaloneWorkspace, } from "./computer.js";
|
|
14
14
|
import { StandaloneAgentBase, standaloneAgents, } from "./agents.js";
|
|
15
15
|
import { workersMedia } from "./media.js";
|
|
@@ -20,70 +20,87 @@ import { StandaloneWorkflowRunsBase, } from "./workflows.js";
|
|
|
20
20
|
import { standaloneTenancy } from "./tenancy.js";
|
|
21
21
|
export { StandaloneTenants } from "./tenancy.js";
|
|
22
22
|
import { standalonePreviewRequest } from "./preview.js";
|
|
23
|
+
import { standaloneMachineLinkRoutes, } from "./machine-link.js";
|
|
24
|
+
export { MachineLinkDO } from "./machine-link.js";
|
|
25
|
+
import { standaloneWorkflowControl } from "./workflow-control.js";
|
|
26
|
+
import { standaloneWorkflowWebhookRoutes, standaloneWorkflowWebhookControls, } from "./workflow-webhooks.js";
|
|
27
|
+
import { Hono } from "hono";
|
|
23
28
|
import { standaloneBuildRoutes } from "./builds.js";
|
|
29
|
+
import { standaloneComputerFleetRoutes, standaloneComputerSelection, } from "./computer-fleet.js";
|
|
24
30
|
import { serveOysterComputerEgress, } from "./computer-egress.js";
|
|
25
31
|
import { appSourceOwnerRoutes, } from "./app-source.js";
|
|
26
32
|
export { StandaloneGraphWorkflow } from "./workflows.js";
|
|
27
33
|
export { MediaOperationDO } from "@fungi.computer/darkroom/cloudflare";
|
|
28
34
|
/** A tenant's registry: it owns that tenant's installations and App builds. */
|
|
29
35
|
const tenantRegistry = (env, scope) => env.REGISTRY.getByName(scope.durableName("registry"));
|
|
30
|
-
/** The standalone
|
|
31
|
-
*
|
|
36
|
+
/** The standalone fleet belongs to its default tenant, whose registry also
|
|
37
|
+
* owns build jobs on the fixed build Computer. */
|
|
32
38
|
const computerRegistry = (env) => tenantRegistry(env, tenantScope(defaultTenant, env.OYSTER_ORIGIN));
|
|
33
39
|
export { ComputerDO } from "./computer.js";
|
|
34
40
|
export { WorkspaceProxy, WorkspaceServiceProxy, } from "@fungi.computer/computer";
|
|
35
|
-
|
|
41
|
+
import { StandaloneRegistry as BaseRegistry, } from "./registry.js";
|
|
42
|
+
/** The registry uses the same root, with its own in-process Computer selection. */
|
|
43
|
+
export class OysterRegistry extends BaseRegistry {
|
|
44
|
+
#rootEnv;
|
|
45
|
+
#root = standaloneRoot(() => this.selectedComputer());
|
|
46
|
+
constructor(state, env, git = {}) {
|
|
47
|
+
super(state, env, git);
|
|
48
|
+
this.#rootEnv = env;
|
|
49
|
+
}
|
|
50
|
+
hostFor(scope) {
|
|
51
|
+
return this.#root.hostFor(this.#rootEnv, scope);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
36
54
|
export { OysterKeys } from "../workers-git.js";
|
|
37
55
|
// WEBHOOKS keeps its deployed class name; the standalone owner also delivers to Workflows.
|
|
38
56
|
export { StandaloneEventDelivery as OysterWebhooks } from "./instance.js";
|
|
39
57
|
export { AgentDirectory } from "./agents.js";
|
|
40
|
-
/** After Oyster's bearer prefix: `<library>.<pass>`, as the library minted it. */
|
|
41
|
-
const workflowGitPassToken = z.lazy(() => z
|
|
42
|
-
.string()
|
|
43
|
-
.regex(/^([a-zA-Z0-9_-]{1,256})\.([0-9a-f]{64})$/u)
|
|
44
|
-
.transform((token) => {
|
|
45
|
-
const [libraryId = "", passId = ""] = token.split(".");
|
|
46
|
-
return [libraryId, passId];
|
|
47
|
-
}));
|
|
48
58
|
/** The one composition root: every door reaches a tenant's host through `hostFor`. */
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
59
|
+
const standaloneRoot = (selectComputer) => {
|
|
60
|
+
const root = oysterGitRoot({
|
|
61
|
+
tenancy: (env) => ({
|
|
62
|
+
resolve: async (request) => (await standaloneTenancy(env)).oyster.resolve(request),
|
|
63
|
+
}),
|
|
64
|
+
homeInstallationId: (env) => env.OYSTER_HOME_INSTALLATION,
|
|
65
|
+
agents: standaloneAgents,
|
|
66
|
+
workflows: standaloneWorkflowControl,
|
|
67
|
+
workspace: async (env, keysLive, scope, request) => standaloneWorkspace(env, keysLive, await selectComputer(tenantRegistry(env, scope), request)),
|
|
68
|
+
capabilities: (env, workspace, keysLive) => [
|
|
69
|
+
...standaloneComputerCapabilities(env, workspace, keysLive),
|
|
70
|
+
...workersMedia(env, workspace),
|
|
71
|
+
],
|
|
72
|
+
// A presented bearer names the library that issued it; only that
|
|
73
|
+
// library's run owner admits it, for one installation repository and scope.
|
|
74
|
+
workflowGitPass: async (env, _scope, bearer, target) => {
|
|
75
|
+
const parsed = workflowGitPassTokenSchema.safeParse(bearer);
|
|
76
|
+
if (!parsed.success)
|
|
77
|
+
return null;
|
|
78
|
+
return env.WORKFLOW_RUNS.getByName(parsed.data.ownerId).admitWorkflowGitPass(bearer, {
|
|
79
|
+
kind: "installation",
|
|
80
|
+
installationId: target.installationId,
|
|
81
|
+
repository: target.repository,
|
|
82
|
+
}, target.scope);
|
|
83
|
+
},
|
|
84
|
+
// A build job's clone reads one repository as the owner who started it.
|
|
85
|
+
buildGitPass: async (env, scope, pass, target) => {
|
|
86
|
+
const admitted = await tenantRegistry(env, scope).admitBuildGitPass(pass, target);
|
|
87
|
+
return admitted === null
|
|
88
|
+
? null
|
|
89
|
+
: {
|
|
90
|
+
kind: "actor",
|
|
91
|
+
actor: { kind: "member", memberId: admitted.requestedBy },
|
|
92
|
+
role: "owner",
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
// Operator source seeding and owner builds share the one owner guard.
|
|
96
|
+
ownerRoutes: (env, scope) => appSourceOwnerRoutes(env, scope)
|
|
97
|
+
.route("/", standaloneBuildRoutes(() => tenantRegistry(env, scope)))
|
|
98
|
+
.route("/", standaloneComputerFleetRoutes(() => tenantRegistry(env, scope)))
|
|
99
|
+
.route("/", standaloneWorkflowWebhookControls(env, () => root.hostFor(env, scope))),
|
|
100
|
+
});
|
|
101
|
+
return root;
|
|
102
|
+
};
|
|
103
|
+
const oysterRoot = standaloneRoot(standaloneComputerSelection);
|
|
87
104
|
export class OysterMcp extends createOysterGitMcpOwner(oysterRoot) {
|
|
88
105
|
}
|
|
89
106
|
/** Background wakes readmit members through this root's tenancy, as HTTP and MCP do. */
|
|
@@ -105,6 +122,9 @@ export class StandaloneWorkflowRuns extends StandaloneWorkflowRunsBase {
|
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
const oyster = createOysterGitWorker(oysterRoot);
|
|
125
|
+
/** Private loopback execution uses this root's ordinary host composition. */
|
|
126
|
+
export class OysterInstallationExecutor extends installationWorkerEntrypoint((env, scope) => oysterRoot.hostFor(env, scope)) {
|
|
127
|
+
}
|
|
108
128
|
/** The Computer's egress gateway: its own HTTPS Git back into this Worker. */
|
|
109
129
|
export class OysterComputerEgress extends WorkerEntrypoint {
|
|
110
130
|
fetch(request) {
|
|
@@ -114,6 +134,7 @@ export class OysterComputerEgress extends WorkerEntrypoint {
|
|
|
114
134
|
origin: this.env.OYSTER_ORIGIN,
|
|
115
135
|
computerId: computerObjectId,
|
|
116
136
|
publicEgress: this.env.COMPUTER_PUBLIC_EGRESS,
|
|
137
|
+
internetAccess: () => this.env.COMPUTER.get(this.env.COMPUTER.idFromString(computerObjectId)).internetAccess(),
|
|
117
138
|
build: {
|
|
118
139
|
gitPassFor: (target) => registry.buildGitPassFor(computerObjectId, target),
|
|
119
140
|
exchangeTemplate: (repository, request) => registry.exchangeBuildTemplate(computerObjectId, repository, request),
|
|
@@ -134,14 +155,29 @@ export class OysterComputerEgress extends WorkerEntrypoint {
|
|
|
134
155
|
}
|
|
135
156
|
export default {
|
|
136
157
|
async fetch(request, env, context) {
|
|
137
|
-
const
|
|
158
|
+
const path = new URL(request.url).pathname;
|
|
159
|
+
if (path === "/local/mesh/join" ||
|
|
160
|
+
new URLPattern({
|
|
161
|
+
pathname: "/api/teams/:teamId/local/mesh/:deviceId/connect",
|
|
162
|
+
}).test(request.url))
|
|
163
|
+
return standaloneMachineLinkRoutes(env).fetch(request);
|
|
164
|
+
const preview = await standalonePreviewRequest(request, env, (computerId) => computerRegistry(env).ownsComputer(computerId), (computerId, signature, port, service) => env.COMPUTER.getByName(computerId).portPreview(signature, port, service));
|
|
138
165
|
if (preview !== null)
|
|
139
166
|
return preview;
|
|
140
167
|
const ingress = onBoxVmIngress(request, env, env.COMPUTER);
|
|
141
168
|
if (ingress !== undefined)
|
|
142
169
|
return ingress;
|
|
143
|
-
|
|
170
|
+
const fetchOyster = oyster.fetch;
|
|
171
|
+
if (fetchOyster === undefined)
|
|
144
172
|
throw new Error("Oyster fetch handler is missing");
|
|
145
|
-
return
|
|
173
|
+
return new Hono()
|
|
174
|
+
.route("/", standaloneWorkflowWebhookRoutes(env, async (incoming) => {
|
|
175
|
+
const admitted = await oysterRoot.admit(env, incoming);
|
|
176
|
+
return admitted === null
|
|
177
|
+
? null
|
|
178
|
+
: oysterRoot.hostFor(env, admitted.scope);
|
|
179
|
+
}))
|
|
180
|
+
.all("*", () => fetchOyster(request, env, context))
|
|
181
|
+
.fetch(request);
|
|
146
182
|
},
|
|
147
183
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as S from "effect/Schema";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { type WorkflowGitPassGrant } from "@fungi.computer/braid/runtime";
|
|
3
4
|
import { eventDisarmInputSchema, scheduleDisarmInputSchema } from "@fungi.computer/workflows-wire";
|
|
4
5
|
import type { Installation } from "../apps/index.js";
|
|
5
|
-
import type { WorkflowGitPassResult } from "@fungi.computer/agar/computer-contracts";
|
|
6
6
|
import { type AppEventFact } from "@fungi.computer/puffball/app-event-facts";
|
|
7
7
|
import type { HostRecipientEvent } from "../workers-git.js";
|
|
8
8
|
import type { FrameBindingProps } from "../cloudflare.js";
|
|
@@ -34,6 +34,8 @@ export declare const triggerArmTargetSchema: z.ZodObject<{
|
|
|
34
34
|
kind: z.ZodLiteral<"team-source">;
|
|
35
35
|
}, z.core.$strict>>]>>;
|
|
36
36
|
workflowId: z.ZodString;
|
|
37
|
+
commit: z.ZodString;
|
|
38
|
+
triggerId: z.ZodString;
|
|
37
39
|
delivery: z.ZodOptional<z.ZodCustom<{
|
|
38
40
|
readonly agentId: string;
|
|
39
41
|
readonly sessionId: string;
|
|
@@ -41,14 +43,12 @@ export declare const triggerArmTargetSchema: z.ZodObject<{
|
|
|
41
43
|
readonly agentId: string;
|
|
42
44
|
readonly sessionId: string;
|
|
43
45
|
}>>;
|
|
44
|
-
triggerId: z.ZodString;
|
|
45
|
-
commit: z.ZodString;
|
|
46
46
|
}, z.core.$strict>;
|
|
47
47
|
export type TriggerArmTarget = z.output<typeof triggerArmTargetSchema>;
|
|
48
48
|
export type ScheduleDisarmInput = z.output<typeof scheduleDisarmInputSchema>;
|
|
49
49
|
export type EventDisarmInput = z.output<typeof eventDisarmInputSchema>;
|
|
50
50
|
/** The frame gate needs only these run-owner calls; it re-decodes each reply with the method's owner schema. */
|
|
51
|
-
export type WorkflowRunCalls = Pick<StandaloneWorkflowRunsBase, "catalog" | "start" | "status" | "cancel" | "answerReview" | "armSchedule" | "disarmSchedule" | "schedules" | "armEventTrigger" | "disarmEventTrigger" | "eventTriggers" | "runs">;
|
|
51
|
+
export type WorkflowRunCalls = Pick<StandaloneWorkflowRunsBase, "admitWorkflowGit" | "catalog" | "start" | "status" | "cancel" | "answerReview" | "armSchedule" | "disarmSchedule" | "schedules" | "armEventTrigger" | "disarmEventTrigger" | "eventTriggers" | "runs">;
|
|
52
52
|
export type WorkflowBindingEnv = Readonly<{
|
|
53
53
|
WORKFLOW_RUNS: Readonly<{
|
|
54
54
|
getByName(installationId: string): WorkflowRunCalls;
|
|
@@ -90,6 +90,7 @@ export declare const workflowFrameMethods: {
|
|
|
90
90
|
kind: "team-source";
|
|
91
91
|
}>;
|
|
92
92
|
readonly requestId: string;
|
|
93
|
+
readonly definition: S.Json;
|
|
93
94
|
readonly published: {
|
|
94
95
|
workflowId: string;
|
|
95
96
|
commit: string;
|
|
@@ -97,7 +98,6 @@ export declare const workflowFrameMethods: {
|
|
|
97
98
|
readonly appReleaseKind: "Sha256Digest";
|
|
98
99
|
};
|
|
99
100
|
};
|
|
100
|
-
readonly definition: S.Json;
|
|
101
101
|
readonly delivery?: {
|
|
102
102
|
readonly agentId: string;
|
|
103
103
|
readonly sessionId: string;
|
|
@@ -122,8 +122,8 @@ export declare const workflowFrameMethods: {
|
|
|
122
122
|
kind: "team-source";
|
|
123
123
|
}>;
|
|
124
124
|
workflowId: string;
|
|
125
|
-
triggerId: string;
|
|
126
125
|
commit: string;
|
|
126
|
+
triggerId: string;
|
|
127
127
|
delivery?: {
|
|
128
128
|
readonly agentId: string;
|
|
129
129
|
readonly sessionId: string;
|
|
@@ -138,8 +138,8 @@ export declare const workflowFrameMethods: {
|
|
|
138
138
|
kind: "team-source";
|
|
139
139
|
}>;
|
|
140
140
|
workflowId: string;
|
|
141
|
-
triggerId: string;
|
|
142
141
|
commit: string;
|
|
142
|
+
triggerId: string;
|
|
143
143
|
delivery?: {
|
|
144
144
|
readonly agentId: string;
|
|
145
145
|
readonly sessionId: string;
|
|
@@ -160,7 +160,7 @@ export declare const workflowFrameMethods: {
|
|
|
160
160
|
* delivery per library and returns; the emit never waits on a library.
|
|
161
161
|
*/
|
|
162
162
|
export declare function workflowEventRecipients(installations: Readonly<{
|
|
163
|
-
list(): Promise<readonly Pick<Installation, "installationId" | "status" | "
|
|
163
|
+
list(): Promise<readonly Pick<Installation, "installationId" | "status" | "authority">[]>;
|
|
164
164
|
}>): Promise<readonly string[]>;
|
|
165
165
|
/**
|
|
166
166
|
* One recorded delivery to one library: the host-attested fact reaches its
|
|
@@ -168,7 +168,7 @@ export declare function workflowEventRecipients(installations: Readonly<{
|
|
|
168
168
|
* so the delivery owner's retries never start a run twice.
|
|
169
169
|
*/
|
|
170
170
|
export declare function deliverWorkflowEvent(env: WorkflowEventEnv, libraryId: string, event: HostRecipientEvent): Promise<void>;
|
|
171
|
-
/** What a Workflow node frame attests when
|
|
171
|
+
/** What a Workflow node frame attests when its Git step is admitted. */
|
|
172
172
|
export declare const workflowGitPassRequestSchema: z.ZodLazy<z.ZodObject<{
|
|
173
173
|
installationId: z.ZodString;
|
|
174
174
|
idempotencyKey: z.ZodString;
|
|
@@ -191,26 +191,22 @@ export declare const workflowGitPassRequestSchema: z.ZodLazy<z.ZodObject<{
|
|
|
191
191
|
computerId: z.ZodString;
|
|
192
192
|
}, z.core.$strict>>;
|
|
193
193
|
export type WorkflowGitPassRequest = z.output<typeof workflowGitPassRequestSchema>;
|
|
194
|
-
/**
|
|
195
|
-
export type
|
|
196
|
-
OYSTER_COMPUTER_ID: string;
|
|
194
|
+
/** Each run library's per-step Workflow Git admission. */
|
|
195
|
+
export type WorkflowGitStepEnv = Readonly<{
|
|
197
196
|
WORKFLOW_RUNS: Readonly<{
|
|
198
|
-
getByName(
|
|
199
|
-
openWorkflowGitPass(request: WorkflowGitPassRequest): Promise<WorkflowGitPassResult | null>;
|
|
200
|
-
}>;
|
|
197
|
+
getByName(libraryId: string): Pick<WorkflowRunCalls, "admitWorkflowGit">;
|
|
201
198
|
}>;
|
|
202
199
|
}>;
|
|
203
200
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* stored run and mints or renews the pass.
|
|
201
|
+
* The public grant for the Git step a member Workflow node frame is running,
|
|
202
|
+
* from the run library that dispatched it; null for any other frame. Every
|
|
203
|
+
* native command the step starts carries this grant, never a credential.
|
|
208
204
|
*/
|
|
209
|
-
export declare function
|
|
210
|
-
list(): Promise<readonly Pick<Installation, "installationId" | "status" | "
|
|
205
|
+
export declare function workflowGitStepGrant(env: WorkflowGitStepEnv, installations: Readonly<{
|
|
206
|
+
list(): Promise<readonly Pick<Installation, "installationId" | "status" | "authority">[]>;
|
|
211
207
|
}>, frame: Readonly<{
|
|
212
208
|
facts: InvocationFacts;
|
|
213
209
|
signal: AbortSignal;
|
|
214
|
-
}
|
|
210
|
+
}>): Promise<WorkflowGitPassGrant | null>;
|
|
215
211
|
/** Called only after the Instance's shared gate resolves this live frame. */
|
|
216
212
|
export declare function dispatchWorkflowBinding(env: WorkflowBindingEnv, frame: InvocationFrame, props: FrameBindingProps, method: string, args: readonly unknown[]): Promise<OysterJson>;
|
|
@@ -79,7 +79,7 @@ export const workflowFrameMethods = {
|
|
|
79
79
|
export async function workflowEventRecipients(installations) {
|
|
80
80
|
return (await installations.list())
|
|
81
81
|
.filter((installation) => installation.status === "enabled" &&
|
|
82
|
-
installation.approvedGrants.some((grant) => grant.capability === "workflow.arm"))
|
|
82
|
+
installation.authority.approvedGrants.some((grant) => grant.capability === "workflow.arm"))
|
|
83
83
|
.map((installation) => installation.installationId);
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
@@ -98,7 +98,7 @@ export async function deliverWorkflowEvent(env, libraryId, event) {
|
|
|
98
98
|
});
|
|
99
99
|
await env.WORKFLOW_RUNS.getByName(libraryId).deliverEvent(fact);
|
|
100
100
|
}
|
|
101
|
-
/** What a Workflow node frame attests when
|
|
101
|
+
/** What a Workflow node frame attests when its Git step is admitted. */
|
|
102
102
|
export const workflowGitPassRequestSchema = z.lazy(() => z.strictObject({
|
|
103
103
|
installationId: z.string().min(1).max(256),
|
|
104
104
|
idempotencyKey: z.string().min(1).max(128),
|
|
@@ -107,21 +107,19 @@ export const workflowGitPassRequestSchema = z.lazy(() => z.strictObject({
|
|
|
107
107
|
computerId: z.string().min(1).max(256),
|
|
108
108
|
}));
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* stored run and mints or renews the pass.
|
|
110
|
+
* The public grant for the Git step a member Workflow node frame is running,
|
|
111
|
+
* from the run library that dispatched it; null for any other frame. Every
|
|
112
|
+
* native command the step starts carries this grant, never a credential.
|
|
114
113
|
*/
|
|
115
|
-
export async function
|
|
116
|
-
z.tuple([z.strictObject({})]).parse(args);
|
|
114
|
+
export async function workflowGitStepGrant(env, installations, frame) {
|
|
117
115
|
const { subject, selection } = frame.facts;
|
|
118
116
|
if (subject.kind !== "call" ||
|
|
119
117
|
subject.context.workflow === undefined ||
|
|
120
118
|
subject.context.idempotencyKey === undefined ||
|
|
121
119
|
subject.context.actor.kind !== "member" ||
|
|
122
|
-
subject.context.computerId
|
|
120
|
+
subject.context.computerId === null ||
|
|
123
121
|
selection.owner.kind !== "installation")
|
|
124
|
-
|
|
122
|
+
return null;
|
|
125
123
|
const request = workflowGitPassRequestSchema.parse({
|
|
126
124
|
installationId: selection.owner.id,
|
|
127
125
|
idempotencyKey: subject.context.idempotencyKey,
|
|
@@ -129,21 +127,23 @@ export async function openWorkflowGitPass(env, installations, frame, args) {
|
|
|
129
127
|
memberId: subject.context.actor.memberId,
|
|
130
128
|
computerId: subject.context.computerId,
|
|
131
129
|
});
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
for (const library of await installations.list()) {
|
|
131
|
+
if (library.status !== "enabled" ||
|
|
132
|
+
!library.authority.approvedGrants.some((grant) => grant.capability === "workflow.run"))
|
|
133
|
+
continue;
|
|
135
134
|
frame.signal.throwIfAborted();
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
return
|
|
135
|
+
const grant = await env.WORKFLOW_RUNS.getByName(library.installationId).admitWorkflowGit(request);
|
|
136
|
+
if (grant !== null)
|
|
137
|
+
return grant;
|
|
139
138
|
}
|
|
140
|
-
|
|
139
|
+
return null;
|
|
141
140
|
}
|
|
142
141
|
/** Called only after the Instance's shared gate resolves this live frame. */
|
|
143
142
|
export async function dispatchWorkflowBinding(env, frame, props, method, args) {
|
|
144
143
|
frame.signal.throwIfAborted();
|
|
145
144
|
if (props.binding !== "WORKFLOWS" ||
|
|
146
|
-
frame.facts.subject.kind !== "call"
|
|
145
|
+
(frame.facts.subject.kind !== "call" &&
|
|
146
|
+
!(method === "runGraph" && frame.facts.subject.name === "onGitPush")) ||
|
|
147
147
|
frame.facts.selection.owner.kind !== "installation")
|
|
148
148
|
throw new AppInstanceError("revoked");
|
|
149
149
|
const runs = env.WORKFLOW_RUNS.getByName(frame.facts.selection.owner.id);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OysterHost } from "../host.js";
|
|
2
|
+
import type { StandaloneWorkflowEnv } from "./workflows.js";
|
|
3
|
+
/** Locate runs in the existing library owners; never create a second run index. */
|
|
4
|
+
export declare function standaloneWorkflowControl(env: Pick<StandaloneWorkflowEnv, "WORKFLOW_RUNS">, host: Pick<OysterHost, "auth" | "installations">): NonNullable<OysterHost["workflows"]>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cancelReplySchema, statusReply } from "@fungi.computer/workflows-wire";
|
|
2
|
+
import { AppInstanceError } from "../index.js";
|
|
3
|
+
/** Locate runs in the existing library owners; never create a second run index. */
|
|
4
|
+
export function standaloneWorkflowControl(env, host) {
|
|
5
|
+
return async (principal) => {
|
|
6
|
+
if (principal.actor.kind !== "member")
|
|
7
|
+
return null;
|
|
8
|
+
const actor = principal.actor;
|
|
9
|
+
const requireOwner = async () => {
|
|
10
|
+
const current = await host.auth.resolve(actor);
|
|
11
|
+
if (current === null || !("role" in current) || current.role !== "owner")
|
|
12
|
+
throw new AppInstanceError("revoked");
|
|
13
|
+
};
|
|
14
|
+
await requireOwner();
|
|
15
|
+
const call = async (operation, runId) => {
|
|
16
|
+
await requireOwner();
|
|
17
|
+
for (const installation of await host.installations.list()) {
|
|
18
|
+
if (installation.status !== "enabled" ||
|
|
19
|
+
!installation.authority.approvedGrants.some((grant) => grant.capability === "workflow.run"))
|
|
20
|
+
continue;
|
|
21
|
+
const result = await env.WORKFLOW_RUNS.getByName(installation.installationId).control(principal, operation, runId);
|
|
22
|
+
if (result !== null)
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
status: async (runId) => {
|
|
29
|
+
const snapshot = await call("status", runId);
|
|
30
|
+
return snapshot === null
|
|
31
|
+
? null
|
|
32
|
+
: statusReply.parse(JSON.parse(JSON.stringify(snapshot)));
|
|
33
|
+
},
|
|
34
|
+
cancel: async (runId) => {
|
|
35
|
+
const result = await call("cancel", runId);
|
|
36
|
+
return cancelReplySchema.parse(result ?? { kind: "refused", reason: "denied" });
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -19,7 +19,7 @@ export declare function createStandaloneWorkflowEvents<Frame>(options: Parameter
|
|
|
19
19
|
} | {
|
|
20
20
|
kind: "refused";
|
|
21
21
|
reason: string;
|
|
22
|
-
|
|
22
|
+
error?: undefined;
|
|
23
23
|
}>;
|
|
24
24
|
disarm(frame: Frame, raw: EventDisarmInput): Promise<{
|
|
25
25
|
kind: "disarmed";
|
|
@@ -41,6 +41,6 @@ export declare function createStandaloneWorkflowEvents<Frame>(options: Parameter
|
|
|
41
41
|
state: "active" | "paused";
|
|
42
42
|
lastError: string | null;
|
|
43
43
|
}[];
|
|
44
|
-
|
|
44
|
+
error?: undefined;
|
|
45
45
|
}>;
|
|
46
46
|
};
|
|
@@ -9,30 +9,29 @@ export function createStandaloneWorkflowEvents(options) {
|
|
|
9
9
|
deliver: (fact) => router.deliver(fact),
|
|
10
10
|
async arm(frame, raw) {
|
|
11
11
|
const target = triggerArmTargetSchema.parse(raw);
|
|
12
|
-
const { libraryId, context, installationAuthority } = await options.admitInvocation(frame, "armEventTrigger");
|
|
13
|
-
if (
|
|
12
|
+
const { libraryId, context, installationAuthority, authority } = await options.admitInvocation(frame, "armEventTrigger");
|
|
13
|
+
if (authority === null)
|
|
14
14
|
return { error: "not_granted" };
|
|
15
15
|
if (context.computerId === null)
|
|
16
16
|
return {
|
|
17
17
|
kind: "refused",
|
|
18
18
|
reason: "Select a Computer before arming an event trigger",
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
return router.arm({ armedBy: context.actor.memberId, armedVia: null }, { ...target, installationId: libraryId }, context.computerId, installationAuthority);
|
|
20
|
+
return router.arm(authority.armer, { ...target, installationId: libraryId }, context.computerId, installationAuthority);
|
|
22
21
|
},
|
|
23
22
|
async disarm(frame, raw) {
|
|
24
23
|
const { eventTriggerId } = eventDisarmInputSchema.parse(raw);
|
|
25
|
-
const { libraryId,
|
|
26
|
-
if (
|
|
24
|
+
const { libraryId, authority } = await options.admitInvocation(frame, "disarmEventTrigger");
|
|
25
|
+
if (authority === null)
|
|
27
26
|
return { error: "not_granted" };
|
|
28
|
-
return router.disarm(
|
|
27
|
+
return router.disarm(authority.principal, libraryId, eventTriggerId);
|
|
29
28
|
},
|
|
30
29
|
async list(frame) {
|
|
31
|
-
const { libraryId,
|
|
32
|
-
if (
|
|
30
|
+
const { libraryId, authority } = await options.admitInvocation(frame, "eventTriggers");
|
|
31
|
+
if (authority === null)
|
|
33
32
|
return { error: "not_granted" };
|
|
34
33
|
return {
|
|
35
|
-
eventTriggers: await router.list(
|
|
34
|
+
eventTriggers: await router.list(authority.principal, libraryId),
|
|
36
35
|
};
|
|
37
36
|
},
|
|
38
37
|
};
|
|
@@ -30,9 +30,10 @@ export function createStandaloneWorkflowInstallationGitCapture(options) {
|
|
|
30
30
|
if (current?.status !== "enabled" ||
|
|
31
31
|
current.installationId !== installation.installationId ||
|
|
32
32
|
current.instanceId !== installation.instanceId ||
|
|
33
|
-
current.authorityVersion !==
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
current.authority.authorityVersion !==
|
|
34
|
+
installation.authority.authorityVersion ||
|
|
35
|
+
current.authority.declaredOperationsDigest !==
|
|
36
|
+
installation.authority.declaredOperationsDigest ||
|
|
36
37
|
current.release.appId !== installation.release.appId ||
|
|
37
38
|
current.release.releaseId !== installation.release.releaseId ||
|
|
38
39
|
current.release.artifact.artifactRef !==
|