@fungi.computer/oyster 0.5.0 → 0.7.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 (185) hide show
  1. package/README.md +155 -63
  2. package/dist/agent-archive-projection.d.ts +8 -0
  3. package/dist/agent-archive-projection.js +49 -0
  4. package/dist/agent-schedules.d.ts +50 -0
  5. package/dist/agent-schedules.js +17 -0
  6. package/dist/agents.d.ts +35 -14
  7. package/dist/agents.js +97 -144
  8. package/dist/app-builds.d.ts +7 -2
  9. package/dist/app-builds.js +19 -2
  10. package/dist/approval-capability.d.ts +1 -1
  11. package/dist/approval-capability.js +11 -16
  12. package/dist/approval-home.d.ts +2 -1
  13. package/dist/approval-home.js +5 -3
  14. package/dist/apps/catalog.js +1 -1
  15. package/dist/apps/gate.d.ts +4 -7
  16. package/dist/apps/gate.js +14 -29
  17. package/dist/apps/index.d.ts +1 -1
  18. package/dist/apps/installation.d.ts +4 -42
  19. package/dist/apps/installation.js +7 -75
  20. package/dist/apps/operations.js +0 -10
  21. package/dist/apps/permissions.d.ts +18 -8
  22. package/dist/apps/permissions.js +7 -1
  23. package/dist/auth.js +9 -1
  24. package/dist/authorization.d.ts +307 -0
  25. package/dist/authorization.js +542 -0
  26. package/dist/boot-host-script.js +1 -1
  27. package/dist/build/build-jobs.d.ts +2 -2
  28. package/dist/build/candidate-builder.d.ts +2 -0
  29. package/dist/build/candidate-builder.js +5 -1
  30. package/dist/build/candidate-cli.js +3 -0
  31. package/dist/build/candidate-cli.mjs +67 -22
  32. package/dist/build/job-log.d.ts +23 -0
  33. package/dist/build/job-log.js +88 -0
  34. package/dist/build/local-build.d.ts +2 -0
  35. package/dist/build/local-build.js +11 -9
  36. package/dist/channels/binding.d.ts +8 -1
  37. package/dist/channels/binding.js +12 -0
  38. package/dist/channels/conversations.d.ts +16 -5
  39. package/dist/channels/visitor-channel.d.ts +53 -0
  40. package/dist/channels/visitor-channel.js +124 -0
  41. package/dist/channels/visitor-edge.d.ts +115 -0
  42. package/dist/channels/visitor-edge.js +582 -0
  43. package/dist/channels/visitor-request.d.ts +7 -0
  44. package/dist/channels/visitor-request.js +17 -0
  45. package/dist/channels/visitor-stream-slots.d.ts +2 -0
  46. package/dist/channels/visitor-stream-slots.js +33 -0
  47. package/dist/channels/visitors.d.ts +47 -0
  48. package/dist/channels/visitors.js +181 -0
  49. package/dist/cloudflare.d.ts +11 -2
  50. package/dist/cloudflare.js +27 -1
  51. package/dist/{page/computer-target.d.ts → computer-target.d.ts} +2 -0
  52. package/dist/{page/computer-target.js → computer-target.js} +3 -1
  53. package/dist/files.js +9 -8
  54. package/dist/git-admission.d.ts +3 -3
  55. package/dist/git-admission.js +4 -6
  56. package/dist/git-door.d.ts +8 -7
  57. package/dist/git-door.js +18 -17
  58. package/dist/git.d.ts +1 -1
  59. package/dist/host.d.ts +38 -42
  60. package/dist/host.js +182 -239
  61. package/dist/installation-execution.js +10 -5
  62. package/dist/installation-operations.d.ts +4 -180
  63. package/dist/installation-operations.js +1 -5
  64. package/dist/installation-store-generation.d.ts +4 -1
  65. package/dist/installation-store-generation.js +59 -6
  66. package/dist/internal/delivery.js +0 -1
  67. package/dist/internal/host-gate.d.ts +9 -6
  68. package/dist/internal/host-gate.js +19 -25
  69. package/dist/internal/invocation-timing.d.ts +16 -0
  70. package/dist/internal/invocation-timing.js +23 -0
  71. package/dist/internal/registry-installations.js +1 -0
  72. package/dist/invocation.d.ts +19 -11
  73. package/dist/invocation.js +171 -96
  74. package/dist/keys.d.ts +2 -19
  75. package/dist/keys.js +1 -37
  76. package/dist/mcp.d.ts +15 -27
  77. package/dist/mcp.js +105 -155
  78. package/dist/page/agent-browser.d.ts +15 -0
  79. package/dist/page/agent-browser.js +162 -0
  80. package/dist/page/app-permissions-port.d.ts +3 -0
  81. package/dist/page/app-permissions-port.js +43 -0
  82. package/dist/page/app-permissions.d.ts +11 -0
  83. package/dist/page/app-permissions.js +296 -0
  84. package/dist/page/capabilities.js +1 -1
  85. package/dist/page/child-selection.d.ts +27 -0
  86. package/dist/page/child-selection.js +38 -0
  87. package/dist/page/isolated-page-theme.d.ts +2 -0
  88. package/dist/page/isolated-page-theme.js +11 -0
  89. package/dist/page/mount.d.ts +2 -13
  90. package/dist/page/mount.js +8 -94
  91. package/dist/page-script.d.ts +0 -3
  92. package/dist/page-script.js +3 -4
  93. package/dist/release.d.ts +13 -0
  94. package/dist/release.js +10 -0
  95. package/dist/request-origin.d.ts +4 -0
  96. package/dist/request-origin.js +10 -0
  97. package/dist/standalone/agent-archive-owner.d.ts +42 -0
  98. package/dist/standalone/agent-archive-owner.js +116 -0
  99. package/dist/standalone/agent-archive-schedules.d.ts +6 -0
  100. package/dist/standalone/agent-archive-schedules.js +76 -0
  101. package/dist/standalone/agent-archive.d.ts +31 -0
  102. package/dist/standalone/agent-archive.js +67 -0
  103. package/dist/standalone/agent-computers.d.ts +7 -6
  104. package/dist/standalone/agent-computers.js +4 -7
  105. package/dist/standalone/agent-mail.d.ts +2 -2
  106. package/dist/standalone/agents.d.ts +157 -20
  107. package/dist/standalone/agents.js +242 -38
  108. package/dist/standalone/app-builds-binding.js +1 -1
  109. package/dist/standalone/app-set.js +2 -54
  110. package/dist/standalone/app-source.d.ts +3 -4
  111. package/dist/standalone/app-source.js +12 -9
  112. package/dist/standalone/builds.d.ts +2 -14
  113. package/dist/standalone/builds.js +15 -13
  114. package/dist/standalone/computer-fleet.d.ts +4 -4
  115. package/dist/standalone/computer-fleet.js +20 -43
  116. package/dist/standalone/computer.d.ts +4 -3
  117. package/dist/standalone/computer.js +52 -53
  118. package/dist/standalone/dashboard-approval.d.ts +10 -0
  119. package/dist/standalone/dashboard-approval.js +66 -0
  120. package/dist/standalone/machine-link.d.ts +4 -221
  121. package/dist/standalone/machine-link.js +21 -15
  122. package/dist/standalone/media.d.ts +1 -0
  123. package/dist/standalone/media.js +20 -14
  124. package/dist/standalone/owner-routes.d.ts +16 -0
  125. package/dist/standalone/owner-routes.js +21 -0
  126. package/dist/standalone/permission-resources.d.ts +5 -0
  127. package/dist/standalone/permission-resources.js +31 -0
  128. package/dist/standalone/registry.d.ts +7 -0
  129. package/dist/standalone/registry.js +3 -0
  130. package/dist/standalone/tenancy.js +3 -1
  131. package/dist/standalone/worker-routes.d.ts +19 -0
  132. package/dist/standalone/worker-routes.js +9 -0
  133. package/dist/standalone/worker.d.ts +1 -1
  134. package/dist/standalone/worker.js +27 -35
  135. package/dist/standalone/workflow-binding.d.ts +8 -3
  136. package/dist/standalone/workflow-binding.js +14 -5
  137. package/dist/standalone/workflow-git-capture.js +2 -1
  138. package/dist/standalone/workflow-host.d.ts +8 -103
  139. package/dist/standalone/workflow-host.js +1 -1
  140. package/dist/standalone/workflow-node-capture.js +2 -2
  141. package/dist/standalone/workflow-root-authority.d.ts +1 -1
  142. package/dist/standalone/workflow-root-authority.js +1 -1
  143. package/dist/standalone/workflow-schedules.d.ts +14 -5
  144. package/dist/standalone/workflow-schedules.js +11 -5
  145. package/dist/standalone/workflow-webhooks.d.ts +4 -18
  146. package/dist/standalone/workflow-webhooks.js +5 -5
  147. package/dist/standalone/workflows.d.ts +36 -28
  148. package/dist/standalone/workflows.js +6 -3
  149. package/dist/storage-frame.d.ts +6 -6
  150. package/dist/testing/capabilities.d.ts +7 -6
  151. package/dist/testing/capabilities.js +3 -6
  152. package/dist/testing/installation.d.ts +0 -1
  153. package/dist/testing/installation.js +2 -5
  154. package/dist/turnstile.d.ts +27 -0
  155. package/dist/turnstile.js +51 -0
  156. package/dist/workers-git.d.ts +12 -4
  157. package/dist/workers-git.js +58 -36
  158. package/dist/workers.d.ts +9 -1
  159. package/dist/workers.js +59 -20
  160. package/dist/workflows.d.ts +2 -0
  161. package/dist/workflows.js +1 -0
  162. package/docs/api/README.md +7 -0
  163. package/docs/api/agent-schedules.md +175 -0
  164. package/docs/api/agents.md +34 -13
  165. package/docs/api/app-storage.md +1 -1
  166. package/docs/api/apps.md +323 -225
  167. package/docs/api/authorization.md +1300 -0
  168. package/docs/api/build-contract.md +2 -2
  169. package/docs/api/build.md +40 -37
  170. package/docs/api/cloudflare.md +27 -2
  171. package/docs/api/git.md +20 -11
  172. package/docs/api/host.md +80 -199
  173. package/docs/api/index.md +1 -1
  174. package/docs/api/invocation.md +15 -11
  175. package/docs/api/keys.md +1 -98
  176. package/docs/api/mcp.md +43 -40
  177. package/docs/api/modules.md +2 -0
  178. package/docs/api/page/mount.md +16 -19
  179. package/docs/api/workers-git.md +46 -12
  180. package/docs/api/workers.md +125 -235
  181. package/docs/site/agent-quickstart.mdx +6 -2
  182. package/examples/standalone/wrangler.celld.jsonc +66 -0
  183. package/package.json +64 -21
  184. package/dist/standalone/channel-session-door.d.ts +0 -4
  185. package/dist/standalone/channel-session-door.js +0 -42
