@fungi.computer/oyster 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +1082 -2
- package/dist/agents.d.ts +114 -0
- package/dist/agents.js +322 -0
- package/dist/app-builds.d.ts +151 -0
- package/dist/app-builds.js +355 -0
- package/dist/app-sandbox.d.ts +2 -0
- package/dist/app-sandbox.js +2 -0
- package/dist/app-sources.d.ts +46 -0
- package/dist/app-sources.js +335 -0
- package/dist/app-storage.d.ts +141 -0
- package/dist/app-storage.js +281 -0
- package/dist/apps/gate.d.ts +105 -0
- package/dist/apps/gate.js +273 -0
- package/dist/apps/index.d.ts +5 -0
- package/dist/apps/index.js +5 -0
- package/dist/apps/installation.d.ts +248 -0
- package/dist/apps/installation.js +307 -0
- package/dist/apps/operations.d.ts +8 -0
- package/dist/apps/operations.js +98 -0
- package/dist/apps/tools.d.ts +33 -0
- package/dist/apps/tools.js +17 -0
- package/dist/auth.d.ts +11 -0
- package/dist/auth.js +93 -0
- package/dist/backend-request.d.ts +3 -0
- package/dist/backend-request.js +53 -0
- package/dist/build/build-jobs.d.ts +128 -0
- package/dist/build/build-jobs.js +197 -0
- package/dist/build/build-step.d.ts +26 -0
- package/dist/build/build-step.js +20 -0
- package/dist/build/bundled-html.d.ts +7 -0
- package/dist/build/bundled-html.js +64 -0
- package/dist/build/definition-emission.d.ts +34 -0
- package/dist/build/definition-emission.js +201 -0
- package/dist/build/effect.d.ts +231 -0
- package/dist/build/effect.js +396 -0
- package/dist/build/git-environment.d.ts +6 -0
- package/dist/build/git-environment.js +48 -0
- package/dist/build/html-recipe.d.ts +20 -0
- package/dist/build/html-recipe.js +51 -0
- package/dist/build/local-build.d.ts +57 -0
- package/dist/build/local-build.js +1078 -0
- package/dist/build/r2-artifact-writer.d.ts +31 -0
- package/dist/build/r2-artifact-writer.js +179 -0
- package/dist/build/snapshot-package-store.d.ts +2 -0
- package/dist/build/snapshot-package-store.js +21 -0
- package/dist/build/snapshot-program-scripts.d.ts +6 -0
- package/dist/build/snapshot-program-scripts.js +2 -0
- package/dist/build/submission-contract.d.ts +384 -0
- package/dist/build/submission-contract.js +70 -0
- package/dist/build/workspace-build.d.ts +50 -0
- package/dist/build/workspace-build.js +156 -0
- package/dist/build-contract.d.ts +4 -0
- package/dist/build-contract.js +4 -0
- package/dist/build-jobs.d.ts +2 -0
- package/dist/build-jobs.js +2 -0
- package/dist/build.d.ts +11 -0
- package/dist/build.js +13 -0
- package/dist/capability-descriptor.d.ts +46 -0
- package/dist/capability-descriptor.js +51 -0
- package/dist/catalog-frame.d.ts +39 -0
- package/dist/catalog-frame.js +72 -0
- package/dist/cause-class.d.ts +19 -0
- package/dist/cause-class.js +54 -0
- package/dist/cloudflare.d.ts +123 -0
- package/dist/cloudflare.js +391 -0
- package/dist/computer-terminal.d.ts +38 -0
- package/dist/computer-terminal.js +410 -0
- package/dist/computer.d.ts +60 -0
- package/dist/computer.js +33 -0
- package/dist/event-recipients.d.ts +57 -0
- package/dist/event-recipients.js +144 -0
- package/dist/facet-invocation.d.ts +4 -0
- package/dist/facet-invocation.js +45 -0
- package/dist/files.d.ts +42 -0
- package/dist/files.js +123 -0
- package/dist/frame-binding-wire-script.d.ts +2 -0
- package/dist/frame-binding-wire-script.js +1 -0
- package/dist/frame-binding-wire.d.ts +28 -0
- package/dist/frame-binding-wire.js +54 -0
- package/dist/git-admission.d.ts +52 -0
- package/dist/git-admission.js +188 -0
- package/dist/git-auth.d.ts +11 -0
- package/dist/git-auth.js +27 -0
- package/dist/git-door.d.ts +35 -0
- package/dist/git-door.js +108 -0
- package/dist/git-journal.d.ts +31 -0
- package/dist/git-journal.js +188 -0
- package/dist/git.d.ts +31 -0
- package/dist/git.js +64 -0
- package/dist/guest-policy.d.ts +9 -0
- package/dist/guest-policy.js +13 -0
- package/dist/host.d.ts +244 -0
- package/dist/host.js +1043 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +320 -0
- package/dist/installation-consent.d.ts +79 -0
- package/dist/installation-consent.js +82 -0
- package/dist/internal/background-origins.d.ts +3 -0
- package/dist/internal/background-origins.js +8 -0
- package/dist/internal/delivery.d.ts +12 -0
- package/dist/internal/delivery.js +167 -0
- package/dist/internal/host-gate.d.ts +14 -0
- package/dist/internal/host-gate.js +62 -0
- package/dist/internal/registry-installations.d.ts +6 -0
- package/dist/internal/registry-installations.js +12 -0
- package/dist/invocation.d.ts +251 -0
- package/dist/invocation.js +377 -0
- package/dist/keys.d.ts +48 -0
- package/dist/keys.js +52 -0
- package/dist/mcp-owner.d.ts +27 -0
- package/dist/mcp-owner.js +143 -0
- package/dist/mcp.d.ts +89 -0
- package/dist/mcp.js +429 -0
- package/dist/media.d.ts +23 -0
- package/dist/media.js +12 -0
- package/dist/pack.d.ts +76 -0
- package/dist/pack.js +134 -0
- package/dist/page/capabilities.d.ts +23 -0
- package/dist/page/capabilities.js +256 -0
- package/dist/page/computer-handles.d.ts +79 -0
- package/dist/page/computer-handles.js +44 -0
- package/dist/page/lifetime.d.ts +6 -0
- package/dist/page/lifetime.js +19 -0
- package/dist/page/mount.d.ts +163 -0
- package/dist/page/mount.js +390 -0
- package/dist/page/storage.d.ts +3 -0
- package/dist/page/storage.js +82 -0
- package/dist/page/terminal.d.ts +5 -0
- package/dist/page/terminal.js +7 -0
- package/dist/page-script.d.ts +14 -0
- package/dist/page-script.js +5 -0
- package/dist/r2-files.d.ts +3 -0
- package/dist/r2-files.js +79 -0
- package/dist/release.d.ts +72 -0
- package/dist/release.js +164 -0
- package/dist/root-data.d.ts +86 -0
- package/dist/root-data.js +69 -0
- package/dist/shell/app-directory.d.ts +537 -0
- package/dist/shell/app-directory.js +195 -0
- package/dist/shell/browser-actions.d.ts +7 -0
- package/dist/shell/browser-actions.js +56 -0
- package/dist/shell/command-host.d.ts +112 -0
- package/dist/shell/command-host.js +502 -0
- package/dist/shell/commands.d.ts +25 -0
- package/dist/shell/commands.js +78 -0
- package/dist/shell/index.d.ts +8 -0
- package/dist/shell/index.js +8 -0
- package/dist/shell/keys.d.ts +41 -0
- package/dist/shell/keys.js +134 -0
- package/dist/shell/shell-module.d.ts +31 -0
- package/dist/shell/shell-module.js +37 -0
- package/dist/shell/window-manager.d.ts +124 -0
- package/dist/shell/window-manager.js +711 -0
- package/dist/shell/workbench-contract.d.ts +68 -0
- package/dist/shell/workbench-contract.js +1 -0
- package/dist/shell/workbench-host-types.d.ts +96 -0
- package/dist/shell/workbench-host-types.js +1 -0
- package/dist/shell/workbench-host.d.ts +34 -0
- package/dist/shell/workbench-host.js +347 -0
- package/dist/shell/workbench-model.d.ts +192 -0
- package/dist/shell/workbench-model.js +53 -0
- package/dist/shell/workbench.d.ts +4 -0
- package/dist/shell/workbench.js +2 -0
- package/dist/source/fork.d.ts +27 -0
- package/dist/source/fork.js +46 -0
- package/dist/source/index.d.ts +11 -0
- package/dist/source/index.js +11 -0
- package/dist/source/seed-receipt.d.ts +53 -0
- package/dist/source/seed-receipt.js +18 -0
- package/dist/source/team-source.d.ts +32 -0
- package/dist/source/team-source.js +42 -0
- package/dist/source/template-repository.d.ts +2 -0
- package/dist/source/template-repository.js +8 -0
- package/dist/source/template-write.d.ts +69 -0
- package/dist/source/template-write.js +344 -0
- package/dist/storage-frame.d.ts +64 -0
- package/dist/storage-frame.js +28 -0
- package/dist/tenant.d.ts +81 -0
- package/dist/tenant.js +71 -0
- package/dist/testing/capabilities.d.ts +29 -0
- package/dist/testing/capabilities.js +130 -0
- package/dist/testing/catalog.d.ts +3 -0
- package/dist/testing/catalog.js +53 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.js +10 -0
- package/dist/testing/installation.d.ts +11 -0
- package/dist/testing/installation.js +25 -0
- package/dist/testing/native-worker.d.ts +21 -0
- package/dist/testing/native-worker.js +106 -0
- package/dist/testing/worker.d.ts +18 -0
- package/dist/testing/worker.js +67 -0
- package/dist/testing/workers-runtime.d.ts +24 -0
- package/dist/testing/workers-runtime.js +33 -0
- package/dist/webhook-delivery.d.ts +14 -0
- package/dist/webhook-delivery.js +17 -0
- package/dist/workers-git.d.ts +285 -0
- package/dist/workers-git.js +1174 -0
- package/dist/workers.d.ts +352 -0
- package/dist/workers.js +866 -0
- package/docs/api/README.md +82 -0
- package/docs/api/agents.md +332 -0
- package/docs/api/app-storage.md +209 -0
- package/docs/api/apps.md +1375 -0
- package/docs/api/auth.md +63 -0
- package/docs/api/build-contract.md +507 -0
- package/docs/api/build.md +1476 -0
- package/docs/api/cloudflare.md +421 -0
- package/docs/api/computer.md +203 -0
- package/docs/api/files.md +117 -0
- package/docs/api/git.md +470 -0
- package/docs/api/host.md +1328 -0
- package/docs/api/index.md +430 -0
- package/docs/api/invocation.md +738 -0
- package/docs/api/keys.md +175 -0
- package/docs/api/mcp.md +301 -0
- package/docs/api/media.md +40 -0
- package/docs/api/modules.md +42 -0
- package/docs/api/pack.md +138 -0
- package/docs/api/page/mount.md +298 -0
- package/docs/api/root-data.md +111 -0
- package/docs/api/shell/app-directory.md +332 -0
- package/docs/api/shell/command-host.md +224 -0
- package/docs/api/shell/commands.md +197 -0
- package/docs/api/shell/keys.md +183 -0
- package/docs/api/shell/shell-module.md +143 -0
- package/docs/api/shell/window-manager.md +267 -0
- package/docs/api/shell/workbench.md +186 -0
- package/docs/api/shell.md +1788 -0
- package/docs/api/tenant.md +194 -0
- package/docs/api/workers-git.md +1527 -0
- package/docs/api/workers.md +1678 -0
- package/docs/media/architecture.mmd +32 -0
- package/docs/media/architecture.png +0 -0
- package/docs/media/bonsai-network.png +0 -0
- package/docs/media/bonsai-repository.png +0 -0
- package/docs/site/agent-quickstart.mdx +349 -0
- package/examples/git/worker.ts +39 -0
- package/examples/git/wrangler.jsonc +32 -0
- package/examples/standalone/worker.ts +14 -0
- package/examples/standalone/wrangler.jsonc +21 -0
- package/package.json +249 -3
package/dist/git.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git and events for Apps: the GIT and EVENTS bindings a host grants an App
|
|
3
|
+
* backend, the git door that lets people and agents push to an App's
|
|
4
|
+
* repositories with ordinary git, and Standard Webhooks signing for events the
|
|
5
|
+
* host delivers. Credentials, remotes and webhook secrets stay in the host;
|
|
6
|
+
* the App sees repository names, git objects and its own events.
|
|
7
|
+
*/
|
|
8
|
+
import { readPacketLines, pktLine } from "@fungi.computer/agar/git-wire";
|
|
9
|
+
import * as Schema from "effect/Schema";
|
|
10
|
+
const decoder = new TextDecoder();
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
/** The protocol-v2 ls-refs request body. */
|
|
13
|
+
export function lsRefsRequest() {
|
|
14
|
+
return encoder.encode(`${pktLine("command=ls-refs\n")}0001${pktLine("ref-prefix refs/\n")}0000`);
|
|
15
|
+
}
|
|
16
|
+
/** Parse an ls-refs response into refs. */
|
|
17
|
+
export function parseLsRefs(response) {
|
|
18
|
+
const refs = [];
|
|
19
|
+
for (const raw of readPacketLines(response, true)) {
|
|
20
|
+
const [hash = "", name = ""] = decoder
|
|
21
|
+
.decode(raw)
|
|
22
|
+
.replace(/\n$/u, "")
|
|
23
|
+
.split(" ");
|
|
24
|
+
if (/^[0-9a-f]{40}$/u.test(hash) && name.startsWith("refs/"))
|
|
25
|
+
refs.push({ name, hash });
|
|
26
|
+
}
|
|
27
|
+
return refs;
|
|
28
|
+
}
|
|
29
|
+
async function hmac(key, message) {
|
|
30
|
+
const imported = await crypto.subtle.importKey("raw", new Uint8Array(key), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
31
|
+
return new Uint8Array(await crypto.subtle.sign("HMAC", imported, encoder.encode(message)));
|
|
32
|
+
}
|
|
33
|
+
/** A `whsec_` secret is base64 key bytes; any other secret is its own UTF-8. */
|
|
34
|
+
function secretBytes(secret) {
|
|
35
|
+
if (!secret.startsWith("whsec_"))
|
|
36
|
+
return encoder.encode(secret);
|
|
37
|
+
return Uint8Array.from(atob(secret.slice(6)), (char) => char.charCodeAt(0));
|
|
38
|
+
}
|
|
39
|
+
function hex(bytes) {
|
|
40
|
+
return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
41
|
+
}
|
|
42
|
+
/** The Standard Webhooks `webhook-signature` value for one delivery. */
|
|
43
|
+
export async function signStandardWebhook(secret, id, timestamp, body) {
|
|
44
|
+
const signature = await hmac(secretBytes(secret), `${id}.${String(timestamp)}.${body}`);
|
|
45
|
+
return `v1,${btoa(String.fromCharCode(...signature))}`;
|
|
46
|
+
}
|
|
47
|
+
/** Headers for one signed delivery: Standard Webhooks plus `X-Hub-Signature-256`. */
|
|
48
|
+
export async function webhookHeaders(secret, id, type, timestamp, body) {
|
|
49
|
+
return {
|
|
50
|
+
"content-type": "application/json",
|
|
51
|
+
"user-agent": "Oyster-Webhooks/1",
|
|
52
|
+
"webhook-id": id,
|
|
53
|
+
"webhook-timestamp": String(timestamp),
|
|
54
|
+
"webhook-signature": await signStandardWebhook(secret, id, timestamp, body),
|
|
55
|
+
// The headers receivers built for git hosts check.
|
|
56
|
+
"x-hub-signature-256": `sha256=${hex(await hmac(encoder.encode(secret), body))}`,
|
|
57
|
+
"x-github-delivery": id,
|
|
58
|
+
"x-github-event": type,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export { createGitDoor, gitDoorRoute, smartHttpExchange } from "./git-door.js";
|
|
62
|
+
export { workflowGitPassPrefix } from "./git-auth.js";
|
|
63
|
+
export { createAdmittedGit, createInstallationGitAdmission, } from "./git-admission.js";
|
|
64
|
+
export { createGitPushJournal } from "./git-journal.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Per-invocation budgets enforced by the guest Worker Loader, including facets. */
|
|
2
|
+
export type GuestLimits = Readonly<{
|
|
3
|
+
/** Maximum guest CPU time in milliseconds. Defaults to 1,000. */
|
|
4
|
+
cpuMs: number;
|
|
5
|
+
/** Maximum guest subrequests. Defaults to 50; zero forbids subrequests. */
|
|
6
|
+
subRequests: number;
|
|
7
|
+
}>;
|
|
8
|
+
/** Validate host configuration and fill each omitted budget with its safe default. */
|
|
9
|
+
export declare function guestLimits(input?: Partial<GuestLimits>): GuestLimits;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
const boundedInteger = Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isLessThanOrEqualTo(2147483647)));
|
|
3
|
+
const limitsSchema = Schema.Struct({
|
|
4
|
+
cpuMs: boundedInteger.pipe(Schema.check(Schema.isGreaterThan(0))),
|
|
5
|
+
subRequests: boundedInteger.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0))),
|
|
6
|
+
});
|
|
7
|
+
/** Validate host configuration and fill each omitted budget with its safe default. */
|
|
8
|
+
export function guestLimits(input = {}) {
|
|
9
|
+
return Object.freeze(Schema.decodeUnknownSync(limitsSchema)({
|
|
10
|
+
cpuMs: input.cpuMs ?? 1000,
|
|
11
|
+
subRequests: input.subRequests ?? 50,
|
|
12
|
+
}));
|
|
13
|
+
}
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type { KnapsackComputer } from "@fungi.computer/knapsack";
|
|
2
|
+
import type { TenantPrincipal } from "./tenant.js";
|
|
3
|
+
import { type GillCall, type GillReply } from "@fungi.computer/gills";
|
|
4
|
+
import { type AppStorageWire } from "@fungi.computer/agar/storage";
|
|
5
|
+
import type { OysterRootDirectory } from "./root-data.js";
|
|
6
|
+
import { type AppGitPushFact, type GitPushQuestion, type GitPushVerdict, type GitWriter } from "@fungi.computer/agar/git";
|
|
7
|
+
import { type GuestLimits } from "./guest-policy.js";
|
|
8
|
+
import { type InvocationFacts } from "./invocation.js";
|
|
9
|
+
export type { GuestLimits } from "./guest-policy.js";
|
|
10
|
+
import { Hono } from "hono";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
import { type BackgroundSyncRefusal } from "@fungi.computer/puffball/background-replay";
|
|
13
|
+
import { type Installation, type InstallationReader } from "./apps/installation.js";
|
|
14
|
+
import type { AppToolPolicy } from "./apps/tools.js";
|
|
15
|
+
import type { LiveOysterKey } from "./keys.js";
|
|
16
|
+
import { type AppMethodReply } from "@fungi.computer/agar/backend";
|
|
17
|
+
import type { AppCapabilityId, HostActor } from "@fungi.computer/puffball/app";
|
|
18
|
+
import { type CapabilityDescriptor } from "./capability-descriptor.js";
|
|
19
|
+
export { capabilityDescriptorSchema, capabilityMethodKindSchema, capabilityMethodSchema, type CapabilityDescriptor, type CapabilityMethodKind, } from "./capability-descriptor.js";
|
|
20
|
+
import type { Release } from "@fungi.computer/puffball";
|
|
21
|
+
import { type Instance, type InstanceId, type OwnerState, type AppInstanceErrorCode } from "./index.js";
|
|
22
|
+
import { type ArtifactStore } from "./release.js";
|
|
23
|
+
import { type GitDoorTarget } from "./git.js";
|
|
24
|
+
import type { AdmittedGit } from "./git-admission.js";
|
|
25
|
+
import { type AppApi } from "@fungi.computer/puffball";
|
|
26
|
+
export { ReleaseError, defaultAssetPolicy, parseRelease, resolveBackend, sha256, verifyRelease, type ArtifactStore, type VerifiedRelease, } from "./release.js";
|
|
27
|
+
/**
|
|
28
|
+
* The anonymous reader of a public installation. The host admits it only when
|
|
29
|
+
* authentication refuses; it reaches that App's page and its `read` methods.
|
|
30
|
+
*/
|
|
31
|
+
export type OysterVisitor = Readonly<{
|
|
32
|
+
actor: Readonly<{
|
|
33
|
+
kind: "visitor";
|
|
34
|
+
}>;
|
|
35
|
+
}>;
|
|
36
|
+
/** Who an admitted request acts for: an authenticated tenant principal or the visitor. */
|
|
37
|
+
export type OysterPrincipal = TenantPrincipal | OysterVisitor;
|
|
38
|
+
/** Narrow an admitted principal to the anonymous public reader. */
|
|
39
|
+
export declare function oysterPrincipalIsVisitor(principal: OysterPrincipal): principal is OysterVisitor;
|
|
40
|
+
/** True only for a member admitted with the owner role. */
|
|
41
|
+
export declare function oysterPrincipalIsOwner(principal: OysterPrincipal): principal is Readonly<{
|
|
42
|
+
actor: Extract<HostActor, {
|
|
43
|
+
kind: "member";
|
|
44
|
+
}>;
|
|
45
|
+
role: "owner";
|
|
46
|
+
}>;
|
|
47
|
+
/** Stable actor identity for host storage and backend attribution. */
|
|
48
|
+
export declare function oysterPrincipalId(principal: TenantPrincipal): string;
|
|
49
|
+
/** The outcome of authenticating one request. */
|
|
50
|
+
export type OysterAuthResult = Readonly<{
|
|
51
|
+
kind: "admitted";
|
|
52
|
+
principal: TenantPrincipal;
|
|
53
|
+
}> | Readonly<{
|
|
54
|
+
kind: "refused";
|
|
55
|
+
status: 401 | 403 | 404 | 429;
|
|
56
|
+
retryAfter?: number;
|
|
57
|
+
}>;
|
|
58
|
+
/** The host's sign-in: who may use this Oyster. */
|
|
59
|
+
export type OysterAuth = Readonly<{
|
|
60
|
+
/** Resolve a retained actor through current host membership, without replaying credentials. */
|
|
61
|
+
resolve: (actor: HostActor) => Promise<TenantPrincipal | null>;
|
|
62
|
+
/** Authenticate one request from its headers or cookies. */
|
|
63
|
+
authenticate: (request: Request) => Promise<OysterAuthResult>;
|
|
64
|
+
/** Handle the browser sign-in form post; returns the response to send. */
|
|
65
|
+
login?: (request: Request) => Promise<Response>;
|
|
66
|
+
}>;
|
|
67
|
+
/** A serializable registry commit result, including across native DO RPC. */
|
|
68
|
+
export type InstallationCommit = Readonly<{
|
|
69
|
+
ok: true;
|
|
70
|
+
}> | Readonly<{
|
|
71
|
+
ok: false;
|
|
72
|
+
code: "stale_authority";
|
|
73
|
+
}>;
|
|
74
|
+
/** Durable commits remain with the host's registry; reads are tenant-scoped. */
|
|
75
|
+
export type InstallationStore = InstallationReader & Readonly<{
|
|
76
|
+
/** Commit one reducer-produced installation record. */
|
|
77
|
+
put: (installation: Installation) => Promise<void>;
|
|
78
|
+
/** Atomically commit only the authority version the owner reviewed. */
|
|
79
|
+
compareAndPut: (installation: Installation, expectedAuthorityVersion: number) => Promise<InstallationCommit>;
|
|
80
|
+
}>;
|
|
81
|
+
/** A JSON value crossing the method boundary. */
|
|
82
|
+
export type OysterJson = Schema.Json;
|
|
83
|
+
/** The result of one Instance operation; refusals carry Oyster's error code. */
|
|
84
|
+
export type InstanceResult<T> = Readonly<{
|
|
85
|
+
ok: true;
|
|
86
|
+
value: T;
|
|
87
|
+
}> | Readonly<{
|
|
88
|
+
ok: false;
|
|
89
|
+
code: AppInstanceErrorCode | "failed";
|
|
90
|
+
/** Closed host diagnostic; absent when the execution owner did not supply one. */
|
|
91
|
+
causeClass?: "Error" | "TypeError" | "RangeError" | "SyntaxError" | "AbortError" | "TimeoutError" | "Other";
|
|
92
|
+
}>;
|
|
93
|
+
/** One running App Instance, wherever the host runs it. */
|
|
94
|
+
export type InstanceHandle = Readonly<{
|
|
95
|
+
/** Apply a complete owner state for `release`. */
|
|
96
|
+
apply: (state: OwnerState, release: Release) => Promise<InstanceResult<Instance>>;
|
|
97
|
+
/** Deliver an admitted Git push under this exact Instance selection. */
|
|
98
|
+
onGitPush: (facts: InvocationFacts, fact: AppGitPushFact) => Promise<void>;
|
|
99
|
+
/** Deliver a lane refusal only through an active zero-grant lifecycle frame. */
|
|
100
|
+
syncRefused: (facts: InvocationFacts, refusal: BackgroundSyncRefusal) => Promise<void>;
|
|
101
|
+
/** Ask a whole-push policy under host-admitted immutable caller facts. */
|
|
102
|
+
authorizeGitPush: (facts: InvocationFacts, question: GitPushQuestion) => Promise<GitPushVerdict>;
|
|
103
|
+
/** Forward an admitted HTTP request to the backend. */
|
|
104
|
+
fetch: (facts: InvocationFacts, request: Request) => Promise<Response>;
|
|
105
|
+
/** Invoke a declared read Gill through the same immutable invocation frame. */
|
|
106
|
+
gill: (facts: InvocationFacts, api: AppApi, source: string, input: GillCall) => Promise<InstanceResult<GillReply>>;
|
|
107
|
+
/** Invoke one declared App method; an App refusal is a refused reply. */
|
|
108
|
+
call: (facts: InvocationFacts, api: AppApi, name: string, input: OysterJson) => Promise<InstanceResult<AppMethodReply>>;
|
|
109
|
+
}>;
|
|
110
|
+
/** Finds the running Instance for an Instance ID. */
|
|
111
|
+
export type InstanceDirectory = Readonly<{
|
|
112
|
+
/** The Instance with this ID. The adapter must enforce the supplied guest budgets. */
|
|
113
|
+
get: (instanceId: InstanceId, limits?: GuestLimits) => InstanceHandle;
|
|
114
|
+
}>;
|
|
115
|
+
/** An MCP endpoint mounted at `/mcp`. */
|
|
116
|
+
export type OysterMcp = Readonly<{
|
|
117
|
+
/** Answer one MCP HTTP request. */
|
|
118
|
+
handleRequest: (request: Request) => Promise<Response>;
|
|
119
|
+
/** Close an explicitly supplied process-local adapter; remote owners expose no close. */
|
|
120
|
+
close?: () => Promise<void>;
|
|
121
|
+
}>;
|
|
122
|
+
/** What Oyster's git door needs from the host beyond sign-in and Instances. */
|
|
123
|
+
export type OysterGitHost = Readonly<{
|
|
124
|
+
/** Project the authenticated host principal into the canonical writer grammar. */
|
|
125
|
+
writerOf(principal: TenantPrincipal): Extract<GitWriter, {
|
|
126
|
+
kind: "actor";
|
|
127
|
+
}>;
|
|
128
|
+
/** Admit a host-minted Workflow Git pass for exactly one repository and
|
|
129
|
+
* scope, as its arming member under the Workflow's branch grant. */
|
|
130
|
+
workflowPass?(pass: string, target: GitDoorTarget): Promise<Extract<GitWriter, {
|
|
131
|
+
kind: "actor";
|
|
132
|
+
}> | null>;
|
|
133
|
+
/** Admit a host-minted build job clone pass: one repository, read only, as
|
|
134
|
+
* the owner who started the build. */
|
|
135
|
+
buildPass?(pass: string, target: GitDoorTarget): Promise<Extract<GitWriter, {
|
|
136
|
+
kind: "actor";
|
|
137
|
+
}> | null>;
|
|
138
|
+
/** Construct the installation-scoped admitted store, policy and durable journal. */
|
|
139
|
+
git(installation: Installation): Promise<AdmittedGit>;
|
|
140
|
+
}>;
|
|
141
|
+
/** The host's admission of one capability request: who, for which installation. */
|
|
142
|
+
export type CapabilityAdmission = Readonly<{
|
|
143
|
+
/** The principal the host authenticated for this request. */
|
|
144
|
+
principal: TenantPrincipal;
|
|
145
|
+
/** The enabled installation the gate admitted for this capability. */
|
|
146
|
+
installation: Installation;
|
|
147
|
+
}>;
|
|
148
|
+
/** Capability routes read the host's admission from `c.env`; they never authenticate. */
|
|
149
|
+
export type CapabilityEnv = {
|
|
150
|
+
Bindings: CapabilityAdmission;
|
|
151
|
+
};
|
|
152
|
+
/** A capability adapter whose routes require live installation admission. */
|
|
153
|
+
export type OysterCapability = Readonly<CapabilityDescriptor & {
|
|
154
|
+
/** The permission declared by an App Release to use this contract. */
|
|
155
|
+
permission: AppCapabilityId;
|
|
156
|
+
/** Routes relative to the descriptor's base path. */
|
|
157
|
+
routes: Hono<CapabilityEnv>;
|
|
158
|
+
}>;
|
|
159
|
+
/** What the host stamps once per request; inner routes read it with `c.get`. */
|
|
160
|
+
export type OysterVariables = {
|
|
161
|
+
principal: OysterPrincipal;
|
|
162
|
+
installation?: Installation;
|
|
163
|
+
};
|
|
164
|
+
/** Owner routes run after the host's owner guard and read `c.get("principal")`. */
|
|
165
|
+
export type OysterEnv = {
|
|
166
|
+
Variables: OysterVariables;
|
|
167
|
+
};
|
|
168
|
+
/** Everything a host supplies to run Oyster. */
|
|
169
|
+
export type OysterHost = Readonly<{
|
|
170
|
+
auth: OysterAuth;
|
|
171
|
+
/** Host-held sealing key for member writes; never exposed to the guest.
|
|
172
|
+
* Absence refuses eligible named member writes, even when the App has no sync continuation.
|
|
173
|
+
*/
|
|
174
|
+
backgroundOriginKey?: () => Promise<CryptoKey>;
|
|
175
|
+
artifacts: ArtifactStore;
|
|
176
|
+
installations: InstallationStore;
|
|
177
|
+
instances: InstanceDirectory;
|
|
178
|
+
/** Fixed Computer selected by the host; request input never selects it. */
|
|
179
|
+
computerId?: string;
|
|
180
|
+
/** The fixed Computer's advertised calls for one admitted caller, or null
|
|
181
|
+
* when the caller holds no Computer access (for a key, without its own
|
|
182
|
+
* `computer.use` grant). The Computer owner accepts each call against the
|
|
183
|
+
* authority the host issued.
|
|
184
|
+
*/
|
|
185
|
+
computer?: (principal: OysterPrincipal) => KnapsackComputer | null | Promise<KnapsackComputer | null>;
|
|
186
|
+
/** Host-attested Agent tool policy; absence grants no App tool access. A
|
|
187
|
+
* key's App access is its own grants (Ear Tag), read through `keys.live`
|
|
188
|
+
* and `keyAppAccess`, never this port. */
|
|
189
|
+
appToolPolicy?: (actor: Extract<HostActor, {
|
|
190
|
+
kind: "agent";
|
|
191
|
+
}>) => AppToolPolicy | null | Promise<AppToolPolicy | null>;
|
|
192
|
+
/** The Ear Tag-backed key store this host owns. */
|
|
193
|
+
keys?: Readonly<{
|
|
194
|
+
/** One key's live facts by id; `null` for an unknown, revoked, expired or suspended key. */
|
|
195
|
+
live(keyId: string): Promise<LiveOysterKey | null>;
|
|
196
|
+
}>;
|
|
197
|
+
/** Guest CPU/subrequest budgets; defaults to 1,000 ms and 50 per invocation. */
|
|
198
|
+
guestLimits?: Partial<GuestLimits>;
|
|
199
|
+
/** Shared Mycelium MCP handler; it authenticates every request itself. */
|
|
200
|
+
mcp?: OysterMcp;
|
|
201
|
+
/** The git door for Apps that use GIT; mounted at `/git/*`. */
|
|
202
|
+
git?: OysterGitHost;
|
|
203
|
+
/** Owner-only `/api/*` routes the host adds (keys, webhooks); they read the
|
|
204
|
+
* admitted owner with `c.get("principal")` and never authenticate again. */
|
|
205
|
+
ownerRoutes?: Hono<OysterEnv>;
|
|
206
|
+
/** Adapters granted only when the Release declares them and admission passes. */
|
|
207
|
+
capabilities?: readonly OysterCapability[];
|
|
208
|
+
/**
|
|
209
|
+
* Root-owned desktop data and per-App storage; HTTP access remains
|
|
210
|
+
* owner-only. With it, the home installation's page is the trusted shell:
|
|
211
|
+
* `pageScript` must render that shell in the top-level `#oyster-shell`
|
|
212
|
+
* document, where it runs with this host's escalated permissions.
|
|
213
|
+
*/
|
|
214
|
+
workbench?: Readonly<{
|
|
215
|
+
/** Read the owner's live installation directory. */
|
|
216
|
+
directory(): Promise<OysterRootDirectory>;
|
|
217
|
+
/** Open storage after fresh installation and owner admission. */
|
|
218
|
+
storage(installationId: string, ownerId: string): Pick<AppStorageWire, "read" | "write" | "reset"> & Readonly<{
|
|
219
|
+
/** Stream changes for an admitted declared storage key. */
|
|
220
|
+
events(key: string): Promise<Response>;
|
|
221
|
+
}>;
|
|
222
|
+
}>;
|
|
223
|
+
/** Root-selected home installation; the core never imports a specific home App. */
|
|
224
|
+
homeInstallationId?: string;
|
|
225
|
+
/** Browser composition supplied by a deployable host; defaults to Oyster shell. */
|
|
226
|
+
pageScript?: string;
|
|
227
|
+
/** Page title shown in the shell. */
|
|
228
|
+
title?: string;
|
|
229
|
+
}>;
|
|
230
|
+
/**
|
|
231
|
+
* Install a Release at `installationId`, or switch an already-live one onto
|
|
232
|
+
* it: the one path the POST install and PUT release-select routes share,
|
|
233
|
+
* and that a build owner's own install call reaches too. Nothing there (or
|
|
234
|
+
* only a deleted installation) is a fresh install; a live installation is
|
|
235
|
+
* switched in place, refusing a change of the installation's App identity.
|
|
236
|
+
*/
|
|
237
|
+
export declare function installOrSelect(host: OysterHost, installationId: string, release: Release, principal: OysterPrincipal): Promise<Response>;
|
|
238
|
+
/**
|
|
239
|
+
* Create the Oyster App server: a Hono app that installs App Releases, serves
|
|
240
|
+
* their UI, forwards their backend requests and methods to their Instances,
|
|
241
|
+
* and mounts the host's MCP endpoint. The host's adapters decide where state
|
|
242
|
+
* lives and who may sign in.
|
|
243
|
+
*/
|
|
244
|
+
export declare function createOyster(host: OysterHost): Hono<OysterEnv>;
|