@fungi.computer/oyster 0.0.1 → 0.1.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/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/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 +28170 -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/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/window-launch.d.ts +18 -0
- package/dist/page/window-launch.js +11 -0
- package/dist/page-script.js +2 -2
- package/dist/release.d.ts +11 -0
- package/dist/release.js +4 -1
- package/dist/shell/app-directory.d.ts +13 -8
- package/dist/shell/app-directory.js +4 -0
- package/dist/shell/shell-module.d.ts +26 -2
- package/dist/shell/shell-module.js +51 -2
- package/dist/shell/workbench-directory.d.ts +332 -0
- package/dist/shell/workbench-directory.js +35 -0
- 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 +220 -0
- package/dist/standalone/agents.js +795 -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 +931 -0
- package/dist/standalone/workflow-host.js +751 -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 +1694 -0
- package/dist/standalone/workflow-trigger-host.js +52 -0
- package/dist/standalone/workflows.d.ts +657 -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.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 +72 -21
- 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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A build's uploaded objects in an R2-shaped store: content addressed
|
|
3
|
+
* (`artifact:sha256-<hex>`), written once from a stream with the store
|
|
4
|
+
* itself verifying the digest, and described by `head()` without a read.
|
|
5
|
+
* The bytes never pass through an isolate's memory as a whole.
|
|
6
|
+
*/
|
|
7
|
+
import { type ArtifactRef, type Sha256Digest } from "@fungi.computer/puffball";
|
|
8
|
+
import type { ArtifactHead } from "../release.js";
|
|
9
|
+
import type { CandidateObject, CandidateObjectMediaType } from "./submission-contract.js";
|
|
10
|
+
/** The parts of an R2 bucket a content-object store uses. */
|
|
11
|
+
export type ContentObjectBucket = Readonly<{
|
|
12
|
+
/** Describe the object at `key` without its body, or `null` when absent. */
|
|
13
|
+
head(key: string): Promise<Readonly<{
|
|
14
|
+
size: number;
|
|
15
|
+
checksums: Readonly<{
|
|
16
|
+
sha256?: ArrayBuffer;
|
|
17
|
+
}>;
|
|
18
|
+
}> | null>;
|
|
19
|
+
/** Store `value` at `key`; the bucket refuses bytes whose SHA-256 differs. */
|
|
20
|
+
put(key: string, value: ReadableStream<Uint8Array> | Uint8Array, options: Readonly<{
|
|
21
|
+
sha256: string;
|
|
22
|
+
httpMetadata: Readonly<{
|
|
23
|
+
contentType: CandidateObjectMediaType;
|
|
24
|
+
}>;
|
|
25
|
+
}>): Promise<object | null>;
|
|
26
|
+
}>;
|
|
27
|
+
/** The store key of one content-addressed object. */
|
|
28
|
+
export declare function contentObjectRef(digest: Sha256Digest): ArtifactRef;
|
|
29
|
+
/** Describe a stored object by its size and the SHA-256 the store verified. */
|
|
30
|
+
export declare function headContentObject(bucket: ContentObjectBucket, artifactRef: ArtifactRef): Promise<ArtifactHead | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Stream one object into the store under its digest. The store refuses a
|
|
33
|
+
* body whose SHA-256 differs; an object already stored with the same
|
|
34
|
+
* verified digest and size is kept (write-once: a stored version may be
|
|
35
|
+
* pinned by a Release) and the body is discarded, never stored.
|
|
36
|
+
*/
|
|
37
|
+
export declare function putContentObject(bucket: ContentObjectBucket, object: CandidateObject, body: ReadableStream<Uint8Array> | null, mediaType: CandidateObjectMediaType): Promise<"stored" | "refused">;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A build's uploaded objects in an R2-shaped store: content addressed
|
|
3
|
+
* (`artifact:sha256-<hex>`), written once from a stream with the store
|
|
4
|
+
* itself verifying the digest, and described by `head()` without a read.
|
|
5
|
+
* The bytes never pass through an isolate's memory as a whole.
|
|
6
|
+
*/
|
|
7
|
+
import { parseArtifactRef, parseSha256Digest, } from "@fungi.computer/puffball";
|
|
8
|
+
/** The store key of one content-addressed object. */
|
|
9
|
+
export function contentObjectRef(digest) {
|
|
10
|
+
return parseArtifactRef(`artifact:sha256-${digest.slice("sha256:".length)}`);
|
|
11
|
+
}
|
|
12
|
+
function hex(bytes) {
|
|
13
|
+
return Array.from(new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
14
|
+
}
|
|
15
|
+
/** Describe a stored object by its size and the SHA-256 the store verified. */
|
|
16
|
+
export async function headContentObject(bucket, artifactRef) {
|
|
17
|
+
const object = await bucket.head(artifactRef);
|
|
18
|
+
if (object === null)
|
|
19
|
+
return null;
|
|
20
|
+
const sha256 = object.checksums.sha256;
|
|
21
|
+
return {
|
|
22
|
+
byteLength: object.size,
|
|
23
|
+
digest: sha256 === undefined ? null : parseSha256Digest(`sha256:${hex(sha256)}`),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Stream one object into the store under its digest. The store refuses a
|
|
28
|
+
* body whose SHA-256 differs; an object already stored with the same
|
|
29
|
+
* verified digest and size is kept (write-once: a stored version may be
|
|
30
|
+
* pinned by a Release) and the body is discarded, never stored.
|
|
31
|
+
*/
|
|
32
|
+
export async function putContentObject(bucket, object, body, mediaType) {
|
|
33
|
+
const artifactRef = contentObjectRef(object.digest);
|
|
34
|
+
const existing = await headContentObject(bucket, artifactRef);
|
|
35
|
+
if (existing !== null &&
|
|
36
|
+
existing.digest === object.digest &&
|
|
37
|
+
existing.byteLength === object.byteLength) {
|
|
38
|
+
// Read the body through (discarding it) rather than cancel it: a
|
|
39
|
+
// cancelled request body resets the uploader's connection mid-send.
|
|
40
|
+
await body?.pipeTo(new WritableStream());
|
|
41
|
+
return "stored";
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await bucket.put(artifactRef, body ?? new Uint8Array(0), {
|
|
45
|
+
sha256: object.digest.slice("sha256:".length),
|
|
46
|
+
httpMetadata: { contentType: mediaType },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return "refused";
|
|
51
|
+
}
|
|
52
|
+
return "stored";
|
|
53
|
+
}
|
package/dist/build/effect.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { AppDeclaration } from "@fungi.computer/puffball";
|
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
import type * as Scope from "effect/Scope";
|
|
6
|
+
import type { CandidateOutputManifest } from "./submission-contract.js";
|
|
6
7
|
/** Canonical recipe policy shared by core and the local adapter. */
|
|
7
8
|
export declare const pinnedRecipeSchema: Schema.Struct<{
|
|
8
9
|
readonly kind: Schema.optional<Schema.Literals<readonly ["bundled-html", "source-html"]>>;
|
|
@@ -211,6 +212,12 @@ export type CapturedConfig = Readonly<{
|
|
|
211
212
|
readonly recipe: PinnedRecipe;
|
|
212
213
|
readonly buildRecipeDigest: Sha256Digest;
|
|
213
214
|
}>;
|
|
215
|
+
/**
|
|
216
|
+
* Whether a pinned recipe pins this Publisher's current toolchain (its build
|
|
217
|
+
* policy included). An executor refuses any other: a recipe pinned under
|
|
218
|
+
* another policy describes a build this code does not perform.
|
|
219
|
+
*/
|
|
220
|
+
export declare function pinsCurrentToolchain(recipe: PinnedRecipe): boolean;
|
|
214
221
|
/** Hash every captured build and output-policy input in the Publisher recipe. */
|
|
215
222
|
export declare function digestPinnedRecipe(recipe: PinnedRecipe): Sha256Digest;
|
|
216
223
|
/** Decode and normalize Publisher-owned recipe policy for durable seed proof. */
|
|
@@ -221,6 +228,17 @@ export declare function normalizeAppPublisherRecipe(input: {
|
|
|
221
228
|
recipe: PinnedRecipe;
|
|
222
229
|
buildRecipeDigest: Sha256Digest;
|
|
223
230
|
}>;
|
|
231
|
+
/**
|
|
232
|
+
* The largest single object a build under this recipe may upload: no larger
|
|
233
|
+
* than the largest output bound the recipe could assign it under.
|
|
234
|
+
*/
|
|
235
|
+
export declare function pinnedRecipeObjectBound(recipe: PinnedRecipe): number;
|
|
236
|
+
/**
|
|
237
|
+
* Whether output built elsewhere (a Computer's candidate manifest) is one
|
|
238
|
+
* this recipe could assign: the same surfaces and `maxOutputBytes` bound the
|
|
239
|
+
* preparer applies here. Asset sizes stay the artifact writer's policy.
|
|
240
|
+
*/
|
|
241
|
+
export declare function fitsPinnedRecipe(output: CandidateOutputManifest, recipe: PinnedRecipe): boolean;
|
|
224
242
|
/** Construct one private App Publisher with copied core configuration and roles. */
|
|
225
243
|
export declare function createAppCandidatePreparer(options: Pick<AppPublisherOptions, "config" | "sourceCapture" | "buildExecutor">): AppCandidatePreparer;
|
|
226
244
|
/** Prepare a candidate from a previously captured recipe. */
|
package/dist/build/effect.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assetBuildPolicySchema, assetBaseSchema, } from "@fungi.computer/puffball/assets";
|
|
2
2
|
import { boundedBundlePolicy, bundledHtmlRecipe } from "./html-recipe.js";
|
|
3
|
+
import { workspaceBuildPolicy } from "./build-policy.js";
|
|
3
4
|
import * as crypto from "node:crypto";
|
|
4
5
|
import { backendJsonSchema, durableBackendSchema, } from "@fungi.computer/puffball/backend";
|
|
5
6
|
import { parseSha256Digest, } from "@fungi.computer/puffball";
|
|
@@ -63,7 +64,7 @@ const workspaceHtmlToolchain = Object.freeze({
|
|
|
63
64
|
tailwindOxide: "4.2.1",
|
|
64
65
|
tailwindResolver: "5.24.5",
|
|
65
66
|
typography: "0.5.19",
|
|
66
|
-
buildPolicy:
|
|
67
|
+
buildPolicy: workspaceBuildPolicy,
|
|
67
68
|
recipe: "captured-workspace-html-v1",
|
|
68
69
|
});
|
|
69
70
|
const workspaceHtmlBackendToolchain = Object.freeze({
|
|
@@ -104,6 +105,29 @@ export class AppPublisherError extends Error {
|
|
|
104
105
|
function sha256Digest(value) {
|
|
105
106
|
return parseSha256Digest(`sha256:${crypto.createHash("sha256").update(value, "utf8").digest("hex")}`);
|
|
106
107
|
}
|
|
108
|
+
/** The toolchain this Publisher pins for a recipe of this kind, entry and backend. */
|
|
109
|
+
function currentToolchain(recipe) {
|
|
110
|
+
if (recipe.kind === "source-html")
|
|
111
|
+
return sourceHtmlToolchain;
|
|
112
|
+
if (recipe.kind === bundledHtmlRecipe.kind)
|
|
113
|
+
return recipe.backend === null
|
|
114
|
+
? bundledHtmlRecipe.toolchain
|
|
115
|
+
: { ...bundledHtmlRecipe.toolchain, ...esmToolchain, pnpm: "11.24.0" };
|
|
116
|
+
if (recipe.entry.endsWith(".html"))
|
|
117
|
+
return recipe.backend === null
|
|
118
|
+
? workspaceHtmlToolchain
|
|
119
|
+
: workspaceHtmlBackendToolchain;
|
|
120
|
+
return esmToolchain;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Whether a pinned recipe pins this Publisher's current toolchain (its build
|
|
124
|
+
* policy included). An executor refuses any other: a recipe pinned under
|
|
125
|
+
* another policy describes a build this code does not perform.
|
|
126
|
+
*/
|
|
127
|
+
export function pinsCurrentToolchain(recipe) {
|
|
128
|
+
const entries = (toolchain) => JSON.stringify(Object.entries(toolchain).sort(([a], [b]) => a.localeCompare(b)));
|
|
129
|
+
return entries(currentToolchain(recipe)) === entries(recipe.toolchain);
|
|
130
|
+
}
|
|
107
131
|
function captureConfig(input) {
|
|
108
132
|
let decoded;
|
|
109
133
|
try {
|
|
@@ -148,17 +172,7 @@ function captureConfig(input) {
|
|
|
148
172
|
: workspaceHtml
|
|
149
173
|
? "html"
|
|
150
174
|
: "esm",
|
|
151
|
-
toolchain:
|
|
152
|
-
? sourceHtmlToolchain
|
|
153
|
-
: bundled
|
|
154
|
-
? decoded.recipe.backend === null
|
|
155
|
-
? bundledHtmlRecipe.toolchain
|
|
156
|
-
: { ...bundledHtmlRecipe.toolchain, ...esmToolchain, pnpm: "11.24.0" }
|
|
157
|
-
: workspaceHtml
|
|
158
|
-
? decoded.recipe.backend === null
|
|
159
|
-
? workspaceHtmlToolchain
|
|
160
|
-
: workspaceHtmlBackendToolchain
|
|
161
|
-
: esmToolchain,
|
|
175
|
+
toolchain: currentToolchain(decoded.recipe),
|
|
162
176
|
maxOutputBytes: decoded.recipe.maxOutputBytes,
|
|
163
177
|
platform: decoded.recipe.backend === null
|
|
164
178
|
? "browser"
|
|
@@ -303,6 +317,32 @@ function encodeBackendOutput(bytes, recipe) {
|
|
|
303
317
|
code: new TextDecoder().decode(bytes),
|
|
304
318
|
}).pipe(Effect.map((encoded) => new TextEncoder().encode(encoded)), Effect.filterOrFail((encoded) => encoded.byteLength <= recipe.maxOutputBytes, () => stageFailure("build")), Effect.mapError(() => stageFailure("build")));
|
|
305
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* The largest single object a build under this recipe may upload: no larger
|
|
322
|
+
* than the largest output bound the recipe could assign it under.
|
|
323
|
+
*/
|
|
324
|
+
export function pinnedRecipeObjectBound(recipe) {
|
|
325
|
+
return Math.max(recipe.maxOutputBytes, recipe.assets?.maxObjectBytes ?? 0);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Whether output built elsewhere (a Computer's candidate manifest) is one
|
|
329
|
+
* this recipe could assign: the same surfaces and `maxOutputBytes` bound the
|
|
330
|
+
* preparer applies here. Asset sizes stay the artifact writer's policy.
|
|
331
|
+
*/
|
|
332
|
+
export function fitsPinnedRecipe(output, recipe) {
|
|
333
|
+
const uiFits = (ui) => ui.content.kind === "html"
|
|
334
|
+
? ui.content.byteLength <= recipe.maxOutputBytes
|
|
335
|
+
: recipe.assets !== undefined && ui.content.base === recipe.assetBase;
|
|
336
|
+
const backendFits = (backend) => recipe.backend !== null && backend.byteLength <= recipe.maxOutputBytes;
|
|
337
|
+
switch (output.kind) {
|
|
338
|
+
case "ui":
|
|
339
|
+
return recipe.backend === null && uiFits(output.ui);
|
|
340
|
+
case "backend":
|
|
341
|
+
return backendFits(output.backend);
|
|
342
|
+
case "app":
|
|
343
|
+
return uiFits(output.ui) && backendFits(output.backend);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
306
346
|
function assignAppOutput(built, recipe) {
|
|
307
347
|
switch (built.kind) {
|
|
308
348
|
case "bytes":
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** Run a nested repository without inheriting the caller's Git checkout. */
|
|
2
2
|
export declare function repositoryEnvironment(): NodeJS.ProcessEnv;
|
|
3
|
+
/** Git environment carrying host-held request headers (credentials) only in
|
|
4
|
+
* Git's own config environment: never argv, a URL or a trace. */
|
|
5
|
+
export declare function authenticatedGitEnvironment(headers: Readonly<Record<string, string>>): NodeJS.ProcessEnv;
|
|
3
6
|
/** Git environment for one authenticated Artifacts fetch; caller validates token. */
|
|
4
7
|
export declare function artifactsGitEnvironment(token: string): NodeJS.ProcessEnv;
|
|
5
8
|
/** Credential-free private route used by the hosted Publisher Git client. */
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
export function repositoryEnvironment() {
|
|
3
3
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.startsWith("GIT_")));
|
|
4
4
|
}
|
|
5
|
-
/** Git environment
|
|
6
|
-
|
|
5
|
+
/** Git environment carrying host-held request headers (credentials) only in
|
|
6
|
+
* Git's own config environment: never argv, a URL or a trace. */
|
|
7
|
+
export function authenticatedGitEnvironment(headers) {
|
|
7
8
|
const excludedEnvironmentNames = new Set([
|
|
8
9
|
"GIT_CURL_VERBOSE",
|
|
9
10
|
"CLOUDFLARE_API_TOKEN",
|
|
@@ -12,19 +13,30 @@ export function artifactsGitEnvironment(token) {
|
|
|
12
13
|
"ARTIFACTS_TOKEN",
|
|
13
14
|
]);
|
|
14
15
|
const environment = Object.fromEntries(Object.entries(repositoryEnvironment()).filter(([name]) => !name.startsWith("GIT_TRACE") && !excludedEnvironmentNames.has(name)));
|
|
16
|
+
for (const [name, value] of Object.entries(headers))
|
|
17
|
+
if (!/^[A-Za-z0-9-]+$/u.test(name) || /[\r\n\0]/u.test(value))
|
|
18
|
+
throw new Error("Git request header is invalid");
|
|
19
|
+
// An empty first value resets any inherited extra headers.
|
|
20
|
+
const config = [
|
|
21
|
+
["http.extraHeader", ""],
|
|
22
|
+
...Object.entries(headers).map(([name, value]) => ["http.extraHeader", `${name}: ${value}`]),
|
|
23
|
+
["http.followRedirects", "false"],
|
|
24
|
+
];
|
|
15
25
|
return {
|
|
16
26
|
...environment,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
GIT_CONFIG_VALUE_2: "false",
|
|
23
|
-
GIT_CONFIG_COUNT: "3",
|
|
27
|
+
...Object.fromEntries(config.flatMap(([key, value], index) => [
|
|
28
|
+
[`GIT_CONFIG_KEY_${String(index)}`, key],
|
|
29
|
+
[`GIT_CONFIG_VALUE_${String(index)}`, value],
|
|
30
|
+
])),
|
|
31
|
+
GIT_CONFIG_COUNT: String(config.length),
|
|
24
32
|
GIT_TRACE: "0",
|
|
25
33
|
GIT_TRACE_CURL: "0",
|
|
26
34
|
};
|
|
27
35
|
}
|
|
36
|
+
/** Git environment for one authenticated Artifacts fetch; caller validates token. */
|
|
37
|
+
export function artifactsGitEnvironment(token) {
|
|
38
|
+
return authenticatedGitEnvironment({ Authorization: `Bearer ${token}` });
|
|
39
|
+
}
|
|
28
40
|
/** Credential-free private route used by the hosted Publisher Git client. */
|
|
29
41
|
export function hostedArtifactsGitRemote(endpoint, repository) {
|
|
30
42
|
if (!/^[a-zA-Z0-9._-]{1,128}$/.test(repository))
|
|
@@ -40,12 +40,22 @@ export declare function createFirstPartyAppSourceDistribution(options: {
|
|
|
40
40
|
readonly source: CapturedSource;
|
|
41
41
|
readonly entry: string;
|
|
42
42
|
}): Effect.Effect<FirstPartyAppSourceDistribution, unknown>;
|
|
43
|
+
/** How one build executor is composed; never part of a recipe or request. */
|
|
44
|
+
export type LocalBuildExecutorOptions = Readonly<{
|
|
45
|
+
packageStoreDirectory?: string;
|
|
46
|
+
/**
|
|
47
|
+
* `run` executes a dependency's declared `fungi.build.script`. Only the
|
|
48
|
+
* admitted Computer build sets it; every other composition refuses a source
|
|
49
|
+
* that declares one, before installing anything.
|
|
50
|
+
*/
|
|
51
|
+
packageScripts?: "run";
|
|
52
|
+
/** Hears how long the dependency install and the compile each took. */
|
|
53
|
+
onPhase?: (phase: "install" | "build", milliseconds: number) => void;
|
|
54
|
+
}>;
|
|
43
55
|
/** Exact pinned esbuild options shared by local builds and artifact-budget proofs. */
|
|
44
56
|
export declare function localSnapshotBuildOptions(source: CapturedSource, recipe: PinnedRecipe, emission: DefinitionEmission): esbuild.BuildOptions;
|
|
45
57
|
/** Local proving adapter; it builds only the captured extracted snapshot. */
|
|
46
|
-
export declare function createLocalBuildExecutor(options?:
|
|
47
|
-
packageStoreDirectory?: string;
|
|
48
|
-
}>): BuildExecutor;
|
|
58
|
+
export declare function createLocalBuildExecutor(options?: LocalBuildExecutorOptions): BuildExecutor;
|
|
49
59
|
/** Local proving adapter; the configured root is private and write-once. */
|
|
50
60
|
export declare function createLocalArtifactWriter(artifactRoot: string, assetPolicy?: AssetBuildPolicy): ArtifactWriter;
|
|
51
61
|
/** Local Git, recipe and artifact directory configuration with a Release catalog. */
|