@@ -49,12 +49,10 @@ export async function executeInstallation(host, input) {
49
49
  const declaration = verified.declaration ?? emptyAppDeclaration;
50
50
  const baseline = command.baseline;
51
51
  const declaredOperations = await deriveDeclaredOperations(verified.release, declaration, host.capabilities ?? []);
52
- // A Workflow reuses the owner's approval; any capability or anonymous
53
- // method its baseline has not approved waits for the owner.
52
+ // A Workflow reuses the owner's approval; any capability its baseline
53
+ // has not approved waits for the owner.
54
54
  if (command.admission.origin === "workflow" &&
55
- (pendingCapabilities(baseline?.authority ?? { approvedGrants: [] }, declaration, declaredOperations).length > 0 ||
56
- declaredOperations.anonymousMethods.some((method) => !(baseline?.approvedAnonymousMethods ?? []).some((approved) => approved.name === method.name &&
57
- approved.digest === method.digest))))
55
+ pendingCapabilities(baseline?.authority ?? { approvedGrants: [] }, declaration, declaredOperations).length > 0)
58
56
  return refused(409, "needs_consent");
59
57
  const reduced = applyInstallationCommand(baseline, baseline === null
60
58
  ? {
@@ -77,6 +75,13 @@ export async function executeInstallation(host, input) {
77
75
  installationId: command.installationId,
78
76
  instanceId: command.instanceId,
79
77
  },
78
+ // Only a fresh owner-direct Tourtois install in the configured home
79
+ // slot receives the ordinary persisted Shell grant. App/workflow
80
+ // requests cannot opt in; selection only intersects existing grants.
81
+ builtInShell: baseline === null &&
82
+ command.admission.origin === "owner-direct" &&
83
+ verified.release.appId === "app_tourtois" &&
84
+ command.installationId === host.homeInstallationId,
80
85
  });
