@fungi.computer/oyster 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +228 -176
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +12 -2
  5. package/dist/agents.js +39 -2
  6. package/dist/app-builds.d.ts +76 -17
  7. package/dist/app-builds.js +207 -63
  8. package/dist/app-sources.d.ts +7 -22
  9. package/dist/app-sources.js +49 -14
  10. package/dist/apps/gate.d.ts +7 -7
  11. package/dist/apps/gate.js +6 -6
  12. package/dist/apps/installation.d.ts +35 -35
  13. package/dist/apps/installation.js +20 -19
  14. package/dist/build/artifact-writer.d.ts +40 -0
  15. package/dist/build/artifact-writer.js +181 -0
  16. package/dist/build/build-jobs.js +7 -1
  17. package/dist/build/build-policy.d.ts +10 -0
  18. package/dist/build/build-policy.js +10 -0
  19. package/dist/build/build-step.d.ts +12 -1
  20. package/dist/build/build-step.js +9 -1
  21. package/dist/build/candidate-builder.d.ts +68 -0
  22. package/dist/build/candidate-builder.js +91 -0
  23. package/dist/build/candidate-cli.d.ts +1 -0
  24. package/dist/build/candidate-cli.js +119 -0
  25. package/dist/build/candidate-cli.mjs +28220 -0
  26. package/dist/build/content-objects.d.ts +37 -0
  27. package/dist/build/content-objects.js +53 -0
  28. package/dist/build/effect.d.ts +18 -0
  29. package/dist/build/effect.js +52 -12
  30. package/dist/build/git-environment.d.ts +3 -0
  31. package/dist/build/git-environment.js +21 -9
  32. package/dist/build/local-build.d.ts +13 -3
  33. package/dist/build/local-build.js +149 -99
  34. package/dist/build/snapshot-package-store.d.ts +10 -0
  35. package/dist/build/snapshot-package-store.js +15 -0
  36. package/dist/build/snapshot-program-scripts.js +1 -1
  37. package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
  38. package/dist/build/snapshot-programs/snapshot-path.js +6 -0
  39. package/dist/build/submission-contract.d.ts +461 -17
  40. package/dist/build/submission-contract.js +136 -26
  41. package/dist/build/workspace-build.d.ts +7 -2
  42. package/dist/build/workspace-build.js +55 -11
  43. package/dist/build-contract.d.ts +3 -0
  44. package/dist/build-contract.js +3 -0
  45. package/dist/build-egress.d.ts +62 -0
  46. package/dist/build-egress.js +148 -0
  47. package/dist/build.d.ts +1 -0
  48. package/dist/build.js +1 -0
  49. package/dist/cloudflare.js +4 -4
  50. package/dist/frame-binding-wire-script.js +1 -1
  51. package/dist/frame-binding-wire.d.ts +1 -1
  52. package/dist/frame-binding-wire.js +1 -1
  53. package/dist/git-journal.js +4 -4
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +1 -0
  56. package/dist/installation-consent.d.ts +3 -1
  57. package/dist/installation-consent.js +2 -0
  58. package/dist/mcp-owner.js +20 -8
  59. package/dist/pack.d.ts +6 -3
  60. package/dist/pack.js +28 -11
  61. package/dist/page/gill-observation.d.ts +4 -0
  62. package/dist/page/gill-observation.js +31 -0
  63. package/dist/page/mount.d.ts +4 -8
  64. package/dist/page/window-launch.d.ts +18 -0
  65. package/dist/page/window-launch.js +11 -0
  66. package/dist/page-script.js +4 -4
  67. package/dist/release.d.ts +11 -0
  68. package/dist/release.js +4 -1
  69. package/dist/shell/app-directory.d.ts +50 -45
  70. package/dist/shell/app-directory.js +19 -18
  71. package/dist/shell/shell-module.d.ts +26 -2
  72. package/dist/shell/shell-module.js +51 -2
  73. package/dist/shell/window-manager.d.ts +5 -1
  74. package/dist/shell/window-manager.js +21 -2
  75. package/dist/shell/workbench-directory.d.ts +332 -0
  76. package/dist/shell/workbench-directory.js +35 -0
  77. package/dist/shell/workbench-host-types.d.ts +1 -1
  78. package/dist/shell/workbench-host.js +5 -0
  79. package/dist/shell/workbench-model.d.ts +3 -1
  80. package/dist/source/index.d.ts +6 -7
  81. package/dist/source/index.js +6 -7
  82. package/dist/source/template-push.d.ts +33 -0
  83. package/dist/source/template-push.js +223 -0
  84. package/dist/source/template-repository.d.ts +2 -0
  85. package/dist/source/template-repository.js +13 -0
  86. package/dist/source/{template-write.d.ts → template-seed.d.ts} +19 -20
  87. package/dist/source/template-seed.js +80 -0
  88. package/dist/standalone/agent-directory.d.ts +4 -0
  89. package/dist/standalone/agent-directory.js +4 -0
  90. package/dist/standalone/agents.d.ts +227 -0
  91. package/dist/standalone/agents.js +834 -0
  92. package/dist/standalone/app-builds-binding.d.ts +36 -0
  93. package/dist/standalone/app-builds-binding.js +119 -0
  94. package/dist/standalone/app-set.d.ts +91 -0
  95. package/dist/standalone/app-set.js +395 -0
  96. package/dist/standalone/app-source.d.ts +41 -0
  97. package/dist/standalone/app-source.js +59 -0
  98. package/dist/standalone/builds.d.ts +18 -0
  99. package/dist/standalone/builds.js +101 -0
  100. package/dist/standalone/computer-egress.d.ts +37 -0
  101. package/dist/standalone/computer-egress.js +111 -0
  102. package/dist/standalone/computer.d.ts +122 -0
  103. package/dist/standalone/computer.js +714 -0
  104. package/dist/standalone/install-apps-cli.d.ts +2 -0
  105. package/dist/standalone/install-apps-cli.js +126 -0
  106. package/dist/standalone/instance.d.ts +35 -0
  107. package/dist/standalone/instance.js +74 -0
  108. package/dist/standalone/media.d.ts +76 -0
  109. package/dist/standalone/media.js +227 -0
  110. package/dist/standalone/preview.d.ts +51 -0
  111. package/dist/standalone/preview.js +167 -0
  112. package/dist/standalone/registry.d.ts +102 -0
  113. package/dist/standalone/registry.js +193 -0
  114. package/dist/standalone/tenancy.d.ts +42 -0
  115. package/dist/standalone/tenancy.js +241 -0
  116. package/dist/standalone/worker.d.ts +55 -0
  117. package/dist/standalone/worker.js +147 -0
  118. package/dist/standalone/workflow-authority-readers.d.ts +16 -0
  119. package/dist/standalone/workflow-authority-readers.js +35 -0
  120. package/dist/standalone/workflow-binding.d.ts +216 -0
  121. package/dist/standalone/workflow-binding.js +217 -0
  122. package/dist/standalone/workflow-events.d.ts +46 -0
  123. package/dist/standalone/workflow-events.js +39 -0
  124. package/dist/standalone/workflow-git-capture.d.ts +7 -0
  125. package/dist/standalone/workflow-git-capture.js +62 -0
  126. package/dist/standalone/workflow-host.d.ts +955 -0
  127. package/dist/standalone/workflow-host.js +778 -0
  128. package/dist/standalone/workflow-node-capture.d.ts +13 -0
  129. package/dist/standalone/workflow-node-capture.js +72 -0
  130. package/dist/standalone/workflow-root-authority.d.ts +27 -0
  131. package/dist/standalone/workflow-root-authority.js +87 -0
  132. package/dist/standalone/workflow-schedules.d.ts +52 -0
  133. package/dist/standalone/workflow-schedules.js +40 -0
  134. package/dist/standalone/workflow-trigger-host.d.ts +1716 -0
  135. package/dist/standalone/workflow-trigger-host.js +52 -0
  136. package/dist/standalone/workflows.d.ts +713 -0
  137. package/dist/standalone/workflows.js +554 -0
  138. package/dist/tenancy/auth0.d.ts +64 -0
  139. package/dist/tenancy/auth0.js +198 -0
  140. package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
  141. package/dist/tenancy/cloudflare/rate-limit.js +19 -0
  142. package/dist/tenancy/cloudflare/registry.d.ts +50 -0
  143. package/dist/tenancy/cloudflare/registry.js +301 -0
  144. package/dist/tenancy/cloudflare.d.ts +2 -0
  145. package/dist/tenancy/cloudflare.js +2 -0
  146. package/dist/tenancy/cold-directory.d.ts +13 -0
  147. package/dist/tenancy/cold-directory.js +43 -0
  148. package/dist/tenancy/contracts.d.ts +195 -0
  149. package/dist/tenancy/contracts.js +1 -0
  150. package/dist/tenancy/index.d.ts +19 -0
  151. package/dist/tenancy/index.js +156 -0
  152. package/dist/tenancy/owner-key.d.ts +26 -0
  153. package/dist/tenancy/owner-key.js +63 -0
  154. package/dist/tenancy/oyster.d.ts +4 -0
  155. package/dist/tenancy/oyster.js +25 -0
  156. package/dist/tenancy/registry-record.d.ts +7 -0
  157. package/dist/tenancy/registry-record.js +44 -0
  158. package/dist/tenancy/registry.d.ts +27 -0
  159. package/dist/tenancy/registry.js +138 -0
  160. package/dist/tenancy/resolve.d.ts +7 -0
  161. package/dist/tenancy/resolve.js +64 -0
  162. package/dist/workers-git.js +1 -4
  163. package/dist/workers.d.ts +2 -2
  164. package/dist/workers.js +3 -1
  165. package/docs/api/build-contract.md +829 -32
  166. package/docs/api/build.md +253 -17
  167. package/docs/api/modules.md +40 -32
  168. package/docs/api/pack.md +6 -3
  169. package/docs/api/shell/app-directory.md +267 -0
  170. package/docs/api/shell/shell-module.md +64 -3
  171. package/docs/api/shell/workbench-directory.md +119 -0
  172. package/docs/api/shell/workbench.md +19 -0
  173. package/docs/api/shell.md +127 -0
  174. package/docs/api/tenancy/auth0.md +110 -0
  175. package/docs/api/tenancy/cloudflare.md +221 -0
  176. package/docs/api/tenancy/cold-directory.md +46 -0
  177. package/docs/api/tenancy/owner-key.md +63 -0
  178. package/docs/api/tenancy/registry.md +77 -0
  179. package/docs/api/tenancy/resolve.md +69 -0
  180. package/docs/api/tenancy.md +430 -0
  181. package/docs/api/workers-git.md +140 -21
  182. package/docs/api/workers.md +15 -2
  183. package/docs/site/agent-quickstart.mdx +52 -55
  184. package/examples/standalone/worker.ts +7 -14
  185. package/examples/standalone/wrangler.jsonc +67 -6
  186. package/package.json +78 -25
  187. package/dist/build/r2-artifact-writer.d.ts +0 -31
  188. package/dist/build/r2-artifact-writer.js +0 -179
  189. package/dist/source/template-write.js +0 -344
  190. package/docs/media/architecture.mmd +0 -32
  191. package/docs/media/architecture.png +0 -0
  192. package/docs/media/bonsai-network.png +0 -0
  193. package/docs/media/bonsai-repository.png +0 -0
  194. package/examples/git/worker.ts +0 -39
  195. package/examples/git/wrangler.jsonc +0 -32
