@fungi.computer/oyster 0.1.0 → 0.3.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 +376 -72
- package/dist/agent-avatars.d.ts +103 -0
- package/dist/agent-avatars.js +66 -0
- package/dist/agents.d.ts +15 -4
- package/dist/agents.js +43 -4
- package/dist/app-builds.d.ts +81 -8
- package/dist/app-builds.js +210 -60
- package/dist/app-storage.d.ts +3 -3
- package/dist/approval-capability.d.ts +5 -0
- package/dist/approval-capability.js +46 -0
- package/dist/approval-home.d.ts +51 -0
- package/dist/approval-home.js +226 -0
- package/dist/apps/catalog.d.ts +335 -0
- package/dist/apps/catalog.js +46 -0
- package/dist/apps/gate.d.ts +26 -12
- package/dist/apps/gate.js +48 -22
- package/dist/apps/index.d.ts +3 -1
- package/dist/apps/index.js +3 -1
- package/dist/apps/installation.d.ts +147 -66
- package/dist/apps/installation.js +193 -86
- package/dist/apps/permissions.d.ts +247 -0
- package/dist/apps/permissions.js +255 -0
- package/dist/boot-capability-route.d.ts +15 -0
- package/dist/boot-capability-route.js +196 -0
- package/dist/boot-capability.d.ts +103 -0
- package/dist/boot-capability.js +141 -0
- package/dist/boot-construction.d.ts +12 -0
- package/dist/boot-construction.js +175 -0
- package/dist/boot-gate.d.ts +267 -0
- package/dist/boot-gate.js +236 -0
- package/dist/boot-host-script.d.ts +2 -0
- package/dist/boot-host-script.js +1 -0
- package/dist/boot-mount.d.ts +21 -0
- package/dist/boot-mount.js +65 -0
- package/dist/browser/boot.d.ts +73 -0
- package/dist/browser/boot.js +502 -0
- package/dist/browser/browser.d.ts +104 -0
- package/dist/browser/browser.js +374 -0
- package/dist/browser/capability-source.d.ts +76 -0
- package/dist/browser/capability-source.js +338 -0
- package/dist/browser/cdp-client.d.ts +56 -0
- package/dist/browser/cdp-client.js +184 -0
- package/dist/browser/errors.d.ts +79 -0
- package/dist/browser/errors.js +32 -0
- package/dist/browser/index.d.ts +16 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/lease-registry.d.ts +61 -0
- package/dist/browser/lease-registry.js +101 -0
- package/dist/browser/operations.d.ts +225 -0
- package/dist/browser/operations.js +137 -0
- package/dist/browser/page.d.ts +25 -0
- package/dist/browser/page.js +172 -0
- package/dist/browser/quick-reads.d.ts +29 -0
- package/dist/browser/quick-reads.js +160 -0
- package/dist/browser/sessions.d.ts +52 -0
- package/dist/browser/sessions.js +118 -0
- package/dist/browser/url-policy.d.ts +18 -0
- package/dist/browser/url-policy.js +58 -0
- package/dist/build/app-imports.d.ts +12 -0
- package/dist/build/app-imports.js +105 -0
- package/dist/build/build-policy.d.ts +5 -3
- package/dist/build/build-policy.js +5 -3
- package/dist/build/candidate-builder.d.ts +1 -1
- package/dist/build/candidate-cli.mjs +8428 -337
- package/dist/build/local-build.d.ts +2 -0
- package/dist/build/local-build.js +28 -6
- package/dist/build/snapshot-package-store.d.ts +1 -1
- package/dist/build/snapshot-package-store.js +7 -2
- package/dist/build/workspace-build.d.ts +92 -5
- package/dist/build/workspace-build.js +93 -19
- package/dist/build-egress.js +4 -4
- package/dist/build.d.ts +1 -1
- package/dist/build.js +1 -1
- package/dist/catalog-frame.js +1 -1
- package/dist/cloudflare.d.ts +13 -3
- package/dist/cloudflare.js +106 -8
- package/dist/frame-binding-wire-script.js +1 -1
- package/dist/frame-binding-wire.d.ts +1 -1
- package/dist/frame-binding-wire.js +5 -3
- package/dist/git-auth.d.ts +0 -2
- package/dist/git-auth.js +0 -2
- package/dist/git-journal.js +4 -4
- package/dist/git.d.ts +0 -1
- package/dist/git.js +0 -2
- package/dist/host.d.ts +39 -13
- package/dist/host.js +268 -142
- package/dist/index.d.ts +26 -15
- package/dist/index.js +40 -16
- package/dist/install-release-cli.d.ts +2 -0
- package/dist/install-release-cli.js +46 -0
- package/dist/installation-client.d.ts +43 -0
- package/dist/installation-client.js +178 -0
- package/dist/installation-execution.d.ts +11 -0
- package/dist/installation-execution.js +184 -0
- package/dist/installation-operations.d.ts +1437 -0
- package/dist/installation-operations.js +664 -0
- package/dist/installation-store-generation.d.ts +3 -0
- package/dist/installation-store-generation.js +16 -0
- package/dist/instance-id.d.ts +10 -0
- package/dist/instance-id.js +10 -0
- package/dist/instance-refusal.d.ts +11 -0
- package/dist/instance-refusal.js +21 -0
- package/dist/internal/delivery.js +4 -2
- package/dist/internal/host-gate.js +7 -1
- package/dist/internal/registry-installations.js +4 -4
- package/dist/keys.d.ts +5 -1
- package/dist/keys.js +10 -2
- package/dist/machine-link/authority.d.ts +89 -0
- package/dist/machine-link/authority.js +37 -0
- package/dist/machine-link/client.d.ts +66 -0
- package/dist/machine-link/client.js +94 -0
- package/dist/machine-link/delivery.d.ts +18 -0
- package/dist/machine-link/delivery.js +55 -0
- package/dist/machine-link/enrollment.d.ts +111 -0
- package/dist/machine-link/enrollment.js +286 -0
- package/dist/machine-link/fences.d.ts +37 -0
- package/dist/machine-link/fences.js +166 -0
- package/dist/machine-link/home.d.ts +20 -0
- package/dist/machine-link/home.js +24 -0
- package/dist/machine-link/host.d.ts +43 -0
- package/dist/machine-link/host.js +189 -0
- package/dist/machine-link/index.d.ts +15 -0
- package/dist/machine-link/index.js +15 -0
- package/dist/machine-link/link.d.ts +48 -0
- package/dist/machine-link/link.js +223 -0
- package/dist/machine-link/presence.d.ts +10 -0
- package/dist/machine-link/presence.js +25 -0
- package/dist/machine-link/workers.d.ts +6 -0
- package/dist/machine-link/workers.js +6 -0
- package/dist/mcp-owner.d.ts +2 -2
- package/dist/mcp-owner.js +41 -33
- package/dist/mcp.d.ts +15 -3
- package/dist/mcp.js +146 -25
- package/dist/pack.d.ts +14 -3
- package/dist/pack.js +44 -19
- package/dist/page/app-access.d.ts +7 -0
- package/dist/page/app-access.js +75 -0
- package/dist/page/boot-host.js +57 -0
- package/dist/page/capabilities.d.ts +3 -3
- package/dist/page/capabilities.js +16 -12
- package/dist/page/computer-handles.d.ts +3 -3
- package/dist/page/computer-target.d.ts +3 -0
- package/dist/page/computer-target.js +9 -0
- package/dist/page/mount.d.ts +23 -7
- package/dist/page/mount.js +152 -16
- package/dist/page-assets.d.ts +22 -0
- package/dist/page-assets.js +28 -0
- package/dist/page-script.d.ts +3 -0
- package/dist/page-script.js +5 -4
- package/dist/release.d.ts +13 -6
- package/dist/release.js +10 -7
- package/dist/root-data.d.ts +16 -6
- package/dist/root-data.js +2 -2
- package/dist/source/index.d.ts +1 -1
- package/dist/source/team-source.d.ts +20 -8
- package/dist/source/team-source.js +39 -10
- package/dist/source/template-seed.d.ts +2 -2
- package/dist/standalone/agent-mail.d.ts +24 -0
- package/dist/standalone/agent-mail.js +62 -0
- package/dist/standalone/agent-store.d.ts +9 -0
- package/dist/standalone/agent-store.js +30 -0
- package/dist/standalone/agents.d.ts +78 -12
- package/dist/standalone/agents.js +470 -59
- package/dist/standalone/app-builds-binding.d.ts +20 -2
- package/dist/standalone/app-builds-binding.js +151 -27
- package/dist/standalone/app-set.d.ts +5 -2
- package/dist/standalone/app-set.js +174 -143
- package/dist/standalone/browser.d.ts +11 -0
- package/dist/standalone/browser.js +72 -0
- package/dist/standalone/builds.d.ts +13 -4
- package/dist/standalone/builds.js +28 -44
- package/dist/standalone/computer-egress.d.ts +2 -0
- package/dist/standalone/computer-egress.js +13 -4
- package/dist/standalone/computer-fleet.d.ts +43 -0
- package/dist/standalone/computer-fleet.js +200 -0
- package/dist/standalone/computer.d.ts +44 -9
- package/dist/standalone/computer.js +132 -25
- package/dist/standalone/install-apps-cli.js +43 -6
- package/dist/standalone/instance.d.ts +2 -2
- package/dist/standalone/instance.js +8 -11
- package/dist/standalone/machine-link.d.ts +354 -0
- package/dist/standalone/machine-link.js +368 -0
- package/dist/standalone/media.d.ts +2 -2
- package/dist/standalone/media.js +19 -16
- package/dist/standalone/preview.d.ts +2 -2
- package/dist/standalone/preview.js +39 -12
- package/dist/standalone/registry.d.ts +149 -9
- package/dist/standalone/registry.js +299 -8
- package/dist/standalone/worker.d.ts +19 -5
- package/dist/standalone/worker.js +90 -54
- package/dist/standalone/workflow-binding.d.ts +28 -32
- package/dist/standalone/workflow-binding.js +20 -20
- package/dist/standalone/workflow-control.d.ts +4 -0
- package/dist/standalone/workflow-control.js +40 -0
- package/dist/standalone/workflow-events.d.ts +2 -2
- package/dist/standalone/workflow-events.js +9 -10
- package/dist/standalone/workflow-git-capture.js +4 -3
- package/dist/standalone/workflow-host.d.ts +177 -152
- package/dist/standalone/workflow-host.js +137 -30
- package/dist/standalone/workflow-node-capture.js +11 -4
- package/dist/standalone/workflow-schedules.d.ts +5 -2
- package/dist/standalone/workflow-schedules.js +9 -10
- package/dist/standalone/workflow-trigger-host.d.ts +88 -6
- package/dist/standalone/workflow-trigger-host.js +2 -2
- package/dist/standalone/workflow-webhooks.d.ts +22 -0
- package/dist/standalone/workflow-webhooks.js +39 -0
- package/dist/standalone/workflows.d.ts +203 -50
- package/dist/standalone/workflows.js +198 -39
- package/dist/storage-frame.d.ts +6 -6
- package/dist/testing/capabilities.js +14 -3
- package/dist/testing/installation.js +26 -2
- package/dist/testing/worker.js +1 -1
- package/dist/testing/workers-runtime.d.ts +8 -2
- package/dist/testing/workers-runtime.js +20 -2
- package/dist/webhook-abuse.d.ts +25 -0
- package/dist/webhook-abuse.js +54 -0
- package/dist/webhook-custody.d.ts +144 -0
- package/dist/webhook-custody.js +222 -0
- package/dist/webhook-ingress.d.ts +36 -0
- package/dist/webhook-ingress.js +146 -0
- package/dist/webhooks.d.ts +111 -0
- package/dist/webhooks.js +189 -0
- package/dist/workers-git.d.ts +12 -17
- package/dist/workers-git.js +60 -55
- package/dist/workers.d.ts +224 -13
- package/dist/workers.js +351 -51
- package/dist/workflow-agent-authority.d.ts +8 -0
- package/dist/workflow-agent-authority.js +42 -0
- package/dist/workflows.d.ts +66 -0
- package/dist/workflows.js +97 -0
- package/docs/api/README.md +63 -37
- package/docs/api/agents.md +17 -0
- package/docs/api/app-storage.md +1 -1
- package/docs/api/apps.md +1394 -543
- package/docs/api/browser/boot.md +132 -0
- package/docs/api/browser.md +1440 -0
- package/docs/api/build-contract.md +38 -25
- package/docs/api/build.md +263 -84
- package/docs/api/cloudflare.md +93 -7
- package/docs/api/git.md +3 -13
- package/docs/api/host.md +944 -118
- package/docs/api/index.md +320 -18
- package/docs/api/keys.md +24 -1
- package/docs/api/mcp.md +59 -12
- package/docs/api/modules.md +33 -40
- package/docs/api/pack.md +57 -8
- package/docs/api/page/mount.md +92 -4
- package/docs/api/workers-git.md +103 -24
- package/docs/api/workers.md +1581 -244
- package/docs/site/agent-quickstart.mdx +28 -14
- package/examples/standalone/worker.ts +3 -1
- package/examples/standalone/wrangler.jsonc +2 -0
- package/package.json +73 -69
- package/dist/installation-consent.d.ts +0 -79
- package/dist/installation-consent.js +0 -82
- package/dist/shell/app-directory.d.ts +0 -542
- package/dist/shell/app-directory.js +0 -199
- package/dist/shell/browser-actions.d.ts +0 -7
- package/dist/shell/browser-actions.js +0 -56
- package/dist/shell/command-host.d.ts +0 -112
- package/dist/shell/command-host.js +0 -502
- package/dist/shell/commands.d.ts +0 -25
- package/dist/shell/commands.js +0 -78
- package/dist/shell/index.d.ts +0 -8
- package/dist/shell/index.js +0 -8
- package/dist/shell/keys.d.ts +0 -41
- package/dist/shell/keys.js +0 -134
- package/dist/shell/shell-module.d.ts +0 -55
- package/dist/shell/shell-module.js +0 -86
- package/dist/shell/window-manager.d.ts +0 -124
- package/dist/shell/window-manager.js +0 -711
- package/dist/shell/workbench-contract.d.ts +0 -68
- package/dist/shell/workbench-directory.d.ts +0 -332
- package/dist/shell/workbench-directory.js +0 -35
- package/dist/shell/workbench-host-types.d.ts +0 -96
- package/dist/shell/workbench-host-types.js +0 -1
- package/dist/shell/workbench-host.d.ts +0 -34
- package/dist/shell/workbench-host.js +0 -347
- package/dist/shell/workbench-model.d.ts +0 -192
- package/dist/shell/workbench-model.js +0 -53
- package/dist/shell/workbench.d.ts +0 -4
- package/dist/shell/workbench.js +0 -2
- package/docs/api/shell/app-directory.md +0 -599
- package/docs/api/shell/command-host.md +0 -224
- package/docs/api/shell/commands.md +0 -197
- package/docs/api/shell/keys.md +0 -183
- package/docs/api/shell/shell-module.md +0 -204
- package/docs/api/shell/window-manager.md +0 -267
- package/docs/api/shell/workbench-directory.md +0 -119
- package/docs/api/shell/workbench.md +0 -205
- package/docs/api/shell.md +0 -1915
- /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type BackgroundSyncRefusal } from "@fungi.computer/puffball/background-replay";
|
|
2
2
|
import { type AppGitPushFact, type GitPushQuestion, type GitPushVerdict } from "@fungi.computer/agar/git";
|
|
3
|
-
import { type CairnId } from "@fungi.computer/cairn/id";
|
|
4
3
|
import * as Effect from "effect/Effect";
|
|
5
4
|
import * as Schema from "effect/Schema";
|
|
6
5
|
import type { DurableBackend } from "@fungi.computer/puffball/backend";
|
|
@@ -9,15 +8,14 @@ import type { AppMethodReply } from "@fungi.computer/agar/backend";
|
|
|
9
8
|
import type { AppApi } from "@fungi.computer/puffball";
|
|
10
9
|
import type { InvocationFrame } from "./invocation.js";
|
|
11
10
|
import type { Installation } from "./apps/installation.js";
|
|
11
|
+
import { type UiBootCheckOutcome } from "./boot-gate.js";
|
|
12
|
+
/** Runtime validator for report-only installation UI-check outcomes. */
|
|
13
|
+
export { uiBootCheckOutcomeSchema } from "./boot-gate.js";
|
|
14
|
+
/** A report-only UI-check result stored with an installation operation. */
|
|
15
|
+
export type { UiBootCheckOutcome } from "./boot-gate.js";
|
|
12
16
|
import { type GillCall, type GillReply } from "@fungi.computer/gills";
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
readonly instance: import("@fungi.computer/cairn").IdCodec<"app-instance", "instance", 1>;
|
|
16
|
-
}>;
|
|
17
|
-
/** A stable App Instance ID minted by {@link instanceIds}. */
|
|
18
|
-
export type InstanceId = CairnId<"app-instance", "instance">;
|
|
19
|
-
/** Decodes a string into an {@link InstanceId}, rejecting any other ID family. */
|
|
20
|
-
export declare const instanceIdSchema: Schema.Codec<InstanceId, string>;
|
|
17
|
+
export { agentAvatarProjectionSchema, agentAvatarSchema, avatarFromProjection, createAgentAvatarStore, type AgentAvatarStore, } from "./agent-avatars.js";
|
|
18
|
+
export { instanceIds, instanceIdSchema, type InstanceId, } from "./instance-id.js";
|
|
21
19
|
/**
|
|
22
20
|
* The owner that issues authority for an Instance: an `installation` of an App
|
|
23
21
|
* or a `deployment`. Owner identity never changes for the life of an Instance.
|
|
@@ -31,7 +29,7 @@ export declare const ownerSchema: Schema.Struct<{
|
|
|
31
29
|
* runs against, at a positive authority version.
|
|
32
30
|
*/
|
|
33
31
|
export declare const selectionSchema: Schema.Struct<{
|
|
34
|
-
readonly instanceId: Schema.Codec<InstanceId, string, never, never>;
|
|
32
|
+
readonly instanceId: Schema.Codec<import("./instance-id.js").InstanceId, string, never, never>;
|
|
35
33
|
readonly owner: Schema.Struct<{
|
|
36
34
|
readonly kind: Schema.Literals<readonly ["installation", "deployment"]>;
|
|
37
35
|
readonly id: Schema.NonEmptyString;
|
|
@@ -43,7 +41,7 @@ export declare const selectionSchema: Schema.Struct<{
|
|
|
43
41
|
/** A complete owner-issued state: a selection plus `enabled`, `disabled` or `deleted`. */
|
|
44
42
|
export declare const ownerStateSchema: Schema.Struct<{
|
|
45
43
|
readonly status: Schema.Literals<readonly ["enabled", "disabled", "deleted"]>;
|
|
46
|
-
readonly instanceId: Schema.Codec<InstanceId, string, never, never>;
|
|
44
|
+
readonly instanceId: Schema.Codec<import("./instance-id.js").InstanceId, string, never, never>;
|
|
47
45
|
readonly owner: Schema.Struct<{
|
|
48
46
|
readonly kind: Schema.Literals<readonly ["installation", "deployment"]>;
|
|
49
47
|
readonly id: Schema.NonEmptyString;
|
|
@@ -62,7 +60,7 @@ export declare const instanceSchema: Schema.Struct<{
|
|
|
62
60
|
readonly stateSchema: Schema.NullOr<Schema.Number>;
|
|
63
61
|
readonly desiredStatus: Schema.Literals<readonly ["enabled", "disabled", "deleted"]>;
|
|
64
62
|
readonly status: Schema.Literals<readonly ["active", "disabled", "deleting", "deleted"]>;
|
|
65
|
-
readonly instanceId: Schema.Codec<InstanceId, string, never, never>;
|
|
63
|
+
readonly instanceId: Schema.Codec<import("./instance-id.js").InstanceId, string, never, never>;
|
|
66
64
|
readonly owner: Schema.Struct<{
|
|
67
65
|
readonly kind: Schema.Literals<readonly ["installation", "deployment"]>;
|
|
68
66
|
readonly id: Schema.NonEmptyString;
|
|
@@ -84,7 +82,7 @@ export type Backend = Readonly<{
|
|
|
84
82
|
backend: DurableBackend;
|
|
85
83
|
}>;
|
|
86
84
|
/** The runtime owns the bounded rejection grammar, including across RPC. */
|
|
87
|
-
export declare const appInstanceErrorCodeSchema: Schema.Literals<readonly ["invalid_owner_state", "invalid_invocation_facts", "revoked", "binding_not_granted", "binding_unavailable", "expired", "reentrant", "instance_identity_mismatch", "instance_owner_mismatch", "conflicting_owner_state", "stale_authority", "instance_deleted", "release_app_mismatch", "state_schema_migration_unsupported", "instance_inactive", "instance_authority_version_mismatch", "release_no_longer_matches_instance", "instance_release_mismatch", "installation_tenant_mismatch"]>;
|
|
85
|
+
export declare const appInstanceErrorCodeSchema: Schema.Literals<readonly ["invalid_owner_state", "invalid_invocation_facts", "revoked", "disabled", "binding_not_granted", "binding_unavailable", "expired", "reentrant", "instance_identity_mismatch", "instance_owner_mismatch", "conflicting_owner_state", "stale_authority", "instance_deleted", "release_app_mismatch", "state_schema_migration_unsupported", "instance_inactive", "instance_authority_version_mismatch", "release_no_longer_matches_instance", "instance_release_mismatch", "installation_tenant_mismatch", ...("backend_load_failed" | "backend_construction_failed" | "ui_mount_failed" | "boot_runner_unavailable" | "boot_browser_binding_missing" | "boot_clone_unavailable" | "boot_timeout" | "boot_cleanup_failed")[]]>;
|
|
88
86
|
/** One of the bounded {@link appInstanceErrorCodeSchema} rejection codes. */
|
|
89
87
|
export type AppInstanceErrorCode = typeof appInstanceErrorCodeSchema.Type;
|
|
90
88
|
/** Stable runtime failure identity; message remains presentation only. */
|
|
@@ -110,8 +108,19 @@ export type InstancePorts<Host> = Readonly<{
|
|
|
110
108
|
write: (instance: Instance) => Effect.Effect<void, Error>;
|
|
111
109
|
/** Resolve a Release ID to its verified durable backend. */
|
|
112
110
|
resolve: (release: Selection["releaseId"], scope: BackendResolution<Host>) => Effect.Effect<Backend, Error>;
|
|
113
|
-
/**
|
|
114
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Host-owned backend construction gate plus UI-check report. Backend
|
|
113
|
+
* construction errors block selection; the returned UI outcome is advisory.
|
|
114
|
+
* `null` means this executor deliberately did not run a UI check. The prior
|
|
115
|
+
* schema comes from this operation's persisted read, not the candidate.
|
|
116
|
+
* Prepare asks for the UI check (`"run"`); apply proves construction again
|
|
117
|
+
* but `"reuse"`s prepare's recorded result and never opens a browser.
|
|
118
|
+
* UI artifacts are verified during preparation, not re-read on apply-only
|
|
119
|
+
* lifecycle changes; Releases and their artifacts are content-addressed.
|
|
120
|
+
*/
|
|
121
|
+
boot: (backend: Backend, priorStateSchema: Instance["stateSchema"], uiCheck: "run" | "reuse") => Effect.Effect<UiBootCheckOutcome | null, Error>;
|
|
122
|
+
/** Abort in-flight work after fencing its authority and invalidate connections. */
|
|
123
|
+
abort: (reason: AppInstanceError) => Effect.Effect<void, Error>;
|
|
115
124
|
/** Delete the backend's own state. */
|
|
116
125
|
purge: () => Effect.Effect<void, Error>;
|
|
117
126
|
/**
|
|
@@ -143,6 +152,8 @@ export type AppInstance<Host> = Readonly<{
|
|
|
143
152
|
* changed input at the same version conflicts and older versions are stale.
|
|
144
153
|
*/
|
|
145
154
|
apply: (input: OwnerState) => Effect.Effect<Instance, Error>;
|
|
155
|
+
/** Run the same lifecycle and boot checks without writing, aborting or purging. */
|
|
156
|
+
prepare: (input: OwnerState) => Effect.Effect<UiBootCheckOutcome | null, Error>;
|
|
146
157
|
/** Admit the frame's selection and forward an HTTP request to the active backend. */
|
|
147
158
|
fetch: (frame: InvocationFrame<Host>, request: Request) => Effect.Effect<Response, Error>;
|
|
148
159
|
/** Admit the frame and invoke a method declared by the Release's App API. */
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
import { backgroundSyncRefusalSchema, } from "@fungi.computer/puffball/background-replay";
|
|
2
2
|
import { appGitPushFactSchema, gitPushQuestionSchema, gitPushVerdictSchema, } from "@fungi.computer/agar/git";
|
|
3
3
|
import * as Semaphore from "effect/Semaphore";
|
|
4
|
-
import {
|
|
4
|
+
import { instanceIdSchema } from "./instance-id.js";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import * as Schema from "effect/Schema";
|
|
7
7
|
import { releaseIdSchema, appIdSchema } from "@fungi.computer/puffball/effect";
|
|
8
8
|
import { appFacetRequest, appFacetResponse } from "./backend-request.js";
|
|
9
9
|
import { appApiSchema } from "@fungi.computer/puffball/app";
|
|
10
|
+
import { bootFailureSchema, BootGateError, } from "./boot-gate.js";
|
|
11
|
+
/** Runtime validator for report-only installation UI-check outcomes. */
|
|
12
|
+
export { uiBootCheckOutcomeSchema } from "./boot-gate.js";
|
|
10
13
|
import { gillCallSchema, gillReplySchema, } from "@fungi.computer/gills";
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
family: "app-instance",
|
|
14
|
-
version: 1,
|
|
15
|
-
kinds: { instance: { prefix: "instance" } },
|
|
16
|
-
});
|
|
17
|
-
/** Decodes a string into an {@link InstanceId}, rejecting any other ID family. */
|
|
18
|
-
export const instanceIdSchema = Schema.String.pipe(Schema.refine((value) => instanceIds.instance.is(value)));
|
|
14
|
+
export { agentAvatarProjectionSchema, agentAvatarSchema, avatarFromProjection, createAgentAvatarStore, } from "./agent-avatars.js";
|
|
15
|
+
export { instanceIds, instanceIdSchema, } from "./instance-id.js";
|
|
19
16
|
/**
|
|
20
17
|
* The owner that issues authority for an Instance: an `installation` of an App
|
|
21
18
|
* or a `deployment`. Owner identity never changes for the life of an Instance.
|
|
@@ -59,7 +56,7 @@ export function selectionOf(installation) {
|
|
|
59
56
|
owner: { kind: "installation", id: installation.installationId },
|
|
60
57
|
appId: installation.release.appId,
|
|
61
58
|
releaseId: installation.release.releaseId,
|
|
62
|
-
authorityVersion: installation.authorityVersion,
|
|
59
|
+
authorityVersion: installation.authority.authorityVersion,
|
|
63
60
|
};
|
|
64
61
|
}
|
|
65
62
|
/** The runtime owns the bounded rejection grammar, including across RPC. */
|
|
@@ -67,6 +64,7 @@ export const appInstanceErrorCodeSchema = Schema.Literals([
|
|
|
67
64
|
"invalid_owner_state",
|
|
68
65
|
"invalid_invocation_facts",
|
|
69
66
|
"revoked",
|
|
67
|
+
"disabled",
|
|
70
68
|
"binding_not_granted",
|
|
71
69
|
"binding_unavailable",
|
|
72
70
|
"expired",
|
|
@@ -83,11 +81,22 @@ export const appInstanceErrorCodeSchema = Schema.Literals([
|
|
|
83
81
|
"release_no_longer_matches_instance",
|
|
84
82
|
"instance_release_mismatch",
|
|
85
83
|
"installation_tenant_mismatch",
|
|
84
|
+
...bootFailureSchema.options,
|
|
86
85
|
]);
|
|
87
86
|
const APP_INSTANCE_ERROR_MESSAGES = {
|
|
87
|
+
backend_load_failed: new BootGateError("backend_load_failed").message,
|
|
88
|
+
backend_construction_failed: new BootGateError("backend_construction_failed")
|
|
89
|
+
.message,
|
|
90
|
+
ui_mount_failed: new BootGateError("ui_mount_failed").message,
|
|
91
|
+
boot_runner_unavailable: new BootGateError("boot_runner_unavailable").message,
|
|
92
|
+
boot_browser_binding_missing: new BootGateError("boot_browser_binding_missing").message,
|
|
93
|
+
boot_clone_unavailable: new BootGateError("boot_clone_unavailable").message,
|
|
94
|
+
boot_timeout: new BootGateError("boot_timeout").message,
|
|
95
|
+
boot_cleanup_failed: new BootGateError("boot_cleanup_failed").message,
|
|
88
96
|
invalid_owner_state: "Invalid owner state",
|
|
89
97
|
invalid_invocation_facts: "Invalid invocation facts",
|
|
90
98
|
revoked: "Invocation authority revoked",
|
|
99
|
+
disabled: "App disabled",
|
|
91
100
|
binding_not_granted: "Binding operation not granted",
|
|
92
101
|
binding_unavailable: "Binding operation unavailable on this host",
|
|
93
102
|
expired: "Invocation deadline exceeded",
|
|
@@ -136,11 +145,11 @@ export function createAppInstance(ports) {
|
|
|
136
145
|
}
|
|
137
146
|
return current;
|
|
138
147
|
});
|
|
139
|
-
const
|
|
148
|
+
const preflight = (input, readCurrent, uiCheck) => Effect.gen(function* () {
|
|
140
149
|
const desired = yield* Schema.decodeUnknownEffect(ownerStateSchema)(input).pipe(Effect.mapError(() => new AppInstanceError("invalid_owner_state")));
|
|
141
150
|
if (desired.instanceId !== ports.instanceId)
|
|
142
151
|
return yield* failure("instance_identity_mismatch");
|
|
143
|
-
const current = yield*
|
|
152
|
+
const current = yield* readCurrent;
|
|
144
153
|
if (current && !sameOwner(current, desired))
|
|
145
154
|
return yield* failure("instance_owner_mismatch");
|
|
146
155
|
const retry = current !== null &&
|
|
@@ -151,14 +160,15 @@ export function createAppInstance(ports) {
|
|
|
151
160
|
return yield* failure("conflicting_owner_state");
|
|
152
161
|
if (current && desired.authorityVersion < current.authorityVersion)
|
|
153
162
|
return yield* failure("stale_authority");
|
|
154
|
-
if (current?.status === "deleted") {
|
|
163
|
+
if (current?.status === "deleted" || current?.status === "deleting") {
|
|
155
164
|
if (retry && desired.status === "deleted")
|
|
156
|
-
return current;
|
|
165
|
+
return { kind: "unchanged", receipt: current };
|
|
157
166
|
return yield* failure("instance_deleted");
|
|
158
167
|
}
|
|
159
168
|
if (retry && current.status === "active")
|
|
160
|
-
return current;
|
|
169
|
+
return { kind: "unchanged", receipt: current };
|
|
161
170
|
let stateSchema = current?.stateSchema ?? null;
|
|
171
|
+
let bootCheck = null;
|
|
162
172
|
if (desired.status === "enabled") {
|
|
163
173
|
const resolved = yield* ports.resolve(desired.releaseId, {
|
|
164
174
|
kind: "metadata",
|
|
@@ -169,7 +179,20 @@ export function createAppInstance(ports) {
|
|
|
169
179
|
stateSchema !== resolved.backend.runtime.stateSchema)
|
|
170
180
|
return yield* failure("state_schema_migration_unsupported");
|
|
171
181
|
stateSchema = resolved.backend.runtime.stateSchema;
|
|
182
|
+
bootCheck = yield* ports.boot(resolved, current?.stateSchema ?? null, uiCheck);
|
|
172
183
|
}
|
|
184
|
+
return { kind: "apply", desired, stateSchema, bootCheck };
|
|
185
|
+
});
|
|
186
|
+
const prepare = (input) => lock.withPermits(1)(Effect.gen(function* () {
|
|
187
|
+
// The one UI check for this selection; apply reuses its result.
|
|
188
|
+
const transition = yield* preflight(input, ports.read(), "run");
|
|
189
|
+
return transition.kind === "apply" ? transition.bootCheck : null;
|
|
190
|
+
}));
|
|
191
|
+
const apply = (input) => lock.withPermits(1)(Effect.gen(function* () {
|
|
192
|
+
const transition = yield* preflight(input, read, "reuse");
|
|
193
|
+
if (transition.kind === "unchanged")
|
|
194
|
+
return transition.receipt;
|
|
195
|
+
const { desired, stateSchema } = transition;
|
|
173
196
|
const next = {
|
|
174
197
|
...desired,
|
|
175
198
|
desiredStatus: desired.status,
|
|
@@ -180,7 +203,7 @@ export function createAppInstance(ports) {
|
|
|
180
203
|
};
|
|
181
204
|
// Persist the exact owner fact before stopping runtime; no resource-issued version.
|
|
182
205
|
yield* ports.write(next);
|
|
183
|
-
yield* ports.abort();
|
|
206
|
+
yield* ports.abort(new AppInstanceError(desired.status === "disabled" ? "disabled" : "revoked"));
|
|
184
207
|
if (desired.status === "deleted")
|
|
185
208
|
yield* ports.purge();
|
|
186
209
|
const receipt = {
|
|
@@ -309,6 +332,7 @@ export function createAppInstance(ports) {
|
|
|
309
332
|
}));
|
|
310
333
|
return {
|
|
311
334
|
syncRefused,
|
|
335
|
+
prepare,
|
|
312
336
|
apply,
|
|
313
337
|
fetch,
|
|
314
338
|
call,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Local Release installation uses the ordinary pack uploader and owner API. */
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
6
|
+
import { installRelease } from "./pack.js";
|
|
7
|
+
export const installReleaseUsage = "Usage: oyster install <directory|release.json> [--installation-id <name>]";
|
|
8
|
+
export async function installReleaseCommand(args) {
|
|
9
|
+
const { values, positionals } = parseArgs({
|
|
10
|
+
args: [...args],
|
|
11
|
+
allowPositionals: true,
|
|
12
|
+
strict: true,
|
|
13
|
+
options: {
|
|
14
|
+
"installation-id": { type: "string" },
|
|
15
|
+
help: { type: "boolean", short: "h" },
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
if (values.help) {
|
|
19
|
+
process.stdout.write(installReleaseUsage +
|
|
20
|
+
"\nUpload a built Release and install it using OYSTER_URL and OYSTER_OWNER_KEY.\n");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const [source] = positionals;
|
|
24
|
+
if (positionals.length !== 1 || source === undefined)
|
|
25
|
+
throw new Error(installReleaseUsage);
|
|
26
|
+
const url = process.env.OYSTER_URL;
|
|
27
|
+
const key = process.env.OYSTER_OWNER_KEY;
|
|
28
|
+
if (!url || !key)
|
|
29
|
+
throw new Error("Set OYSTER_URL and OYSTER_OWNER_KEY for the target Oyster. " +
|
|
30
|
+
installReleaseUsage);
|
|
31
|
+
const path = resolve(source);
|
|
32
|
+
const info = await stat(path);
|
|
33
|
+
if (!info.isDirectory() &&
|
|
34
|
+
(!info.isFile() || basename(path) !== "release.json"))
|
|
35
|
+
throw new Error("Expected a Release directory or release.json");
|
|
36
|
+
const response = await installRelease({
|
|
37
|
+
directory: info.isDirectory() ? path : dirname(path),
|
|
38
|
+
url,
|
|
39
|
+
key,
|
|
40
|
+
installationId: values["installation-id"],
|
|
41
|
+
});
|
|
42
|
+
const body = await response.text();
|
|
43
|
+
if (!response.ok)
|
|
44
|
+
throw new Error("Installation failed (" + String(response.status) + "): " + body);
|
|
45
|
+
process.stdout.write(body + "\n");
|
|
46
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Release } from "@fungi.computer/puffball";
|
|
2
|
+
import { type InstallationOperation } from "./installation-operations.js";
|
|
3
|
+
export type InstallationCompletion = Exclude<InstallationOperation, {
|
|
4
|
+
state: "pending";
|
|
5
|
+
}>;
|
|
6
|
+
export type InstallationObservationBudget = Readonly<{
|
|
7
|
+
/** Upload/observation time; expiry never cancels admitted durable work. */
|
|
8
|
+
waitMs?: number;
|
|
9
|
+
/** Caller-owned budget; used unchanged unless waitMs is also explicit. */
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}>;
|
|
12
|
+
/** Share one budget across pack uploads and the subsequent receipt observation. */
|
|
13
|
+
export declare function installationObservationSignal(input: InstallationObservationBudget): AbortSignal;
|
|
14
|
+
/** Observer failure supplies no installation outcome and never cancels its owner. */
|
|
15
|
+
export declare class InstallationObservationError extends Error {
|
|
16
|
+
readonly requestId: string;
|
|
17
|
+
constructor(requestId: string, options?: ErrorOptions);
|
|
18
|
+
}
|
|
19
|
+
/** Observe one retained command, over either HTTP or the host's decoded port. */
|
|
20
|
+
export declare function observeInstallation(input: Readonly<{
|
|
21
|
+
requestId: string;
|
|
22
|
+
initial: InstallationOperation | null;
|
|
23
|
+
read(): Promise<InstallationOperation | null>;
|
|
24
|
+
signal: AbortSignal;
|
|
25
|
+
pollMs?: number;
|
|
26
|
+
idle?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
27
|
+
}>): Promise<InstallationCompletion>;
|
|
28
|
+
/** Completed HTTP meaning shared by pack and the retained PUT selection door. */
|
|
29
|
+
export declare function completedInstallationResponse(operation: InstallationCompletion): Response;
|
|
30
|
+
/**
|
|
31
|
+
* Submit once and observe the correlated owner receipt. Both CLI paths use
|
|
32
|
+
* exactly this contract; no directory reads or old completed-POST branch.
|
|
33
|
+
*/
|
|
34
|
+
export declare function installOnOyster(input: Readonly<{
|
|
35
|
+
url: string;
|
|
36
|
+
key: string;
|
|
37
|
+
installationId: string;
|
|
38
|
+
release: Release;
|
|
39
|
+
pollMs?: number;
|
|
40
|
+
idle?: (ms: number, signal: AbortSignal) => Promise<void>;
|
|
41
|
+
/** Once, after the owner supplies a correlated record, even after a lost ack. */
|
|
42
|
+
onAdmitted?: (operation: InstallationOperation) => void;
|
|
43
|
+
}> & InstallationObservationBudget): Promise<InstallationCompletion>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
|
+
import { addAbortListener } from "node:events";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { releaseSchema } from "@fungi.computer/puffball/effect";
|
|
5
|
+
import { instanceRefusalBody } from "./instance-refusal.js";
|
|
6
|
+
import { installationOperationSchema, installationCommandIds, } from "./installation-operations.js";
|
|
7
|
+
/**
|
|
8
|
+
* Installer-owned observer budget, matching the standalone installer's existing
|
|
9
|
+
* twenty-minute default. Not an App grant lifetime or a server execution limit.
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_INSTALLATION_WAIT_MS = 20 * 60_000;
|
|
12
|
+
/** Share one budget across pack uploads and the subsequent receipt observation. */
|
|
13
|
+
export function installationObservationSignal(input) {
|
|
14
|
+
if (input.signal !== undefined && input.waitMs === undefined)
|
|
15
|
+
return input.signal;
|
|
16
|
+
const timer = AbortSignal.timeout(input.waitMs ?? DEFAULT_INSTALLATION_WAIT_MS);
|
|
17
|
+
return input.signal === undefined
|
|
18
|
+
? timer
|
|
19
|
+
: AbortSignal.any([input.signal, timer]);
|
|
20
|
+
}
|
|
21
|
+
/** Observer failure supplies no installation outcome and never cancels its owner. */
|
|
22
|
+
export class InstallationObservationError extends Error {
|
|
23
|
+
requestId;
|
|
24
|
+
constructor(requestId, options) {
|
|
25
|
+
super(`Installation outcome unconfirmed (${requestId})`, options);
|
|
26
|
+
this.requestId = requestId;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const idle = (ms, signal) => sleep(ms, undefined, { signal });
|
|
30
|
+
/** Observe one retained command, over either HTTP or the host's decoded port. */
|
|
31
|
+
export async function observeInstallation(input) {
|
|
32
|
+
try {
|
|
33
|
+
input.signal.throwIfAborted();
|
|
34
|
+
let operation = input.initial;
|
|
35
|
+
while (operation === null || operation.state === "pending") {
|
|
36
|
+
input.signal.throwIfAborted();
|
|
37
|
+
// The decoded RPC port has no cancellation argument. Stop THIS wait
|
|
38
|
+
// without cancelling the retained command or abandoning its late reply.
|
|
39
|
+
let listener;
|
|
40
|
+
try {
|
|
41
|
+
operation = await new Promise((resolve, reject) => {
|
|
42
|
+
listener = addAbortListener(input.signal, () => {
|
|
43
|
+
reject(new InstallationObservationError(input.requestId, {
|
|
44
|
+
cause: input.signal.reason,
|
|
45
|
+
}));
|
|
46
|
+
});
|
|
47
|
+
// Both late outcomes remain handled after the observer has left.
|
|
48
|
+
Promise.resolve()
|
|
49
|
+
.then(() => input.read())
|
|
50
|
+
.then(resolve, reject);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
listener?.[Symbol.dispose]();
|
|
55
|
+
}
|
|
56
|
+
input.signal.throwIfAborted();
|
|
57
|
+
if (operation === null || operation.state === "pending")
|
|
58
|
+
await (input.idle ?? idle)(input.pollMs ?? 5_000, input.signal);
|
|
59
|
+
}
|
|
60
|
+
return operation;
|
|
61
|
+
}
|
|
62
|
+
catch (cause) {
|
|
63
|
+
if (cause instanceof InstallationObservationError)
|
|
64
|
+
throw cause;
|
|
65
|
+
throw new InstallationObservationError(input.requestId, { cause });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Completed HTTP meaning shared by pack and the retained PUT selection door. */
|
|
69
|
+
export function completedInstallationResponse(operation) {
|
|
70
|
+
if (operation.state === "unconfirmed")
|
|
71
|
+
throw new InstallationObservationError(operation.requestId);
|
|
72
|
+
if (operation.state === "refused")
|
|
73
|
+
return Response.json(instanceRefusalBody(operation.code), {
|
|
74
|
+
status: operation.status,
|
|
75
|
+
});
|
|
76
|
+
if (operation.installation === null)
|
|
77
|
+
return Response.json({
|
|
78
|
+
error: "installation_result_unavailable",
|
|
79
|
+
requestId: operation.requestId,
|
|
80
|
+
reference: operation.reference,
|
|
81
|
+
}, { status: 409 });
|
|
82
|
+
return Response.json(operation.installation, {
|
|
83
|
+
status: operation.creation === "replacement" ? 200 : 201,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Submit once and observe the correlated owner receipt. Both CLI paths use
|
|
88
|
+
* exactly this contract; no directory reads or old completed-POST branch.
|
|
89
|
+
*/
|
|
90
|
+
export async function installOnOyster(input) {
|
|
91
|
+
const requestId = installationCommandIds.request.generate();
|
|
92
|
+
const signal = installationObservationSignal(input);
|
|
93
|
+
const headers = {
|
|
94
|
+
Authorization: `Bearer ${input.key}`,
|
|
95
|
+
Accept: "application/json",
|
|
96
|
+
};
|
|
97
|
+
let admitted = false;
|
|
98
|
+
const decode = async (response) => {
|
|
99
|
+
const operation = installationOperationSchema.parse(await response.json());
|
|
100
|
+
if (operation.requestId !== requestId ||
|
|
101
|
+
operation.requestedInstallationId !== input.installationId ||
|
|
102
|
+
operation.release.appId !== input.release.appId ||
|
|
103
|
+
operation.release.releaseId !== input.release.releaseId ||
|
|
104
|
+
operation.release.artifact.artifactDigest !==
|
|
105
|
+
input.release.artifact.artifactDigest ||
|
|
106
|
+
(operation.state === "succeeded" &&
|
|
107
|
+
operation.installation !== null &&
|
|
108
|
+
(operation.installation.installationId !== operation.installationId ||
|
|
109
|
+
operation.installation.appId !== input.release.appId ||
|
|
110
|
+
operation.installation.release.releaseId !==
|
|
111
|
+
input.release.releaseId ||
|
|
112
|
+
operation.installation.release.artifact.artifactDigest !==
|
|
113
|
+
input.release.artifact.artifactDigest)))
|
|
114
|
+
throw new InstallationObservationError(requestId);
|
|
115
|
+
if (!admitted) {
|
|
116
|
+
admitted = true;
|
|
117
|
+
input.onAdmitted?.(operation);
|
|
118
|
+
}
|
|
119
|
+
return operation;
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
signal.throwIfAborted();
|
|
123
|
+
let operation = null;
|
|
124
|
+
// Catch only the transport, not a malformed authoritative acknowledgement.
|
|
125
|
+
let submitted;
|
|
126
|
+
try {
|
|
127
|
+
submitted = await fetch(new URL("/api/installations", input.url), {
|
|
128
|
+
method: "POST",
|
|
129
|
+
signal,
|
|
130
|
+
headers: {
|
|
131
|
+
...headers,
|
|
132
|
+
"Content-Type": "application/json",
|
|
133
|
+
"Idempotency-Key": requestId,
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
installationId: input.installationId,
|
|
137
|
+
release: Schema.encodeUnknownSync(releaseSchema)(input.release),
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
signal.throwIfAborted();
|
|
143
|
+
submitted = null;
|
|
144
|
+
// Missing acknowledgement is not permission to resubmit.
|
|
145
|
+
}
|
|
146
|
+
if (submitted?.status === 202)
|
|
147
|
+
operation = await decode(submitted);
|
|
148
|
+
else if (submitted !== null && submitted.status < 500)
|
|
149
|
+
throw new InstallationObservationError(requestId);
|
|
150
|
+
const statusUrl = new URL(`/api/installations/${encodeURIComponent(input.installationId)}/status`, input.url);
|
|
151
|
+
statusUrl.searchParams.set("requestId", requestId);
|
|
152
|
+
let observation = {
|
|
153
|
+
requestId,
|
|
154
|
+
initial: operation,
|
|
155
|
+
signal,
|
|
156
|
+
read: async () => {
|
|
157
|
+
// Like decoded RPC reads, transport errors reach the observer with
|
|
158
|
+
// their original cause; they are not an authoritative pending read.
|
|
159
|
+
const observed = await fetch(statusUrl, { headers, signal });
|
|
160
|
+
if (observed.status === 200)
|
|
161
|
+
return decode(observed);
|
|
162
|
+
if (observed.status !== 404 && observed.status < 500)
|
|
163
|
+
throw new InstallationObservationError(requestId);
|
|
164
|
+
return null;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
if (input.pollMs !== undefined)
|
|
168
|
+
observation = { ...observation, pollMs: input.pollMs };
|
|
169
|
+
if (input.idle !== undefined)
|
|
170
|
+
observation = { ...observation, idle: input.idle };
|
|
171
|
+
return await observeInstallation(observation);
|
|
172
|
+
}
|
|
173
|
+
catch (cause) {
|
|
174
|
+
if (cause instanceof InstallationObservationError)
|
|
175
|
+
throw cause;
|
|
176
|
+
throw new InstallationObservationError(requestId, { cause });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
+
import { type TenantScope } from "./tenant.js";
|
|
3
|
+
import { type RetainedInstallationCommand, type InstallationOutcome } from "./installation-operations.js";
|
|
4
|
+
import type { OysterHost } from "./host.js";
|
|
5
|
+
/** Ordinary Worker-side verification and lifecycle I/O for one retained intent. */
|
|
6
|
+
export declare function executeInstallation(host: OysterHost, input: RetainedInstallationCommand): Promise<InstallationOutcome>;
|
|
7
|
+
/** A loopback export with ordinary Worker I/O, not another resource or HTTP API. */
|
|
8
|
+
export declare function installationWorkerEntrypoint<Env>(hostFor: (env: Env, scope: TenantScope) => OysterHost | Promise<OysterHost>): new (ctx: ExecutionContext, env: Env) => WorkerEntrypoint<Env, unknown> & {
|
|
9
|
+
/** Execute the retained command these props name, in its tenant scope. */
|
|
10
|
+
run(): Promise<InstallationOutcome>;
|
|
11
|
+
};
|