81
86
  if (Result.isFailure(reduced))
82
87
  return refused(409, reduced.failure.code);
@@ -60,28 +60,6 @@ declare const installationOutcomeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
60
60
  disabled: "disabled";
61
61
  deleted: "deleted";
62
62
  }>;
63
- visibility: z.ZodEnum<{
64
- private: "private";
65
- public: "public";
66
- }>;
67
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
68
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
69
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
70
- }, z.core.$strict>>>>;
71
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
72
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
73
- kind: import("zod/mini").ZodMiniLiteral<"member">;
74
- memberId: import("zod/mini").ZodMiniString<string>;
75
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
76
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
77
- agentId: import("zod/mini").ZodMiniString<string>;
78
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
79
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
80
- keyId: import("zod/mini").ZodMiniString<string>;
81
- }, z.core.$strip>], "kind">;
82
- at: z.ZodNumber;
83
- authorityVersion: z.ZodLazy<z.ZodNumber>;
84
- }, z.core.$strict>>>>;
85
63
  }, z.core.$strict>;
86
64
  creation: z.ZodEnum<{
87
65
  fresh: "fresh";
@@ -300,28 +278,6 @@ export declare const installationOperationSchema: z.ZodDiscriminatedUnion<[z.Zod
300
278
  disabled: "disabled";
301
279
  deleted: "deleted";
302
280
  }>;
303
- visibility: z.ZodEnum<{
304
- private: "private";
305
- public: "public";
306
- }>;
307
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
308
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
309
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
310
- }, z.core.$strict>>>>;
311
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
312
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
313
- kind: import("zod/mini").ZodMiniLiteral<"member">;
314
- memberId: import("zod/mini").ZodMiniString<string>;
315
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
316
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
317
- agentId: import("zod/mini").ZodMiniString<string>;
318
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
319
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
320
- keyId: import("zod/mini").ZodMiniString<string>;
321
- }, z.core.$strip>], "kind">;
322
- at: z.ZodNumber;
323
- authorityVersion: z.ZodLazy<z.ZodNumber>;
324
- }, z.core.$strict>>>>;
325
281
  }, z.core.$strict>>;
326
282
  }, z.core.$strict>, z.ZodObject<{
327
283
  state: z.ZodLiteral<"refused">;
@@ -400,8 +356,8 @@ declare const installationAdmissionSchema: z.ZodObject<{
400
356
  "create-only": "create-only";
401
357
  }>;
402
358
  origin: z.ZodEnum<{
403
- workflow: "workflow";
404
359
  "owner-direct": "owner-direct";
360
+ workflow: "workflow";
405
361
  }>;
406
362
  }, z.core.$strict>;
407
363
  export type InstallationAdmission = z.output<typeof installationAdmissionSchema>;
@@ -439,8 +395,8 @@ export declare const retainedInstallationCommandSchema: z.ZodObject<{
439
395
  "create-only": "create-only";
440
396
  }>;
441
397
  origin: z.ZodEnum<{
442
- workflow: "workflow";
443
398
  "owner-direct": "owner-direct";
399
+ workflow: "workflow";
444
400
  }>;
445
401
  }, z.core.$strict>;