@@ -0,0 +1,138 @@
1
+ import { checkedOrigin, immutable, createMemberId, membershipVersionSchema, } from "./registry-record.js";
2
+ import * as Schema from "effect/Schema";
3
+ import { tenantIdSchema } from "../tenant.js";
4
+ /** In-memory tenant and member owner; create updates both atomically. */
5
+ export function memoryRegistry(options = {}) {
6
+ const tenants = new Map();
7
+ const handles = new Map();
8
+ const domains = new Map();
9
+ const identities = new Map();
10
+ const memberships = new Map();
11
+ let revision = 0;
12
+ const nextRevision = () => {
13
+ revision = Schema.decodeUnknownSync(membershipVersionSchema)(revision + 1);
14
+ return revision;
15
+ };
16
+ const canonicalMember = (identity) => identities.get(identity.provider)?.get(identity.subject);
17
+ const retainMember = (identity, memberId) => {
18
+ let subjects = identities.get(identity.provider);
19
+ if (subjects === undefined) {
20
+ subjects = new Map();
21
+ identities.set(identity.provider, subjects);
22
+ }
23
+ const previous = subjects.get(identity.subject);
24
+ if (previous !== undefined && previous !== memberId)
25
+ throw new Error("Identity already has a canonical member mapping");
26
+ subjects.set(identity.subject, memberId);
27
+ };
28
+ const insert = (tenant) => {
29
+ if (tenants.has(tenant.id) ||
30
+ handles.has(tenant.handle) ||
31
+ tenant.domains.some((domain) => domains.has(domain)))
32
+ throw new Error("Tenant identity, handle or domain already exists");
33
+ const stored = immutable(tenant);
34
+ tenants.set(tenant.id, stored);
35
+ handles.set(tenant.handle, tenant.id);
36
+ for (const domain of tenant.domains)
37
+ domains.set(domain, tenant.id);
38
+ return stored;
39
+ };
40
+ for (const tenant of options.tenants ?? []) {
41
+ Schema.decodeUnknownSync(tenantIdSchema)(tenant.id);
42
+ Schema.decodeUnknownSync(tenantIdSchema)(tenant.handle);
43
+ insert({ ...tenant, origin: checkedOrigin(tenant.origin, tenant.domains) });
44
+ }
45
+ for (const membership of options.memberships ?? []) {
46
+ if (!tenants.has(membership.tenantId))
47
+ throw new Error("Membership tenant does not exist");
48
+ retainMember(membership.identity, membership.memberId);
49
+ let entries = memberships.get(membership.tenantId);
50
+ if (entries === undefined) {
51
+ entries = new Map();
52
+ memberships.set(membership.tenantId, entries);
53
+ }
54
+ entries.set(membership.memberId, {
55
+ memberId: membership.memberId,
56
+ role: membership.role,
57
+ membershipVersion: nextRevision(),
58
+ });
59
+ }
60
+ const get = (id) => tenants.get(id) ?? null;
61
+ return {
62
+ get: (id) => Promise.resolve(get(id)),
63
+ byHandle(handle) {
64
+ const id = handles.get(handle);
65
+ return Promise.resolve(id === undefined ? null : get(id));
66
+ },
67
+ byDomain(host) {
68
+ const id = domains.get(host);
69
+ return Promise.resolve(id === undefined ? null : get(id));
70
+ },
71
+ status: (id) => Promise.resolve(get(id)?.status ?? null),
72
+ memberById(id, memberId) {
73
+ const member = memberships.get(id)?.get(memberId);
74
+ return Promise.resolve(member === undefined ? null : { ...member });
75
+ },
76
+ membershipOf(id, identity) {
77
+ const memberId = canonicalMember(identity);
78
+ return Promise.resolve(memberId === undefined
79
+ ? null
80
+ : (memberships.get(id)?.get(memberId) ?? null));
81
+ },
82
+ create(input) {
83
+ return Promise.resolve().then(() => {
84
+ const handle = Schema.decodeUnknownSync(tenantIdSchema)(input.handle);
85
+ const origin = checkedOrigin(input.origin, input.domains);
86
+ const id = handle;
87
+ const memberId = canonicalMember(input.owner) ?? createMemberId();
88
+ const tenant = {
89
+ id,
90
+ handle,
91
+ origin,
92
+ domains: [...input.domains],
93
+ owners: [memberId],
94
+ status: "active",
95
+ };
96
+ const stored = insert(tenant);
97
+ retainMember(input.owner, memberId);
98
+ memberships.set(id, new Map([
99
+ [
100
+ memberId,
101
+ {
102
+ memberId,
103
+ role: "owner",
104
+ membershipVersion: nextRevision(),
105
+ },
106
+ ],
107
+ ]));
108
+ return stored;
109
+ });
110
+ },
111
+ setStatus(id, status) {
112
+ const tenant = get(id);
113
+ if (tenant === null)
114
+ return Promise.reject(new Error("Tenant does not exist"));
115
+ if (tenant.status !== status) {
116
+ const membershipVersion = nextRevision();
117
+ for (const [memberId, membership] of memberships.get(id) ?? [])
118
+ memberships
119
+ .get(id)
120
+ ?.set(memberId, { ...membership, membershipVersion });
121
+ }
122
+ tenants.set(id, immutable({ ...tenant, status }));
123
+ return Promise.resolve();
124
+ },
125
+ delete(id) {
126
+ const tenant = get(id);
127
+ if (tenant === null)
128
+ return Promise.resolve();
129
+ nextRevision();
130
+ tenants.delete(id);
131
+ handles.delete(tenant.handle);
132
+ memberships.delete(id);
133
+ for (const domain of tenant.domains)
134
+ domains.delete(domain);
135
+ return Promise.resolve();
136
+ },
137
+ };
138
+ }
@@ -0,0 +1,7 @@
1
+ import type { ReadonlyTenantRegistry, TenantResolverAdapter } from "./contracts.js";
2
+ /** Resolve a provisioned label immediately below a configured base hostname. */
3
+ export declare function subdomain(baseDomain: string): TenantResolverAdapter<"origin">;
4
+ /** Resolve a provisioned custom domain through the registry's domain index. */
5
+ export declare function hosts(registry: ReadonlyTenantRegistry): TenantResolverAdapter<"origin">;
6
+ /** Resolve provisioned path tenants for APIs; this resolver cannot host Oyster. */
7
+ export declare function path(pattern: string): TenantResolverAdapter<"path">;
@@ -0,0 +1,64 @@
1
+ import { match, parse } from "path-to-regexp";
2
+ import * as Schema from "effect/Schema";
3
+ import { tenantIdSchema } from "../tenant.js";
4
+ /** Resolve a provisioned label immediately below a configured base hostname. */
5
+ export function subdomain(baseDomain) {
6
+ const base = new URL(`https://${baseDomain}`);
7
+ if (base.host !== baseDomain.toLowerCase() ||
8
+ base.port !== "" ||
9
+ base.pathname !== "/" ||
10
+ base.search ||
11
+ base.hash ||
12
+ base.username ||
13
+ base.password ||
14
+ base.hostname.endsWith("."))
15
+ throw new TypeError("Configure a base hostname without credentials, path, port or trailing dot");
16
+ const suffix = `.${base.hostname}`;
17
+ return {
18
+ kind: "origin",
19
+ async resolve(url, registry) {
20
+ if (!url.hostname.endsWith(suffix))
21
+ return null;
22
+ const handle = url.hostname.slice(0, -suffix.length);
23
+ const parsed = Schema.decodeUnknownOption(tenantIdSchema)(handle);
24
+ if (parsed._tag === "None")
25
+ return null;
26
+ return (await registry.byHandle(handle))?.id ?? null;
27
+ },
28
+ };
29
+ }
30
+ /** Resolve a provisioned custom domain through the registry's domain index. */
31
+ export function hosts(registry) {
32
+ return {
33
+ kind: "origin",
34
+ resolve: async (url) => (await registry.byDomain?.(url.host))?.id ?? null,
35
+ };
36
+ }
37
+ /** Resolve provisioned path tenants for APIs; this resolver cannot host Oyster. */
38
+ export function path(pattern) {
39
+ const tokens = parse(pattern).tokens;
40
+ if (!tokens.some((token) => token.type === "param" && token.name === "tenant"))
41
+ throw new TypeError("A tenant path must contain the :tenant parameter");
42
+ const route = match(pattern, { end: false });
43
+ return {
44
+ kind: "path",
45
+ async resolve(url, registry) {
46
+ let result;
47
+ try {
48
+ result = route(url.pathname);
49
+ }
50
+ catch (cause) {
51
+ if (cause instanceof URIError)
52
+ return null;
53
+ throw cause;
54
+ }
55
+ if (result === false)
56
+ return null;
57
+ const handle = result.params.tenant;
58
+ const parsed = Schema.decodeUnknownOption(tenantIdSchema)(handle);
59
+ if (parsed._tag === "None")
60
+ return null;
61
+ return (await registry.byHandle(parsed.value))?.id ?? null;
62
+ },
63
+ };
64
+ }
@@ -773,10 +773,7 @@ const revokeKeySchema = Schema.Struct({
773
773
  keyId: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256)),
