@fungi.computer/oyster 0.0.1 → 0.2.0
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 +228 -176
- package/dist/agent-avatars.d.ts +103 -0
- package/dist/agent-avatars.js +66 -0
- package/dist/agents.d.ts +12 -2
- package/dist/agents.js +39 -2
- package/dist/app-builds.d.ts +76 -17
- package/dist/app-builds.js +207 -63
- package/dist/app-sources.d.ts +7 -22
- package/dist/app-sources.js +49 -14
- package/dist/apps/gate.d.ts +7 -7
- package/dist/apps/gate.js +6 -6
- package/dist/apps/installation.d.ts +35 -35
- package/dist/apps/installation.js +20 -19
- package/dist/build/artifact-writer.d.ts +40 -0
- package/dist/build/artifact-writer.js +181 -0
- package/dist/build/build-jobs.js +7 -1
- package/dist/build/build-policy.d.ts +10 -0
- package/dist/build/build-policy.js +10 -0
- package/dist/build/build-step.d.ts +12 -1
- package/dist/build/build-step.js +9 -1
- package/dist/build/candidate-builder.d.ts +68 -0
- package/dist/build/candidate-builder.js +91 -0
- package/dist/build/candidate-cli.d.ts +1 -0
- package/dist/build/candidate-cli.js +119 -0
- package/dist/build/candidate-cli.mjs +28220 -0
- package/dist/build/content-objects.d.ts +37 -0
- package/dist/build/content-objects.js +53 -0
- package/dist/build/effect.d.ts +18 -0
- package/dist/build/effect.js +52 -12
- package/dist/build/git-environment.d.ts +3 -0
- package/dist/build/git-environment.js +21 -9
- package/dist/build/local-build.d.ts +13 -3
- package/dist/build/local-build.js +149 -99
- package/dist/build/snapshot-package-store.d.ts +10 -0
- package/dist/build/snapshot-package-store.js +15 -0
- package/dist/build/snapshot-program-scripts.js +1 -1
- package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
- package/dist/build/snapshot-programs/snapshot-path.js +6 -0
- package/dist/build/submission-contract.d.ts +461 -17
- package/dist/build/submission-contract.js +136 -26
- package/dist/build/workspace-build.d.ts +7 -2
- package/dist/build/workspace-build.js +55 -11
- package/dist/build-contract.d.ts +3 -0
- package/dist/build-contract.js +3 -0
- package/dist/build-egress.d.ts +62 -0
- package/dist/build-egress.js +148 -0
- package/dist/build.d.ts +1 -0
- package/dist/build.js +1 -0
- package/dist/cloudflare.js +4 -4
- package/dist/frame-binding-wire-script.js +1 -1
- package/dist/frame-binding-wire.d.ts +1 -1
- package/dist/frame-binding-wire.js +1 -1
- package/dist/git-journal.js +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/installation-consent.d.ts +3 -1
- package/dist/installation-consent.js +2 -0
- package/dist/mcp-owner.js +20 -8
- package/dist/pack.d.ts +6 -3
- package/dist/pack.js +28 -11
- package/dist/page/gill-observation.d.ts +4 -0
- package/dist/page/gill-observation.js +31 -0
- package/dist/page/mount.d.ts +4 -8
- package/dist/page/window-launch.d.ts +18 -0
- package/dist/page/window-launch.js +11 -0
- package/dist/page-script.js +4 -4
- package/dist/release.d.ts +11 -0
- package/dist/release.js +4 -1
- package/dist/shell/app-directory.d.ts +50 -45
- package/dist/shell/app-directory.js +19 -18
- package/dist/shell/shell-module.d.ts +26 -2
- package/dist/shell/shell-module.js +51 -2
- package/dist/shell/window-manager.d.ts +5 -1
- package/dist/shell/window-manager.js +21 -2
- package/dist/shell/workbench-directory.d.ts +332 -0
- package/dist/shell/workbench-directory.js +35 -0
- package/dist/shell/workbench-host-types.d.ts +1 -1
- package/dist/shell/workbench-host.js +5 -0
- package/dist/shell/workbench-model.d.ts +3 -1
- package/dist/source/index.d.ts +6 -7
- package/dist/source/index.js +6 -7
- package/dist/source/template-push.d.ts +33 -0
- package/dist/source/template-push.js +223 -0
- package/dist/source/template-repository.d.ts +2 -0
- package/dist/source/template-repository.js +13 -0
- package/dist/source/{template-write.d.ts → template-seed.d.ts} +19 -20
- package/dist/source/template-seed.js +80 -0
- package/dist/standalone/agent-directory.d.ts +4 -0
- package/dist/standalone/agent-directory.js +4 -0
- package/dist/standalone/agents.d.ts +227 -0
- package/dist/standalone/agents.js +834 -0
- package/dist/standalone/app-builds-binding.d.ts +36 -0
- package/dist/standalone/app-builds-binding.js +119 -0
- package/dist/standalone/app-set.d.ts +91 -0
- package/dist/standalone/app-set.js +395 -0
- package/dist/standalone/app-source.d.ts +41 -0
- package/dist/standalone/app-source.js +59 -0
- package/dist/standalone/builds.d.ts +18 -0
- package/dist/standalone/builds.js +101 -0
- package/dist/standalone/computer-egress.d.ts +37 -0
- package/dist/standalone/computer-egress.js +111 -0
- package/dist/standalone/computer.d.ts +122 -0
- package/dist/standalone/computer.js +714 -0
- package/dist/standalone/install-apps-cli.d.ts +2 -0
- package/dist/standalone/install-apps-cli.js +126 -0
- package/dist/standalone/instance.d.ts +35 -0
- package/dist/standalone/instance.js +74 -0
- package/dist/standalone/media.d.ts +76 -0
- package/dist/standalone/media.js +227 -0
- package/dist/standalone/preview.d.ts +51 -0
- package/dist/standalone/preview.js +167 -0
- package/dist/standalone/registry.d.ts +102 -0
- package/dist/standalone/registry.js +193 -0
- package/dist/standalone/tenancy.d.ts +42 -0
- package/dist/standalone/tenancy.js +241 -0
- package/dist/standalone/worker.d.ts +55 -0
- package/dist/standalone/worker.js +147 -0
- package/dist/standalone/workflow-authority-readers.d.ts +16 -0
- package/dist/standalone/workflow-authority-readers.js +35 -0
- package/dist/standalone/workflow-binding.d.ts +216 -0
- package/dist/standalone/workflow-binding.js +217 -0
- package/dist/standalone/workflow-events.d.ts +46 -0
- package/dist/standalone/workflow-events.js +39 -0
- package/dist/standalone/workflow-git-capture.d.ts +7 -0
- package/dist/standalone/workflow-git-capture.js +62 -0
- package/dist/standalone/workflow-host.d.ts +955 -0
- package/dist/standalone/workflow-host.js +778 -0
- package/dist/standalone/workflow-node-capture.d.ts +13 -0
- package/dist/standalone/workflow-node-capture.js +72 -0
- package/dist/standalone/workflow-root-authority.d.ts +27 -0
- package/dist/standalone/workflow-root-authority.js +87 -0
- package/dist/standalone/workflow-schedules.d.ts +52 -0
- package/dist/standalone/workflow-schedules.js +40 -0
- package/dist/standalone/workflow-trigger-host.d.ts +1716 -0
- package/dist/standalone/workflow-trigger-host.js +52 -0
- package/dist/standalone/workflows.d.ts +713 -0
- package/dist/standalone/workflows.js +554 -0
- package/dist/tenancy/auth0.d.ts +64 -0
- package/dist/tenancy/auth0.js +198 -0
- package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
- package/dist/tenancy/cloudflare/rate-limit.js +19 -0
- package/dist/tenancy/cloudflare/registry.d.ts +50 -0
- package/dist/tenancy/cloudflare/registry.js +301 -0
- package/dist/tenancy/cloudflare.d.ts +2 -0
- package/dist/tenancy/cloudflare.js +2 -0
- package/dist/tenancy/cold-directory.d.ts +13 -0
- package/dist/tenancy/cold-directory.js +43 -0
- package/dist/tenancy/contracts.d.ts +195 -0
- package/dist/tenancy/contracts.js +1 -0
- package/dist/tenancy/index.d.ts +19 -0
- package/dist/tenancy/index.js +156 -0
- package/dist/tenancy/owner-key.d.ts +26 -0
- package/dist/tenancy/owner-key.js +63 -0
- package/dist/tenancy/oyster.d.ts +4 -0
- package/dist/tenancy/oyster.js +25 -0
- package/dist/tenancy/registry-record.d.ts +7 -0
- package/dist/tenancy/registry-record.js +44 -0
- package/dist/tenancy/registry.d.ts +27 -0
- package/dist/tenancy/registry.js +138 -0
- package/dist/tenancy/resolve.d.ts +7 -0
- package/dist/tenancy/resolve.js +64 -0
- package/dist/workers-git.js +1 -4
- package/dist/workers.d.ts +2 -2
- package/dist/workers.js +3 -1
- package/docs/api/build-contract.md +829 -32
- package/docs/api/build.md +253 -17
- package/docs/api/modules.md +40 -32
- package/docs/api/pack.md +6 -3
- package/docs/api/shell/app-directory.md +267 -0
- package/docs/api/shell/shell-module.md +64 -3
- package/docs/api/shell/workbench-directory.md +119 -0
- package/docs/api/shell/workbench.md +19 -0
- package/docs/api/shell.md +127 -0
- package/docs/api/tenancy/auth0.md +110 -0
- package/docs/api/tenancy/cloudflare.md +221 -0
- package/docs/api/tenancy/cold-directory.md +46 -0
- package/docs/api/tenancy/owner-key.md +63 -0
- package/docs/api/tenancy/registry.md +77 -0
- package/docs/api/tenancy/resolve.md +69 -0
- package/docs/api/tenancy.md +430 -0
- package/docs/api/workers-git.md +140 -21
- package/docs/api/workers.md +15 -2
- package/docs/site/agent-quickstart.mdx +52 -55
- package/examples/standalone/worker.ts +7 -14
- package/examples/standalone/wrangler.jsonc +67 -6
- package/package.json +78 -25
- package/dist/build/r2-artifact-writer.d.ts +0 -31
- package/dist/build/r2-artifact-writer.js +0 -179
- package/dist/source/template-write.js +0 -344
- package/docs/media/architecture.mmd +0 -32
- package/docs/media/architecture.png +0 -0
- package/docs/media/bonsai-network.png +0 -0
- package/docs/media/bonsai-repository.png +0 -0
- package/examples/git/worker.ts +0 -39
- package/examples/git/wrangler.jsonc +0 -32
|
@@ -6,7 +6,7 @@ import type { CapabilityDescriptor } from "../capability-descriptor.js";
|
|
|
6
6
|
/** Reuse the owning Effect codec at a JSON/storage boundary. */
|
|
7
7
|
export declare function ownerCodec<A, I>(schema: Schema.Codec<A, I>): z.ZodPipe<z.ZodUnknown, z.ZodTransform<Awaited<A>, unknown>>;
|
|
8
8
|
/** Installation names cannot contain the tenant separator. */
|
|
9
|
-
export declare const installationIdSchema: z.ZodString
|
|
9
|
+
export declare const installationIdSchema: z.ZodLazy<z.ZodString>;
|
|
10
10
|
export type ResourceRef = Exclude<ApprovedGrant["resources"], "tenant-scope">[number];
|
|
11
11
|
/**
|
|
12
12
|
* Consent approves capabilities, with explicit operation and resource ceilings.
|
|
@@ -21,13 +21,13 @@ export type ResourceRef = Exclude<ApprovedGrant["resources"], "tenant-scope">[nu
|
|
|
21
21
|
* Exact operation rows are enforced for capability routes and backend bindings.
|
|
22
22
|
*/
|
|
23
23
|
export declare const approvedGrantSchema: z.ZodReadonly<z.ZodObject<{
|
|
24
|
-
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
24
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
25
25
|
capabilityApproved: z.ZodLiteral<true>;
|
|
26
|
-
operations: z.ZodReadonly<z.ZodArray<z.ZodString
|
|
27
|
-
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
26
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
27
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
28
28
|
kind: z.ZodString;
|
|
29
29
|
id: z.ZodString;
|
|
30
|
-
}, z.core.$strict
|
|
30
|
+
}, z.core.$strict>>>>>]>;
|
|
31
31
|
}, z.core.$strict>>;
|
|
32
32
|
export type ApprovedGrant = Readonly<z.output<typeof approvedGrantSchema>>;
|
|
33
33
|
export type GrantRequest = Extract<InstallationCommand, {
|
|
@@ -35,7 +35,7 @@ export type GrantRequest = Extract<InstallationCommand, {
|
|
|
35
35
|
}>["grants"];
|
|
36
36
|
export type Approval = NonNullable<Installation["approval"]>;
|
|
37
37
|
/** Immutable operation facts derived from descriptor methods and the binding registry. */
|
|
38
|
-
export declare const declaredOperationsSchema: z.ZodObject<{
|
|
38
|
+
export declare const declaredOperationsSchema: z.ZodLazy<z.ZodObject<{
|
|
39
39
|
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
40
40
|
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
41
41
|
anonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
@@ -43,10 +43,10 @@ export declare const declaredOperationsSchema: z.ZodObject<{
|
|
|
43
43
|
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
44
44
|
}, z.core.$strict>>>>;
|
|
45
45
|
capabilities: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
46
|
-
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
47
|
-
operations: z.ZodReadonly<z.ZodArray<z.ZodString
|
|
46
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
47
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
48
48
|
}, z.core.$strict>>>>;
|
|
49
|
-
}, z.core.$strict
|
|
49
|
+
}, z.core.$strict>>;
|
|
50
50
|
export type DeclaredOperations = Readonly<z.output<typeof declaredOperationsSchema>>;
|
|
51
51
|
/** Use the existing adapter's permission and methods; hosts author no operation lists. */
|
|
52
52
|
export type CapabilityOperationDescriptor = Pick<CapabilityDescriptor, "id" | "methods"> & Readonly<{
|
|
@@ -54,7 +54,7 @@ export type CapabilityOperationDescriptor = Pick<CapabilityDescriptor, "id" | "m
|
|
|
54
54
|
}>;
|
|
55
55
|
/** Resolved immutable Release plus host-owned installation and approval state. */
|
|
56
56
|
export declare const installationSchema: z.ZodObject<{
|
|
57
|
-
installationId: z.ZodString
|
|
57
|
+
installationId: z.ZodLazy<z.ZodString>;
|
|
58
58
|
instanceId: z.ZodNullable<z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("../index.js").InstanceId, unknown>>>;
|
|
59
59
|
appId: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").AppId, unknown>>;
|
|
60
60
|
release: z.ZodPipe<z.ZodUnknown, z.ZodTransform<{
|
|
@@ -74,7 +74,7 @@ export declare const installationSchema: z.ZodObject<{
|
|
|
74
74
|
pinned: "pinned";
|
|
75
75
|
floating: "floating";
|
|
76
76
|
}>;
|
|
77
|
-
authorityVersion: z.ZodNumber
|
|
77
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
78
78
|
status: z.ZodEnum<{
|
|
79
79
|
enabled: "enabled";
|
|
80
80
|
disabled: "disabled";
|
|
@@ -85,16 +85,16 @@ export declare const installationSchema: z.ZodObject<{
|
|
|
85
85
|
public: "public";
|
|
86
86
|
}>;
|
|
87
87
|
declaredOperationsDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
88
|
-
approvedGrants: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
89
|
-
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
88
|
+
approvedGrants: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
89
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
90
90
|
capabilityApproved: z.ZodLiteral<true>;
|
|
91
|
-
operations: z.ZodReadonly<z.ZodArray<z.ZodString
|
|
92
|
-
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
91
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
92
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
93
93
|
kind: z.ZodString;
|
|
94
94
|
id: z.ZodString;
|
|
95
|
-
}, z.core.$strict
|
|
96
|
-
}, z.core.$strict
|
|
97
|
-
approval: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
|
|
95
|
+
}, z.core.$strict>>>>>]>;
|
|
96
|
+
}, z.core.$strict>>>>>;
|
|
97
|
+
approval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
98
98
|
by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
99
99
|
kind: import("zod/mini").ZodMiniLiteral<"member">;
|
|
100
100
|
memberId: import("zod/mini").ZodMiniString<string>;
|
|
@@ -106,13 +106,13 @@ export declare const installationSchema: z.ZodObject<{
|
|
|
106
106
|
keyId: import("zod/mini").ZodMiniString<string>;
|
|
107
107
|
}, z.core.$strip>], "kind">;
|
|
108
108
|
at: z.ZodNumber;
|
|
109
|
-
authorityVersion: z.ZodNumber
|
|
110
|
-
}, z.core.$strict
|
|
109
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
110
|
+
}, z.core.$strict>>>>;
|
|
111
111
|
approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
112
112
|
name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
|
|
113
113
|
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
114
114
|
}, z.core.$strict>>>>;
|
|
115
|
-
anonymousApproval: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
|
|
115
|
+
anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
116
116
|
by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
117
117
|
kind: import("zod/mini").ZodMiniLiteral<"member">;
|
|
118
118
|
memberId: import("zod/mini").ZodMiniString<string>;
|
|
@@ -124,19 +124,19 @@ export declare const installationSchema: z.ZodObject<{
|
|
|
124
124
|
keyId: import("zod/mini").ZodMiniString<string>;
|
|
125
125
|
}, z.core.$strip>], "kind">;
|
|
126
126
|
at: z.ZodNumber;
|
|
127
|
-
authorityVersion: z.ZodNumber
|
|
128
|
-
}, z.core.$strict
|
|
127
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
128
|
+
}, z.core.$strict>>>>;
|
|
129
129
|
}, z.core.$strict>;
|
|
130
130
|
export type Installation = Readonly<z.output<typeof installationSchema>>;
|
|
131
131
|
/** Host commands; floating targets have already been resolved to immutable Releases. */
|
|
132
|
-
export declare const installationCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
132
|
+
export declare const installationCommandSchema: z.ZodLazy<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
133
133
|
grants: z.ZodUnion<readonly [z.ZodLiteral<"none">, z.ZodLiteral<"declared">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
134
|
-
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
135
|
-
operations: z.ZodReadonly<z.ZodArray<z.ZodString
|
|
136
|
-
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
134
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
135
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
136
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
137
137
|
kind: z.ZodString;
|
|
138
138
|
id: z.ZodString;
|
|
139
|
-
}, z.core.$strict
|
|
139
|
+
}, z.core.$strict>>>>>]>;
|
|
140
140
|
}, z.core.$strict>>>>]>;
|
|
141
141
|
release: z.ZodPipe<z.ZodUnknown, z.ZodTransform<{
|
|
142
142
|
readonly releaseId: import("@fungi.computer/puffball").ReleaseId;
|
|
@@ -191,12 +191,12 @@ export declare const installationCommandSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
191
191
|
}, z.core.$strict>, z.ZodObject<{
|
|
192
192
|
kind: z.ZodLiteral<"set-grants">;
|
|
193
193
|
grants: z.ZodUnion<readonly [z.ZodLiteral<"none">, z.ZodLiteral<"declared">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
194
|
-
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
195
|
-
operations: z.ZodReadonly<z.ZodArray<z.ZodString
|
|
196
|
-
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
194
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
195
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
196
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
197
197
|
kind: z.ZodString;
|
|
198
198
|
id: z.ZodString;
|
|
199
|
-
}, z.core.$strict
|
|
199
|
+
}, z.core.$strict>>>>>]>;
|
|
200
200
|
}, z.core.$strict>>>>]>;
|
|
201
201
|
}, z.core.$strict>, z.ZodObject<{
|
|
202
202
|
kind: z.ZodLiteral<"approve-anonymous">;
|
|
@@ -204,7 +204,7 @@ export declare const installationCommandSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
204
204
|
name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
|
|
205
205
|
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
206
206
|
}, z.core.$strict>>>>;
|
|
207
|
-
}, z.core.$strict>], "kind"
|
|
207
|
+
}, z.core.$strict>], "kind">>;
|
|
208
208
|
export type InstallationCommand = z.output<typeof installationCommandSchema>;
|
|
209
209
|
/** Values captured by the host; identities and time are never generated by the reducer. */
|
|
210
210
|
export type InstallationContext = Readonly<{
|
|
@@ -221,7 +221,7 @@ export type InstallationContext = Readonly<{
|
|
|
221
221
|
}>;
|
|
222
222
|
}>;
|
|
223
223
|
/** Closed refusals: failed commands produce no installation update. */
|
|
224
|
-
export declare const installationRefusalSchema: z.ZodObject<{
|
|
224
|
+
export declare const installationRefusalSchema: z.ZodLazy<z.ZodObject<{
|
|
225
225
|
kind: z.ZodLiteral<"refused">;
|
|
226
226
|
code: z.ZodEnum<{
|
|
227
227
|
unavailable: "unavailable";
|
|
@@ -231,7 +231,7 @@ export declare const installationRefusalSchema: z.ZodObject<{
|
|
|
231
231
|
not_owner: "not_owner";
|
|
232
232
|
invalid_command: "invalid_command";
|
|
233
233
|
}>;
|
|
234
|
-
}, z.core.$strict
|
|
234
|
+
}, z.core.$strict>>;
|
|
235
235
|
export type InstallationRefusal = z.output<typeof installationRefusalSchema>;
|
|
236
236
|
export type InstallationUpdate = Readonly<{
|
|
237
237
|
next: Installation;
|
|
@@ -20,20 +20,18 @@ export function ownerCodec(schema) {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
/** Installation names cannot contain the tenant separator. */
|
|
23
|
-
export const installationIdSchema = z
|
|
24
|
-
.string()
|
|
25
|
-
.regex(/^[a-z](?:[a-z0-9]|-(?!-)){0,62}$/u);
|
|
23
|
+
export const installationIdSchema = z.lazy(() => z.string().regex(/^[a-z](?:[a-z0-9]|-(?!-)){0,62}$/u));
|
|
26
24
|
/** A resource identity minted and resolved by the host, never by this module. */
|
|
27
|
-
const resourceRefSchema = z
|
|
25
|
+
const resourceRefSchema = z.lazy(() => z
|
|
28
26
|
.strictObject({
|
|
29
27
|
kind: z.string().min(1),
|
|
30
28
|
id: z.string().min(1),
|
|
31
29
|
})
|
|
32
|
-
.readonly();
|
|
33
|
-
const operationsSchema = z
|
|
30
|
+
.readonly());
|
|
31
|
+
const operationsSchema = z.lazy(() => z
|
|
34
32
|
.array(z.string().min(1))
|
|
35
33
|
.refine((values) => new Set(values).size === values.length, "Operations must be unique")
|
|
36
|
-
.readonly();
|
|
34
|
+
.readonly());
|
|
37
35
|
/**
|
|
38
36
|
* Consent approves capabilities, with explicit operation and resource ceilings.
|
|
39
37
|
* A Release adding a method that requires an already-approved capability needs
|
|
@@ -58,10 +56,10 @@ export const approvedGrantSchema = z
|
|
|
58
56
|
})
|
|
59
57
|
.readonly();
|
|
60
58
|
/** One grant per capability keeps operation/resource pairs unambiguous. */
|
|
61
|
-
const approvedGrantsSchema = z
|
|
59
|
+
const approvedGrantsSchema = z.lazy(() => z
|
|
62
60
|
.array(approvedGrantSchema)
|
|
63
61
|
.refine((grants) => new Set(grants.map((grant) => grant.capability)).size === grants.length, "Capabilities must be unique")
|
|
64
|
-
.readonly();
|
|
62
|
+
.readonly());
|
|
65
63
|
/** Shorthand is accepted only on a command and expanded at approval time. */
|
|
66
64
|
const grantRequestSchema = z.union([
|
|
67
65
|
z.literal("none"),
|
|
@@ -74,15 +72,15 @@ const grantRequestSchema = z.union([
|
|
|
74
72
|
.refine((grants) => new Set(grants.map((grant) => grant.capability)).size === grants.length, "Capabilities must be unique")
|
|
75
73
|
.readonly(),
|
|
76
74
|
]);
|
|
77
|
-
const versionSchema = z.number().int().positive();
|
|
75
|
+
const versionSchema = z.lazy(() => z.number().int().positive());
|
|
78
76
|
/** An owner's approval of a fixed operation snapshot. */
|
|
79
|
-
const approvalSchema = z
|
|
77
|
+
const approvalSchema = z.lazy(() => z
|
|
80
78
|
.strictObject({
|
|
81
79
|
by: hostActorSchema,
|
|
82
80
|
at: z.number().int().nonnegative(),
|
|
83
81
|
authorityVersion: versionSchema,
|
|
84
82
|
})
|
|
85
|
-
.readonly();
|
|
83
|
+
.readonly());
|
|
86
84
|
const anonymousMethodsSchema = z
|
|
87
85
|
.array(z
|
|
88
86
|
.strictObject({
|
|
@@ -96,7 +94,7 @@ const anonymousMethodsSchema = z
|
|
|
96
94
|
}), "Anonymous method identities must have unique, sorted names")
|
|
97
95
|
.readonly();
|
|
98
96
|
/** Immutable operation facts derived from descriptor methods and the binding registry. */
|
|
99
|
-
export const declaredOperationsSchema = z.strictObject({
|
|
97
|
+
export const declaredOperationsSchema = z.lazy(() => z.strictObject({
|
|
100
98
|
artifactDigest: ownerCodec(sha256DigestSchema),
|
|
101
99
|
digest: ownerCodec(sha256DigestSchema),
|
|
102
100
|
anonymousMethods: anonymousMethodsSchema,
|
|
@@ -108,7 +106,7 @@ export const declaredOperationsSchema = z.strictObject({
|
|
|
108
106
|
})
|
|
109
107
|
.readonly())
|
|
110
108
|
.readonly(),
|
|
111
|
-
});
|
|
109
|
+
}));
|
|
112
110
|
/** Resolved immutable Release plus host-owned installation and approval state. */
|
|
113
111
|
export const installationSchema = z
|
|
114
112
|
.strictObject({
|
|
@@ -141,7 +139,7 @@ const releaseFields = {
|
|
|
141
139
|
releasePin: installationSchema.shape.releasePin,
|
|
142
140
|
};
|
|
143
141
|
/** Host commands; floating targets have already been resolved to immutable Releases. */
|
|
144
|
-
export const installationCommandSchema = z.discriminatedUnion("kind", [
|
|
142
|
+
export const installationCommandSchema = z.lazy(() => z.discriminatedUnion("kind", [
|
|
145
143
|
z.strictObject({
|
|
146
144
|
kind: z.literal("install"),
|
|
147
145
|
...releaseFields,
|
|
@@ -156,14 +154,17 @@ export const installationCommandSchema = z.discriminatedUnion("kind", [
|
|
|
156
154
|
kind: z.literal("set-visibility"),
|
|
157
155
|
visibility: installationSchema.shape.visibility,
|
|
158
156
|
}),
|
|
159
|
-
z.strictObject({
|
|
157
|
+
z.strictObject({
|
|
158
|
+
kind: z.literal("set-grants"),
|
|
159
|
+
grants: grantRequestSchema,
|
|
160
|
+
}),
|
|
160
161
|
z.strictObject({
|
|
161
162
|
kind: z.literal("approve-anonymous"),
|
|
162
163
|
methods: anonymousMethodsSchema,
|
|
163
164
|
}),
|
|
164
|
-
]);
|
|
165
|
+
]));
|
|
165
166
|
/** Closed refusals: failed commands produce no installation update. */
|
|
166
|
-
export const installationRefusalSchema = z.strictObject({
|
|
167
|
+
export const installationRefusalSchema = z.lazy(() => z.strictObject({
|
|
167
168
|
kind: z.literal("refused"),
|
|
168
169
|
code: z.enum([
|
|
169
170
|
"unavailable",
|
|
@@ -173,7 +174,7 @@ export const installationRefusalSchema = z.strictObject({
|
|
|
173
174
|
"release_app_mismatch",
|
|
174
175
|
"invalid_command",
|
|
175
176
|
]),
|
|
176
|
-
});
|
|
177
|
+
}));
|
|
177
178
|
/** Pure transition; hosts retain transactions, receipts, epochs and delivery. */
|
|
178
179
|
export function applyInstallationCommand(current, rawCommand, context) {
|
|
179
180
|
const refuse = (code) => Result.fail({ kind: "refused", code });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type AssetBuildPolicy } from "@fungi.computer/puffball/assets";
|
|
2
|
+
import { type ArtifactRef, type Sha256Digest } from "@fungi.computer/puffball";
|
|
3
|
+
import type { BuildOutput, StoredArtifact } from "./effect.js";
|
|
4
|
+
import type { CandidateOutputManifest } from "./submission-contract.js";
|
|
5
|
+
/** Write-once object storage for one artifact root. */
|
|
6
|
+
export type ImmutableArtifactObjects = Readonly<{
|
|
7
|
+
/** Create the object, or answer `exists` when the reference is taken. */
|
|
8
|
+
create(artifactRef: ArtifactRef, bytes: Uint8Array): Promise<"created" | "exists">;
|
|
9
|
+
/** Read the object's bytes, or `null` when absent. */
|
|
10
|
+
read(artifactRef: ArtifactRef): Promise<Uint8Array | null>;
|
|
11
|
+
}>;
|
|
12
|
+
/** One object ready to store under its reference. */
|
|
13
|
+
export type StagedArtifactObject = Readonly<{
|
|
14
|
+
artifactRef: ArtifactRef;
|
|
15
|
+
bytes: Uint8Array;
|
|
16
|
+
digest: Sha256Digest;
|
|
17
|
+
}>;
|
|
18
|
+
/** A build's output manifest and each distinct object it names. */
|
|
19
|
+
export type StagedBuildOutput = Readonly<{
|
|
20
|
+
manifest: CandidateOutputManifest;
|
|
21
|
+
objects: readonly StagedArtifactObject[];
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Stage a build's bytes: the output manifest that names each object by its
|
|
25
|
+
* digest and size, and each distinct object once.
|
|
26
|
+
*/
|
|
27
|
+
export declare function stageBuildOutput(output: BuildOutput): StagedBuildOutput;
|
|
28
|
+
/**
|
|
29
|
+
* Write the asset manifest and App root an output manifest names. The
|
|
30
|
+
* objects it names are already stored, and checked, by the caller.
|
|
31
|
+
*/
|
|
32
|
+
export declare function writeArtifactRoot(manifest: CandidateOutputManifest, objects: ImmutableArtifactObjects, options: Readonly<{
|
|
33
|
+
rootArtifactRef: ArtifactRef;
|
|
34
|
+
assetPolicy: AssetBuildPolicy | undefined;
|
|
35
|
+
}>): Promise<StoredArtifact>;
|
|
36
|
+
/** Persist one build's UI, backend and root; an existing object must hold the same bytes. */
|
|
37
|
+
export declare function writeImmutableArtifact(output: BuildOutput, objects: ImmutableArtifactObjects, options: Readonly<{
|
|
38
|
+
rootArtifactRef: ArtifactRef;
|
|
39
|
+
assetPolicy: AssetBuildPolicy | undefined;
|
|
40
|
+
}>): Promise<StoredArtifact>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Oyster's one immutable artifact representation: digest-addressed bytes
|
|
3
|
+
* keyed by artifact reference, with media types carried by the App build
|
|
4
|
+
* and asset manifests (never by the store). The local packer writes it to a
|
|
5
|
+
* directory, and a host's build owner writes it to that host's artifact store,
|
|
6
|
+
* so a Release built on the host and one packed and uploaded share objects.
|
|
7
|
+
*
|
|
8
|
+
* It has two halves. Staging turns a build's bytes into content-addressed
|
|
9
|
+
* objects and the output manifest that names them by digest and size. The
|
|
10
|
+
* root half turns an output manifest into the small objects only the store's
|
|
11
|
+
* owner writes: the asset manifest and the App root. The local packer runs
|
|
12
|
+
* both; a host whose builder uploaded the objects itself runs only the root
|
|
13
|
+
* half, over the same manifest, so both write identical root bytes.
|
|
14
|
+
*
|
|
15
|
+
* Every object is derived and checked before the first is stored: an asset
|
|
16
|
+
* build that its policy refuses, or a root over its bound, stores nothing.
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import mime from "mime";
|
|
20
|
+
import * as Schema from "effect/Schema";
|
|
21
|
+
import { assetBuildJsonSchema, assetPathSchema, decodeAssetBuild, } from "@fungi.computer/puffball/assets";
|
|
22
|
+
import { appBuildJsonSchema, createAppBuild, } from "@fungi.computer/puffball/app";
|
|
23
|
+
import { parseArtifactRef, parseSha256Digest, } from "@fungi.computer/puffball";
|
|
24
|
+
function sha256(bytes) {
|
|
25
|
+
return parseSha256Digest(`sha256:${createHash("sha256").update(bytes).digest("hex")}`);
|
|
26
|
+
}
|
|
27
|
+
/** The content address of an object: `artifact:sha256-<hex>`. */
|
|
28
|
+
function contentArtifactRef(digest) {
|
|
29
|
+
return parseArtifactRef(`artifact:sha256-${digest.slice("sha256:".length)}`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The root bound for an App whose recipe declares no asset policy: this
|
|
33
|
+
* writer's private fallback, not recipe policy. An asset recipe's own
|
|
34
|
+
* `maxManifestBytes` bounds its root as it bounds its asset manifest.
|
|
35
|
+
*/
|
|
36
|
+
const fallbackRootBytes = 1024 * 1024;
|
|
37
|
+
/**
|
|
38
|
+
* Stage a build's bytes: the output manifest that names each object by its
|
|
39
|
+
* digest and size, and each distinct object once.
|
|
40
|
+
*/
|
|
41
|
+
export function stageBuildOutput(output) {
|
|
42
|
+
const objects = [];
|
|
43
|
+
const stage = (bytes) => {
|
|
44
|
+
const digest = sha256(bytes);
|
|
45
|
+
if (!objects.some((object) => object.digest === digest))
|
|
46
|
+
objects.push({
|
|
47
|
+
artifactRef: contentArtifactRef(digest),
|
|
48
|
+
bytes: bytes.slice(),
|
|
49
|
+
digest,
|
|
50
|
+
});
|
|
51
|
+
return { digest, byteLength: bytes.byteLength };
|
|
52
|
+
};
|
|
53
|
+
const declared = output.declaration === undefined ? {} : { declaration: output.declaration };
|
|
54
|
+
const ui = (prepared) => prepared.content.kind === "html"
|
|
55
|
+
? {
|
|
56
|
+
mediaType: "text/html; charset=utf-8",
|
|
57
|
+
content: { kind: "html", ...stage(prepared.content.bytes) },
|
|
58
|
+
}
|
|
59
|
+
: {
|
|
60
|
+
mediaType: "application/vnd.fungi.app-assets+json",
|
|
61
|
+
content: {
|
|
62
|
+
kind: "assets",
|
|
63
|
+
base: prepared.content.base,
|
|
64
|
+
assets: prepared.content.assets.map((asset) => ({
|
|
65
|
+
path: asset.path,
|
|
66
|
+
...stage(asset.bytes),
|
|
67
|
+
})),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const manifest = output.kind === "ui"
|
|
71
|
+
? { kind: "ui", ui: ui(output.ui), ...declared }
|
|
72
|
+
: output.kind === "backend"
|
|
73
|
+
? { kind: "backend", backend: stage(output.backend), ...declared }
|
|
74
|
+
: {
|
|
75
|
+
kind: "app",
|
|
76
|
+
ui: ui(output.ui),
|
|
77
|
+
backend: stage(output.backend),
|
|
78
|
+
...declared,
|
|
79
|
+
};
|
|
80
|
+
return { manifest, objects };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Derive the asset manifest (for an asset UI) and the App root an output
|
|
84
|
+
* manifest names, each checked against the policy, without storing either.
|
|
85
|
+
*/
|
|
86
|
+
function artifactRootObjects(manifest, options) {
|
|
87
|
+
const objects = [];
|
|
88
|
+
const referenced = (object) => ({
|
|
89
|
+
artifactRef: contentArtifactRef(object.digest),
|
|
90
|
+
digest: object.digest,
|
|
91
|
+
version: object.digest,
|
|
92
|
+
byteLength: object.byteLength,
|
|
93
|
+
});
|
|
94
|
+
const stage = (bytes, ref) => {
|
|
95
|
+
const digest = sha256(bytes);
|
|
96
|
+
const artifactRef = ref ?? contentArtifactRef(digest);
|
|
97
|
+
objects.push({ artifactRef, bytes, digest });
|
|
98
|
+
return {
|
|
99
|
+
artifactRef,
|
|
100
|
+
digest,
|
|
101
|
+
version: digest,
|
|
102
|
+
byteLength: bytes.byteLength,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const ui = manifest.kind === "backend" ? null : manifest.ui;
|
|
106
|
+
const storedUi = (() => {
|
|
107
|
+
if (ui === null)
|
|
108
|
+
return null;
|
|
109
|
+
if (ui.content.kind === "html")
|
|
110
|
+
return { ...referenced(ui.content), mediaType: ui.mediaType };
|
|
111
|
+
if (!options.assetPolicy)
|
|
112
|
+
throw new Error("Asset writer requires explicit policy");
|
|
113
|
+
const byPath = new Map();
|
|
114
|
+
for (const asset of ui.content.assets) {
|
|
115
|
+
const path = Schema.decodeUnknownSync(assetPathSchema)(asset.path);
|
|
116
|
+
if (byPath.has(path))
|
|
117
|
+
throw new Error("Duplicate build path");
|
|
118
|
+
byPath.set(path, asset);
|
|
119
|
+
}
|
|
120
|
+
const assets = [];
|
|
121
|
+
for (const [path, asset] of [...byPath].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)) {
|
|
122
|
+
const mediaType = mime.getType(path);
|
|
123
|
+
const contentType = mediaType?.startsWith("text/")
|
|
124
|
+
? `${mediaType}; charset=utf-8`
|
|
125
|
+
: mediaType;
|
|
126
|
+
if (!contentType)
|
|
127
|
+
throw new Error("Build asset has no maintained content type");
|
|
128
|
+
assets.push({ path, ...referenced(asset), contentType });
|
|
129
|
+
}
|
|
130
|
+
const assetManifest = new TextEncoder().encode(Schema.encodeUnknownSync(assetBuildJsonSchema)({
|
|
131
|
+
format: "fungi-assets-v1",
|
|
132
|
+
base: ui.content.base,
|
|
133
|
+
assets,
|
|
134
|
+
}));
|
|
135
|
+
decodeAssetBuild(assetManifest, options.assetPolicy);
|
|
136
|
+
return { ...stage(assetManifest), mediaType: ui.mediaType };
|
|
137
|
+
})();
|
|
138
|
+
const storedBackend = manifest.kind === "ui"
|
|
139
|
+
? null
|
|
140
|
+
: {
|
|
141
|
+
...referenced(manifest.backend),
|
|
142
|
+
mediaType: "application/vnd.fungi.app-backend+json",
|
|
143
|
+
};
|
|
144
|
+
const rootBytes = new TextEncoder().encode(Schema.encodeUnknownSync(appBuildJsonSchema)(createAppBuild(storedUi, storedBackend, manifest.declaration)));
|
|
145
|
+
if (rootBytes.byteLength >
|
|
146
|
+
(options.assetPolicy?.maxManifestBytes ?? fallbackRootBytes))
|
|
147
|
+
throw new Error("App root exceeds its manifest bound");
|
|
148
|
+
const root = stage(rootBytes, options.rootArtifactRef);
|
|
149
|
+
return {
|
|
150
|
+
objects,
|
|
151
|
+
root: Object.freeze({
|
|
152
|
+
artifactRef: root.artifactRef,
|
|
153
|
+
artifactDigest: root.digest,
|
|
154
|
+
}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Store each object once; an existing object must hold the same bytes. */
|
|
158
|
+
async function storeObjects(staged, objects) {
|
|
159
|
+
for (const { artifactRef, bytes, digest } of staged)
|
|
160
|
+
if ((await objects.create(artifactRef, bytes)) === "exists") {
|
|
161
|
+
const existing = await objects.read(artifactRef);
|
|
162
|
+
if (existing === null || sha256(existing) !== digest)
|
|
163
|
+
throw new Error("Immutable artifact collision");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Write the asset manifest and App root an output manifest names. The
|
|
168
|
+
* objects it names are already stored, and checked, by the caller.
|
|
169
|
+
*/
|
|
170
|
+
export async function writeArtifactRoot(manifest, objects, options) {
|
|
171
|
+
const derived = artifactRootObjects(manifest, options);
|
|
172
|
+
await storeObjects(derived.objects, objects);
|
|
173
|
+
return derived.root;
|
|
174
|
+
}
|
|
175
|
+
/** Persist one build's UI, backend and root; an existing object must hold the same bytes. */
|
|
176
|
+
export async function writeImmutableArtifact(output, objects, options) {
|
|
177
|
+
const staged = stageBuildOutput(output);
|
|
178
|
+
const derived = artifactRootObjects(staged.manifest, options);
|
|
179
|
+
await storeObjects([...staged.objects, ...derived.objects], objects);
|
|
180
|
+
return derived.root;
|
|
181
|
+
}
|
package/dist/build/build-jobs.js
CHANGED
|
@@ -52,6 +52,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
52
52
|
});
|
|
53
53
|
import * as Schema from "effect/Schema";
|
|
54
54
|
import { base64url } from "jose";
|
|
55
|
+
import { workspaceBuildPolicy } from "./build-policy.js";
|
|
55
56
|
/** The secret-free Team job; no provider token enters publication. */
|
|
56
57
|
const jobSchema = Schema.Struct({
|
|
57
58
|
jobId: Schema.NonEmptyString,
|
|
@@ -177,6 +178,8 @@ export function createTeamBuildPublisher(options) {
|
|
|
177
178
|
export function teamAppBuildCommand(configuration, uploadGrant) {
|
|
178
179
|
const encoded = base64url.encode(JSON.stringify({
|
|
179
180
|
uploadGrant,
|
|
181
|
+
// A builder that predates this policy refuses the whole request.
|
|
182
|
+
buildPolicy: workspaceBuildPolicy,
|
|
180
183
|
appId: configuration.appId,
|
|
181
184
|
sourceRevision: configuration.sourceRevision,
|
|
182
185
|
recipe: configuration.source.recipe,
|
|
@@ -191,7 +194,10 @@ export function teamAppBuildCommand(configuration, uploadGrant) {
|
|
|
191
194
|
`trap 'rm -rf "$work"' EXIT`,
|
|
192
195
|
'mkdir "$work/tmp"',
|
|
193
196
|
'export TMPDIR="$work/tmp"',
|
|
197
|
+
"clone_started=$(date +%s%3N)",
|
|
194
198
|
'git clone -q --no-checkout -- "$TEAM_BUILD_REMOTE" "$work/source" 2>/dev/null',
|
|
195
|
-
|
|
199
|
+
// The builder reports each phase's duration with its outcome.
|
|
200
|
+
"export TEAM_BUILD_CLONE_MS=$(( $(date +%s%3N) - clone_started ))",
|
|
201
|
+
`node /opt/fungi/team-candidate-builder.mjs '${encoded}' "$work/source" "$work/candidate"`,
|
|
196
202
|
].join("\n");
|
|
197
203
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pinned workspace build policy: how a captured workspace's manifests
|
|
3
|
+
* build (`package.json#fungi.build`). v2 lets a dependency name its own
|
|
4
|
+
* package build script, which only an admitted Computer build runs.
|
|
5
|
+
*
|
|
6
|
+
* It is part of every workspace HTML recipe's toolchain, so its digest moves
|
|
7
|
+
* with it, and the Computer build request carries it at the top level, where
|
|
8
|
+
* a builder compiled before it existed refuses the request outright.
|
|
9
|
+
*/
|
|
10
|
+
export declare const workspaceBuildPolicy = "package-json-fungi-build-v2";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pinned workspace build policy: how a captured workspace's manifests
|
|
3
|
+
* build (`package.json#fungi.build`). v2 lets a dependency name its own
|
|
4
|
+
* package build script, which only an admitted Computer build runs.
|
|
5
|
+
*
|
|
6
|
+
* It is part of every workspace HTML recipe's toolchain, so its digest moves
|
|
7
|
+
* with it, and the Computer build request carries it at the top level, where
|
|
8
|
+
* a builder compiled before it existed refuses the request outright.
|
|
9
|
+
*/
|
|
10
|
+
export const workspaceBuildPolicy = "package-json-fungi-build-v2";
|
|
@@ -3,7 +3,10 @@ import * as Schema from "effect/Schema";
|
|
|
3
3
|
* One captured dependency build step. Paths are relative to the captured
|
|
4
4
|
* snapshot root. A TypeScript step compiles one config; a Tailwind step
|
|
5
5
|
* compiles one stylesheet input into its output (the same path for an App's
|
|
6
|
-
* own stylesheet, which compiles in place).
|
|
6
|
+
* own stylesheet, which compiles in place). A script step runs the one
|
|
7
|
+
* `package.json` script a workspace dependency names as its build
|
|
8
|
+
* (`fungi.build.script`), with pnpm, in that package's directory; only an
|
|
9
|
+
* admitted Computer build executes it.
|
|
7
10
|
*/
|
|
8
11
|
export declare const workspaceBuildStepSchema: Schema.Union<readonly [Schema.Struct<{
|
|
9
12
|
readonly kind: Schema.Literal<"typescript">;
|
|
@@ -12,6 +15,10 @@ export declare const workspaceBuildStepSchema: Schema.Union<readonly [Schema.Str
|
|
|
12
15
|
readonly kind: Schema.Literal<"tailwind">;
|
|
13
16
|
readonly input: Schema.String;
|
|
14
17
|
readonly output: Schema.String;
|
|
18
|
+
}>, Schema.Struct<{
|
|
19
|
+
readonly kind: Schema.Literal<"script">;
|
|
20
|
+
readonly directory: Schema.String;
|
|
21
|
+
readonly script: Schema.String;
|
|
15
22
|
}>]>;
|
|
16
23
|
/** One captured dependency build step. */
|
|
17
24
|
export type WorkspaceBuildStep = Schema.Schema.Type<typeof workspaceBuildStepSchema>;
|
|
@@ -23,4 +30,8 @@ export declare const workspaceBuildStepsJsonSchema: Schema.fromJsonString<Schema
|
|
|
23
30
|
readonly kind: Schema.Literal<"tailwind">;
|
|
24
31
|
readonly input: Schema.String;
|
|
25
32
|
readonly output: Schema.String;
|
|
33
|
+
}>, Schema.Struct<{
|
|
34
|
+
readonly kind: Schema.Literal<"script">;
|
|
35
|
+
readonly directory: Schema.String;
|
|
36
|
+
readonly script: Schema.String;
|
|
26
37
|
}>]>>>;
|
package/dist/build/build-step.js
CHANGED
|
@@ -3,7 +3,10 @@ import * as Schema from "effect/Schema";
|
|
|
3
3
|
* One captured dependency build step. Paths are relative to the captured
|
|
4
4
|
* snapshot root. A TypeScript step compiles one config; a Tailwind step
|
|
5
5
|
* compiles one stylesheet input into its output (the same path for an App's
|
|
6
|
-
* own stylesheet, which compiles in place).
|
|
6
|
+
* own stylesheet, which compiles in place). A script step runs the one
|
|
7
|
+
* `package.json` script a workspace dependency names as its build
|
|
8
|
+
* (`fungi.build.script`), with pnpm, in that package's directory; only an
|
|
9
|
+
* admitted Computer build executes it.
|
|
7
10
|
*/
|
|
8
11
|
export const workspaceBuildStepSchema = Schema.Union([
|
|
9
12
|
Schema.Struct({
|
|
@@ -15,6 +18,11 @@ export const workspaceBuildStepSchema = Schema.Union([
|
|
|
15
18
|
input: Schema.String,
|
|
16
19
|
output: Schema.String,
|
|
17
20
|
}),
|
|
21
|
+
Schema.Struct({
|
|
22
|
+
kind: Schema.Literal("script"),
|
|
23
|
+
directory: Schema.String,
|
|
24
|
+
script: Schema.String,
|
|
25
|
+
}),
|
|
18
26
|
]);
|
|
19
27
|
/** The steps one dependency-build process runs, encoded as one argument. */
|
|
20
28
|
export const workspaceBuildStepsJsonSchema = Schema.fromJsonString(Schema.Array(workspaceBuildStepSchema));
|