446
402
  scope: z.ZodObject<{
@@ -503,28 +459,6 @@ export declare const retainedInstallationCommandSchema: z.ZodObject<{
503
459
  disabled: "disabled";
504
460
  deleted: "deleted";
505
461
  }>;
506
- visibility: z.ZodEnum<{
507
- private: "private";
508
- public: "public";
509
- }>;
510
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
511
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
512
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
513
- }, z.core.$strict>>>>;
514
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
515
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
516
- kind: import("zod/mini").ZodMiniLiteral<"member">;
517
- memberId: import("zod/mini").ZodMiniString<string>;
518
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
519
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
520
- agentId: import("zod/mini").ZodMiniString<string>;
521
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
522
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
523
- keyId: import("zod/mini").ZodMiniString<string>;
524
- }, z.core.$strip>], "kind">;
525
- at: z.ZodNumber;
526
- authorityVersion: z.ZodLazy<z.ZodNumber>;
527
- }, z.core.$strict>>>>;
528
462
  }, z.core.$strict>>;
529
463
  acceptedAt: z.ZodNumber;
530
464
  creation: z.ZodEnum<{
@@ -586,28 +520,6 @@ export declare const retainedInstallationCommandSchema: z.ZodObject<{
586
520
  disabled: "disabled";
587
521
  deleted: "deleted";
588
522
  }>;
589
- visibility: z.ZodEnum<{
590
- private: "private";
591
- public: "public";
592
- }>;
593
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
594
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
595
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
596
- }, z.core.$strict>>>>;
597
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
598
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
599
- kind: import("zod/mini").ZodMiniLiteral<"member">;
600
- memberId: import("zod/mini").ZodMiniString<string>;
601
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
602
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
603
- agentId: import("zod/mini").ZodMiniString<string>;
604
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
605
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
606
- keyId: import("zod/mini").ZodMiniString<string>;
607
- }, z.core.$strip>], "kind">;
608
- at: z.ZodNumber;
609
- authorityVersion: z.ZodLazy<z.ZodNumber>;
610
- }, z.core.$strict>>>>;
611
523
  }, z.core.$strict>;
612
524
  hasBackend: z.ZodBoolean;
613
525
  prepared: z.ZodBoolean;
@@ -731,8 +643,8 @@ declare const installationOperationRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
731
643
  "create-only": "create-only";
732
644
  }>;
733
645
  origin: z.ZodEnum<{
734
- workflow: "workflow";
735
646
  "owner-direct": "owner-direct";
647
+ workflow: "workflow";
736
648
  }>;
737
649
  }, z.core.$strict>;
738
650
  }, z.core.$strict>, z.ZodObject<{
@@ -810,28 +722,6 @@ declare const installationOperationRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
810
722
  disabled: "disabled";
811
723
  deleted: "deleted";
812
724
  }>;
813
- visibility: z.ZodEnum<{
814
- private: "private";
815
- public: "public";
816
- }>;
817
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
818
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
819
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
820
- }, z.core.$strict>>>>;
821
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
822
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
823
- kind: import("zod/mini").ZodMiniLiteral<"member">;
824
- memberId: import("zod/mini").ZodMiniString<string>;
825
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
826
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
827
- agentId: import("zod/mini").ZodMiniString<string>;
828
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
829
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
830
- keyId: import("zod/mini").ZodMiniString<string>;
831
- }, z.core.$strip>], "kind">;
832
- at: z.ZodNumber;
833
- authorityVersion: z.ZodLazy<z.ZodNumber>;
834
- }, z.core.$strict>>>>;
835
725
  }, z.core.$strict>;
836
726
  hasBackend: z.ZodBoolean;
837
727
  }, z.core.$strict>, z.ZodObject<{
@@ -1052,28 +942,6 @@ declare const installationOperationReplySchema: z.ZodDiscriminatedUnion<[z.ZodOb
1052
942
  disabled: "disabled";
1053
943
  deleted: "deleted";
1054
944
  }>;
1055
- visibility: z.ZodEnum<{
1056
- private: "private";
1057
- public: "public";
1058
- }>;
1059
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
1060
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
1061
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
1062
- }, z.core.$strict>>>>;
1063
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
1064
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
1065
- kind: import("zod/mini").ZodMiniLiteral<"member">;
1066
- memberId: import("zod/mini").ZodMiniString<string>;
1067
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1068
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
1069
- agentId: import("zod/mini").ZodMiniString<string>;
1070
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1071
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
1072
- keyId: import("zod/mini").ZodMiniString<string>;
1073
- }, z.core.$strip>], "kind">;
1074
- at: z.ZodNumber;
1075
- authorityVersion: z.ZodLazy<z.ZodNumber>;
1076
- }, z.core.$strict>>>>;
1077
945
  }, z.core.$strict>>;
1078
946
  }, z.core.$strict>, z.ZodObject<{
1079
947
  state: z.ZodLiteral<"refused">;
@@ -1154,8 +1022,8 @@ declare const installationOperationReplySchema: z.ZodDiscriminatedUnion<[z.ZodOb
1154
1022
  "create-only": "create-only";
1155
1023
  }>;
1156
1024
  origin: z.ZodEnum<{
1157
- workflow: "workflow";
1158
1025
  "owner-direct": "owner-direct";
1026
+ workflow: "workflow";
1159
1027
  }>;
1160
1028
  }, z.core.$strict>;