774
774
  requestId: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_.:-]{1,112}$/u)),
775
775
  });
776
- const oysterGrantsArraySchema = z
777
- .array(oysterKeyVocabulary.grantSchema)
778
- .min(1)
779
- .max(64);
776
+ const oysterGrantsArraySchema = z.lazy(() => z.array(oysterKeyVocabulary.grantSchema).min(1).max(64));
780
777
  function keySummary(record) {
781
778
  return {
782
779
  keyId: record.keyId,
package/dist/workers.d.ts CHANGED
@@ -18,7 +18,7 @@ import { type BackgroundFrameState, type InvocationFacts, type InvocationFrame }
18
18
  import { type InstallationCommit, type InstanceResult, type OysterAuth, type OysterHost, type OysterJson } from "./host.js";
19
19
  import { type AppStorageResult, type AppStorageWrite, type AppStorageReset, type ResolvedAppStorage } from "@fungi.computer/agar/storage";
20
20
  import { type OysterRootDirectory } from "./root-data.js";
21
- import { type ArtifactStore } from "./release.js";
21
+ import { type ArtifactHeads, type ArtifactStore } from "./release.js";
22
22
  import type { AppApi } from "@fungi.computer/puffball";
23
23
  import type { AppDeclaration } from "@fungi.computer/puffball/app";
24
24
  import { createOysterAppSourceReceipts, createOysterAppRegistrations, createOysterArtifactsRepositoryMetadataStore } from "./app-sources.js";
@@ -64,7 +64,7 @@ export type OysterWorkerEnv = Readonly<{
64
64
  LOADER: WorkerLoader;
65
65
  }>;
66
66
  /** Store Release artifacts in an R2 bucket. */
67
- export declare function r2ArtifactStore(bucket: R2Bucket): ArtifactStore;
67
+ export declare function r2ArtifactStore(bucket: R2Bucket): ArtifactStore & ArtifactHeads;
68
68
  /** The installation registry: one SQLite-backed Durable Object per Oyster. */
69
69
  export declare class OysterRegistry extends DurableObject<OysterWorkerEnv> {
70
70
  #private;
package/dist/workers.js CHANGED
@@ -30,12 +30,14 @@ import { storageFrameMethods } from "./storage-frame.js";
30
30
  import { catalogFrameMethods, oysterAppCatalog } from "./catalog-frame.js";
31
31
  import { appStorageKeyNameSchema, appStorageWriteSchema, appStorageResetSchema, } from "@fungi.computer/agar/storage";
32
32
  import { createOysterRootData } from "./root-data.js";
33
- import { backendCache, resolveBackend } from "./release.js";
33
+ import { backendCache, resolveBackend, } from "./release.js";
34
+ import { headContentObject } from "./build/content-objects.js";
34
35
  import { ensureAppSourceTables, createOysterAppSourceReceipts, createOysterAppRegistrations, createOysterArtifactsRepositoryMetadataStore, } from "./app-sources.js";
35
36
  export { r2FileSource, ownerKeyAuth };
36
37
  /** Store Release artifacts in an R2 bucket. */
37
38
  export function r2ArtifactStore(bucket) {
38
39
  return {
40
+ head: (artifactRef) => headContentObject(bucket, artifactRef),
39
41
  async get(artifactRef) {
40
42
  const object = await bucket.get(artifactRef);
41
43
  return object === null