1161
1029
  scope: z.ZodObject<{
@@ -1218,28 +1086,6 @@ declare const installationOperationReplySchema: z.ZodDiscriminatedUnion<[z.ZodOb
1218
1086
  disabled: "disabled";
1219
1087
  deleted: "deleted";
1220
1088
  }>;
1221
- visibility: z.ZodEnum<{
1222
- private: "private";
1223
- public: "public";
1224
- }>;
1225
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
1226
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
1227
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
1228
- }, z.core.$strict>>>>;
1229
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
1230
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
1231
- kind: import("zod/mini").ZodMiniLiteral<"member">;
1232
- memberId: import("zod/mini").ZodMiniString<string>;
1233
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1234
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
1235
- agentId: import("zod/mini").ZodMiniString<string>;
1236
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1237
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
1238
- keyId: import("zod/mini").ZodMiniString<string>;
1239
- }, z.core.$strip>], "kind">;
1240
- at: z.ZodNumber;
1241
- authorityVersion: z.ZodLazy<z.ZodNumber>;
1242
- }, z.core.$strict>>>>;
1243
1089
  }, z.core.$strict>>;
1244
1090
  acceptedAt: z.ZodNumber;
1245
1091
  creation: z.ZodEnum<{
@@ -1301,28 +1147,6 @@ declare const installationOperationReplySchema: z.ZodDiscriminatedUnion<[z.ZodOb
1301
1147
  disabled: "disabled";
1302
1148
  deleted: "deleted";
1303
1149
  }>;
1304
- visibility: z.ZodEnum<{
1305
- private: "private";
1306
- public: "public";
1307
- }>;
1308
- approvedAnonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
1309
- name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
1310
- digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
1311
- }, z.core.$strict>>>>;
1312
- anonymousApproval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
1313
- by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
1314
- kind: import("zod/mini").ZodMiniLiteral<"member">;
1315
- memberId: import("zod/mini").ZodMiniString<string>;
1316
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1317
- kind: import("zod/mini").ZodMiniLiteral<"agent">;
1318
- agentId: import("zod/mini").ZodMiniString<string>;
1319
- }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
1320
- kind: import("zod/mini").ZodMiniLiteral<"team-key">;
1321
- keyId: import("zod/mini").ZodMiniString<string>;
1322
- }, z.core.$strip>], "kind">;
1323
- at: z.ZodNumber;
1324
- authorityVersion: z.ZodLazy<z.ZodNumber>;
1325
- }, z.core.$strict>>>>;
1326
1150
  }, z.core.$strict>;
1327
1151
  hasBackend: z.ZodBoolean;
1328
1152
  prepared: z.ZodBoolean;
@@ -296,15 +296,11 @@ const version = (record) => record?.authority.authorityVersion ?? 0;
296
296
  /** Whether a plan only reuses, or narrows, the approval its baseline holds. */
297
297
  function reusesApproval(baseline, next) {
298
298
  const grants = baseline?.authority.approvedGrants ?? [];
299
- const methods = baseline?.approvedAnonymousMethods ?? [];
300
299
  return (next.authority.approvedGrants.every((grant) => grants.some((held) => held.capability === grant.capability &&
301
300
  same(held.resources, grant.resources) &&
302
301
  grant.operations.every((operation) => held.operations.includes(operation)))) &&
303
302
  (next.authority.approval === null ||
304
- same(next.authority.approval, baseline?.authority.approval ?? null)) &&
305
- next.approvedAnonymousMethods.every((method) => methods.some((held) => held.name === method.name && held.digest === method.digest)) &&
306
- (next.anonymousApproval === null ||
307
- same(next.anonymousApproval, baseline?.anonymousApproval ?? null)));
303
+ same(next.authority.approval, baseline?.authority.approval ?? null)));
308
304
  }
309
305
  /**
310
306
  * One registry-owned command journal joined to maintained Watchdog transactions.
@@ -1,3 +1,6 @@
1
1
  import type { WatchdogSqliteOwner } from "@fungi.computer/watchdog";
2
2
  /** Own one persisted store incarnation, independent of installation row revisions. */
3
- export declare function createInstallationStoreGeneration(sql: WatchdogSqliteOwner["sql"]): () => string;
3
+ export declare function createInstallationStoreGeneration(owner: WatchdogSqliteOwner): {
4
+ generation: () => string;
5
+ resetAt: () => number | null;
6
+ };
@@ -1,16 +1,69 @@
1
1
  import * as Schema from "effect/Schema";
2
2
  import { defineIdFamily } from "@fungi.computer/cairn/id";
3
+ import { installationsFromOlderOyster } from "./older-oyster-store.js";
3
4
  const installationStoreIds = defineIdFamily({
4
5
  family: "installation-store",
5
6
  version: 1,
6
7
  kinds: { generation: { prefix: "store" } },
7
8
  });
8
9
  const generationRow = Schema.decodeUnknownSync(Schema.Struct({ generation: Schema.NonEmptyString }));
10
+ const resetRow = Schema.decodeUnknownSync(Schema.Struct({ reset_at: Schema.NullOr(Schema.Int) }));
11
+ const columnRow = Schema.decodeUnknownSync(Schema.Struct({ name: Schema.String }));
12
+ const countRow = Schema.decodeUnknownSync(Schema.Struct({ count: Schema.Int }));
13
+ /** Recognize only the retired producer's keys, never general decode failures. */
14
+ function preOwnerOnlyInstallations(sql) {
15
+ if (sql
16
+ .exec("SELECT 1 FROM sqlite_master WHERE type='table' AND name='installations'")
17
+ .toArray().length === 0)
18
+ return false;
19
+ // Missing authority belongs to the existing pre-0.3 refusal, not this reset.
20
+ if (installationsFromOlderOyster(sql))
21
+ return false;
22
+ return (sql
23
+ .exec(`SELECT 1 FROM installations WHERE json_valid(record) AND (
24
+ json_type(record, '$.visibility') IS NOT NULL OR
25
+ json_type(record, '$.approvedAnonymousMethods') IS NOT NULL OR
26
+ json_type(record, '$.anonymousApproval') IS NOT NULL
27
+ ) LIMIT 1`)
28
+ .toArray().length > 0);
29
+ }
9
30
  /** Own one persisted store incarnation, independent of installation row revisions. */
10
- export function createInstallationStoreGeneration(sql) {
11
- sql.exec("CREATE TABLE IF NOT EXISTS installation_store (id INTEGER PRIMARY KEY CHECK (id=1), generation TEXT NOT NULL) STRICT");
12
- sql.exec("INSERT OR IGNORE INTO installation_store (id,generation) VALUES(1,?)", installationStoreIds.generation.generate());
13
- return () => generationRow(sql
14
- .exec("SELECT generation FROM installation_store WHERE id=1")
15
- .toArray()[0]).generation;
31
+ export function createInstallationStoreGeneration(owner) {
32
+ const { sql } = owner;
33
+ const needsReset = preOwnerOnlyInstallations(sql);
34
+ const resetAt = () => resetRow(sql
35
+ .exec("SELECT reset_at FROM installation_store WHERE id=1")
36
+ .toArray()[0]).reset_at;
37
+ owner.transactionSync(() => {
38
+ sql.exec("CREATE TABLE IF NOT EXISTS installation_store (id INTEGER PRIMARY KEY CHECK (id=1), generation TEXT NOT NULL, reset_at INTEGER, reset_rows INTEGER) STRICT");
39
+ // Enroll the existing incarnation singleton in its current audit shape.
40
+ const columns = sql
41
+ .exec("PRAGMA table_info(installation_store)")
42
+ .toArray()
43
+ .map((row) => columnRow(row));
44
+ if (!columns.some(({ name }) => name === "reset_at"))
45
+ sql.exec("ALTER TABLE installation_store ADD COLUMN reset_at INTEGER");
46
+ if (!columns.some(({ name }) => name === "reset_rows"))
47
+ sql.exec("ALTER TABLE installation_store ADD COLUMN reset_rows INTEGER");
48
+ sql.exec("INSERT OR IGNORE INTO installation_store (id,generation) VALUES(1,?)", installationStoreIds.generation.generate());
49
+ if (!needsReset || resetAt() !== null || !preOwnerOnlyInstallations(sql))
50
+ return;
51
+ const rows = countRow(sql.exec("SELECT COUNT(*) AS count FROM installations").toArray()[0]).count;
52
+ // any row keyed by an installationId that is read as authority must be
53
+ // cleared in the same transaction. Other owners and Watchdog job identities
54
+ // remain intact; their existing missing-command handling settles orphan work.
55
+ sql.exec("DELETE FROM installations");
56
+ if (sql
57
+ .exec("SELECT 1 FROM sqlite_master WHERE type='table' AND name='installation_commands'")
58
+ .toArray().length > 0)
59
+ sql.exec("DELETE FROM installation_commands");
60
+ sql.exec("UPDATE installation_store SET generation=? WHERE id=1", installationStoreIds.generation.generate());
61
+ sql.exec("UPDATE installation_store SET reset_at=?, reset_rows=? WHERE id=1", Date.now(), rows);
62
+ });
63
+ return {
64
+ generation: () => generationRow(sql
65
+ .exec("SELECT generation FROM installation_store WHERE id=1")
66
+ .toArray()[0]).generation,
67
+ resetAt,
68
+ };
16
69
  }
@@ -92,7 +92,6 @@ export async function deliverBackground(host, raw) {
92
92
  case "not_declared":
93
93
  case "approval_required":
94
94
  case "invalid_input":
95
- case "visitor_read_only":
96
95
  return { kind: "refused", code: "denied" };
97
96
  }
98
97
  }
@@ -1,14 +1,17 @@
1
1
  /** Release verification and gate facts shared by the HTTP host and its delivery engines. */
2
+ import type { TenantPrincipal } from "../tenant.js";
2
3
  import type { Release } from "@fungi.computer/puffball";
3
4
  import type { GateFacts } from "../apps/gate.js";
4
5
  import type { Installation } from "../apps/installation.js";
5
- import type { OysterHost, OysterPrincipal } from "../host.js";
6
+ import type { OysterHost } from "../host.js";
6
7
  import { type ArtifactStore, type VerifiedRelease } from "../release.js";
7
8
  /**
8
- * Verify each Release once per process: a failed read is not cached, so the
9
- * next request reads it again. Installation verified every asset; serving
10
- * verifies each on read.
9
+ * Verify each Release once per owner (an isolate's HTTP host, or the
10
+ * Registry): a failed read is not cached, so the next request reads it again.
11
+ * Installation verified every asset; serving verifies each on read. A Release
12
+ * is content-addressed and immutable, so the key is its ID and root digest and
13
+ * a hit never goes stale; the bound only forgets the oldest-verified Releases.
11
14
  */
12
- export declare function releaseCache(artifacts: ArtifactStore): (release: Release) => Promise<VerifiedRelease>;
15
+ export declare function releaseCache(artifacts: ArtifactStore, limit?: number): (release: Release) => Promise<VerifiedRelease>;
13
16
  /** The gate facts one principal presents to one installation. */
14
- export declare function hostGateFacts(host: OysterHost, installation: Installation, release: VerifiedRelease, principal: OysterPrincipal): Promise<GateFacts>;
17
+ export declare function hostGateFacts(host: OysterHost, installation: Installation, release: VerifiedRelease, principal: TenantPrincipal): Promise<GateFacts>;
@@ -1,53 +1,47 @@
1
1
  import { emptyAppDeclaration } from "@fungi.computer/puffball/app";
2
2
  import { deriveDeclaredOperations } from "../apps/operations.js";
3
- import { keyAppAccess } from "../keys.js";
3
+ import { appToolAccess, authorityOf, hostAuthorityPorts, } from "../authorization.js";
4
4
  import { defaultAssetPolicy, verifyRelease, } from "../release.js";
5
+ /** Verified Releases one cache keeps; the least recently added leaves first. */
6
+ const releaseCacheLimit = 256;
5
7
  /**
6
- * Verify each Release once per process: a failed read is not cached, so the
7
- * next request reads it again. Installation verified every asset; serving
8
- * verifies each on read.
8
+ * Verify each Release once per owner (an isolate's HTTP host, or the
9
+ * Registry): a failed read is not cached, so the next request reads it again.
10
+ * Installation verified every asset; serving verifies each on read. A Release
11
+ * is content-addressed and immutable, so the key is its ID and root digest and
12
+ * a hit never goes stale; the bound only forgets the oldest-verified Releases.
9
13
  */
10
- export function releaseCache(artifacts) {
14
+ export function releaseCache(artifacts, limit = releaseCacheLimit) {
11
15
  const verified = new Map();
12
16
  return (release) => {
13
17
  const key = `${release.releaseId}:${release.artifact.artifactDigest}`;
14
18
  let entry = verified.get(key);
15
19
  if (entry === undefined) {
16
- // A failed read is not cached: the next request reads the Release again.
17
- // Installation verified every asset; serving verifies each on read.
18
- entry = verifyRelease(artifacts, release, defaultAssetPolicy, false).then((value) => value, (cause) => {
20
+ entry = verifyRelease(artifacts, release, defaultAssetPolicy, false).catch((cause) => {
19
21
  verified.delete(key);
20
22
  throw cause;
21
23
  });
22
24
  verified.set(key, entry);
25
+ for (const oldest of verified.keys()) {
26
+ if (verified.size <= limit)
27
+ break;
28
+ verified.delete(oldest);
29
+ }
23
30
  }
24
31
  return entry;
25
32
  };
26
33
  }
27
- /**
28
- * Only Agents and keys hold tool policy; members and visitors never ask. An
29
- * Agent keeps its one blanket policy; a key's access is its own grants for
30
- * this one installation -- `null` when its live key is unknown, revoked,
31
- * expired or suspended, or simply does not reach this installation, which
32
- * then refuses `not_approved`, the same as an Agent with no approval.
33
- */
34
- async function hostToolPolicy(host, actor, installationId) {
35
- if (actor.kind === "agent")
36
- return (await host.appToolPolicy?.(actor)) ?? null;
37
- if (actor.kind !== "team-key")
38
- return null;
39
- const key = (await host.keys?.live(actor.keyId)) ?? null;
40
- return key === null ? null : keyAppAccess(key, installationId);
41
- }
42
34
  /** The gate facts one principal presents to one installation. */
43
35
  export async function hostGateFacts(host, installation, release, principal) {
44
36
  const { actor } = principal;
45
37
  const declaration = release.declaration ?? emptyAppDeclaration;
46
- const toolPolicy = await hostToolPolicy(host, actor, installation.installationId);
38
+ // Only Agents and keys hold tool policy (`authorization.ts`); `null`
39
+ // refuses `not_approved`, the same as an Agent with no approval.
40
+ const ports = hostAuthorityPorts(host);
41
+ const toolPolicy = await appToolAccess(await authorityOf(principal, ports), installation.installationId, ports);
47
42
  return {
48
43
  installation: {
49
44
  status: installation.status,
50
- visibility: installation.visibility,
51
45
  instanceId: installation.instanceId,
52
46
  authority: installation.authority,
53
47
  artifactDigest: installation.release.artifact.artifactDigest,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Name where a slow App invocation waited, as the Instance saw it: verifying
3
+ * its backend, waiting for the frame permit, running the guest, and the guest's
4
+ * binding packets inside that run. Durable Object wall time otherwise hides
5
+ * which of these a caller's seconds went to.
6
+ */
7
+ export declare function reportSlowInvocation(name: string, host: Readonly<{
8
+ bindingWaits: {
9
+ count: number;
10
+ ms: number;
11
+ };
12
+ }>, at: Readonly<{
13
+ entered: number;
14
+ verified: number;
15
+ admitted: number;
16
+ }>, now?: () => number): void;
@@ -0,0 +1,23 @@
1
+ /** Stage timing for slow App invocations, logged by the Instance that ran them. */
2
+ /** Invocations slower than this log their stages; faster ones log nothing. */
3
+ const slowInvocationMs = 200;
4
+ /**
5
+ * Name where a slow App invocation waited, as the Instance saw it: verifying
6
+ * its backend, waiting for the frame permit, running the guest, and the guest's
7
+ * binding packets inside that run. Durable Object wall time otherwise hides
8
+ * which of these a caller's seconds went to.
9
+ */
10
+ export function reportSlowInvocation(name, host, at, now = Date.now) {
11
+ const finished = now();
12
+ if (finished - at.entered < slowInvocationMs)
13
+ return;
14
+ console.log("Slow App invocation", {
15
+ name,
16
+ totalMs: finished - at.entered,
17
+ verifyMs: at.verified - at.entered,
18
+ permitMs: at.admitted - at.verified,
19
+ runMs: finished - at.admitted,
20
+ bindingCalls: host.bindingWaits.count,
21
+ bindingMs: host.bindingWaits.ms,
22
+ });
23
+ }
@@ -5,6 +5,7 @@ export function registryInstallations(env, scope) {
5
5
  return {
6
6
  operations: installationOperationsPort((request) => registry().installationOperation(request), { tenantId: scope.tenantId, origin: scope.origin }),
7
7
  generation: async () => registry().generation(),
8
+ resetAt: async () => registry().installationResetAt(),
8
9
  list: async () => registry().list(),
9
10
  get: async (id) => registry().get(id),
10
11
  compareAndPut: async (installation, expectedAuthorityVersion, expectedGeneration) => await registry().compareAndPut(installation, expectedAuthorityVersion, expectedGeneration, scope.tenantId),
@@ -1,4 +1,5 @@
1
- import type { OysterHost, OysterPrincipal } from "./host.js";
1
+ import type { TenantPrincipal } from "./tenant.js";
2
+ import type { OysterHost } from "./host.js";
2
3
  import type { VerifiedRelease } from "./release.js";
3
4
  import type { Installation } from "./apps/installation.js";
4
5
  import { type InvocationGrants } from "./apps/gate.js";
@@ -191,9 +192,9 @@ export type BackgroundFrameState = {
191
192
  export declare function assertBackgroundBinding(frame: InvocationFrame<BackgroundFrameState>, binding: AppBackendBindingName): void;
192
193
  /** Consume this frame's one origin check before awaiting verification, then retain only its decision. */
193
194
  export declare function admitBackgroundFrame(key: CryptoKey, frame: InvocationFrame<BackgroundFrameState>, raw: unknown): Promise<ClaimedJobAdmission>;
194
- /** The host's native guest-abort and authority-close hooks. */
195
+ /** The host's native guest-abort and frame-authority-close hooks. */
195
196
  export type InvocationGatePorts<Host> = Readonly<{
196
- /** Stop the guest when the captured invocation's authority closes. */
197
+ /** Stop the shared guest at cohort drain or revocation, before the last close. */
197
198
  abortGuest: () => Promise<void>;
198
199
  /** Release the host resources belonging to this completed or revoked frame. */
199
200
  close: (frame: InvocationFrame<Host>) => Promise<void>;
@@ -202,10 +203,10 @@ export type InvocationGatePorts<Host> = Readonly<{
202
203
  }>;
203
204
  /** One invocation owner shared by Hub shards and standalone Instances. */
204
205
  export type InvocationGate<Host> = Readonly<{
205
- /** Run work within one immutable frame and close its authority afterward. */
206
+ /** Run one immutable frame; verified foreground reads may share until drain. */
206
207
  run: <A>(facts: InvocationFacts, host: Host, work: (frame: InvocationFrame<Host>) => Promise<A>) => Promise<A>;
207
- /** Resolve the sole admitted frame, refusing outside an active invocation. */
208
- active: () => InvocationFrame<Host>;
208
+ /** Resolve one live frame by its id, refusing a closed or unknown frame. */
209
+ active: (frameId: string) => InvocationFrame<Host>;
209
210
  /** Close live authority, optionally restricted to frames of a selected run. */
210
211
  revoke: (reason?: Error, target?: Readonly<{
211
212
  runId: string;
@@ -215,7 +216,15 @@ export type InvocationGate<Host> = Readonly<{
215
216
  }>;
216
217
  /** Decode only identities minted from the invocation-frame ID family. */
217
218
  export declare const invocationFrameIdSchema: Schema.String;
218
- /** Serialize authority, preempt replay only for verified writes, and close each guest before admission. */
219
+ /**
220
+ * One Instance shares up to eight verified foreground reads; all other work
221
+ * runs alone in first-come order. Every finish fences its frame; the last live
222
+ * frame stops the native guest before closing authority and releasing admission.
223
+ * Binding checks alone cannot stop a timer mutating the facet's own SQLite.
224
+ * Revocation, expiry and a verified write preempting replay stop every live frame.
225
+ * Arrivals wait for a stopping guest. Once the opening deadline passes, new
226
+ * reads queue exclusively so the current cohort cannot be prolonged forever.
227
+ */
219
228
  export declare function createInvocationGate<Host>(ports: InvocationGatePorts<Host>): InvocationGate<Host>;
220
229
  /** Verified selection, artifact and binding grants before caller attribution. */
221
230
  export type InvocationAuthority = Omit<InvocationFacts, "subject" | "deadlineAt">;
@@ -226,11 +235,10 @@ export type InvocationDeadline = Readonly<{
226
235
  }>;
227
236
  /**
228
237
  * Project an admitted principal into App attribution; only the host chooses
229
- * the fixed Computer context. The App caller grammar has no visitor actor, so
230
- * the anonymous public reader is attributed as the reserved `visitor` key
231
- * without a Computer. Host admission reads the principal, never this projection.
238
+ * the fixed Computer context. Host admission reads the principal, never this
239
+ * projection.
232
240
  */
233
- export declare function invocationCallerContext(principal: OysterPrincipal, computerId: string | null): AppMethodCallContext;
241
+ export declare function invocationCallerContext(principal: TenantPrincipal, computerId: string | null): AppMethodCallContext;
234
242
  /** Shared host-held caller/Workflow fact builders, never guest argument decoders. */
235
243
  export declare const invocationFacts: {
236
244
  /** Combine host-admitted caller facts with the invocation and grant deadlines. */