@cat-factory/gatekeeper-worker 0.5.0 → 0.6.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 (73) hide show
  1. package/README.md +43 -2
  2. package/dist/arguments.d.ts +18 -0
  3. package/dist/arguments.d.ts.map +1 -0
  4. package/dist/arguments.js +75 -0
  5. package/dist/arguments.js.map +1 -0
  6. package/dist/capability.d.ts +10 -0
  7. package/dist/capability.d.ts.map +1 -1
  8. package/dist/capability.js +39 -1
  9. package/dist/capability.js.map +1 -1
  10. package/dist/env.d.ts +10 -0
  11. package/dist/env.d.ts.map +1 -1
  12. package/dist/env.js +12 -0
  13. package/dist/env.js.map +1 -1
  14. package/dist/errors.d.ts +20 -1
  15. package/dist/errors.d.ts.map +1 -1
  16. package/dist/errors.js +11 -0
  17. package/dist/errors.js.map +1 -1
  18. package/dist/gatekeeper.d.ts +31 -1
  19. package/dist/gatekeeper.d.ts.map +1 -1
  20. package/dist/gatekeeper.js +38 -8
  21. package/dist/gatekeeper.js.map +1 -1
  22. package/dist/index.d.ts +8 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +5 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/os/discoverability.d.ts +13 -1
  27. package/dist/os/discoverability.d.ts.map +1 -1
  28. package/dist/os/discoverability.js +23 -6
  29. package/dist/os/discoverability.js.map +1 -1
  30. package/dist/os/exports.d.ts +27 -0
  31. package/dist/os/exports.d.ts.map +1 -1
  32. package/dist/os/exports.js +25 -0
  33. package/dist/os/exports.js.map +1 -1
  34. package/dist/os/hook-controller.d.ts +14 -0
  35. package/dist/os/hook-controller.d.ts.map +1 -0
  36. package/dist/os/hook-controller.js +53 -0
  37. package/dist/os/hook-controller.js.map +1 -0
  38. package/dist/os/hooks.d.ts +200 -0
  39. package/dist/os/hooks.d.ts.map +1 -0
  40. package/dist/os/hooks.js +253 -0
  41. package/dist/os/hooks.js.map +1 -0
  42. package/dist/os/protocol.d.ts +43 -0
  43. package/dist/os/protocol.d.ts.map +1 -1
  44. package/dist/os/queue.d.ts +9 -0
  45. package/dist/os/queue.d.ts.map +1 -1
  46. package/dist/os/queue.js +44 -1
  47. package/dist/os/queue.js.map +1 -1
  48. package/dist/os/resource-core.d.ts +25 -10
  49. package/dist/os/resource-core.d.ts.map +1 -1
  50. package/dist/os/resource-core.js +31 -14
  51. package/dist/os/resource-core.js.map +1 -1
  52. package/dist/os/resource.d.ts.map +1 -1
  53. package/dist/os/resource.js +7 -1
  54. package/dist/os/resource.js.map +1 -1
  55. package/dist/os/session-types.d.ts.map +1 -1
  56. package/dist/os/session-types.js +28 -0
  57. package/dist/os/session-types.js.map +1 -1
  58. package/dist/os/sharing.d.ts +35 -0
  59. package/dist/os/sharing.d.ts.map +1 -0
  60. package/dist/os/sharing.js +135 -0
  61. package/dist/os/sharing.js.map +1 -0
  62. package/dist/os/vendor.d.ts +1 -1
  63. package/dist/os/vendor.d.ts.map +1 -1
  64. package/dist/os/vendor.js +8 -1
  65. package/dist/os/vendor.js.map +1 -1
  66. package/dist/state.d.ts +80 -1
  67. package/dist/state.d.ts.map +1 -1
  68. package/dist/state.js +234 -6
  69. package/dist/state.js.map +1 -1
  70. package/dist/worker.d.ts.map +1 -1
  71. package/dist/worker.js +4 -1
  72. package/dist/worker.js.map +1 -1
  73. package/package.json +3 -3
package/README.md CHANGED
@@ -123,6 +123,26 @@ version has to be the consumer's.
123
123
  caller's own key.
124
124
  - **Run lifecycle without polling.** `run.started` / `run.completed` / `run.failed` land as a
125
125
  `runs_watched()` projection, and a terminal event settles that run's open cards.
126
+ - **Hooks, so the workspace is pushed rather than asked.** A session binds a callback through the
127
+ workspace's own `bindHook`, the workspace enables it when it is ready to, and each card or run
128
+ transition is then pushed: a fresh callback per delivery, authorized as the observation it is.
129
+ What a hook pushes is exactly what `approvals_list()` and `runs_watched()` answer, which stay the
130
+ truth: a delivery a hook missed is still readable there, and `hooks_bound()` reports the miss
131
+ rather than leaving it to be inferred from a quiet inbox. The fan-out runs BEHIND the delivery's
132
+ acknowledgement and each push is bounded by its own deadline, so a workspace that hangs costs a
133
+ notification and never the platform's retry budget.
134
+ - **Sharing that is verified, not assumed.** A workspace user shared onto a bound resource is
135
+ admitted only when their OWN account's tier reaches everything the resource's tier reaches, and
136
+ masks no more; a tier that can read captured agent text is never shareable at all. The observer
137
+ has to hold an account THIS deployment minted, checked before any tier is resolved: an unknown id
138
+ would otherwise resolve to the auto-provisioned tier, which is the tier every account here holds,
139
+ so a viewer from another vendor entirely measured up as identical to the owner. Anything the
140
+ Gatekeeper cannot answer (an observer with no verifier, an account it never minted) is a refusal
141
+ that says which it is.
142
+ - **Arguments checked against what each operation declares.** An argument no operation reads used
143
+ to be dropped on the way through, so a filter nobody applied came back as an answer shaped like a
144
+ filtered one. It is now a refusal naming what the operation does take, made before a key is
145
+ minted or an approval is spent.
126
146
  - **Self-enrolment and offboarding.** The endpoint registers itself under a caller-chosen webhook
127
147
  id, hourly and idempotently. `POST /admin/retire?actorId=…` revokes every key minted for one
128
148
  person, upstream first and then here.
@@ -182,9 +202,14 @@ workspace that finds either missing does not get an error anyone monitors; it ne
182
202
  installing. So a green response carries the answer beside `ok`:
183
203
 
184
204
  ```json
185
- { "ok": true, "os": { "discoverable": true, "blockers": [] } }
205
+ { "ok": true, "os": { "discoverable": true, "blockers": [], "limitations": [] } }
186
206
  ```
187
207
 
208
+ `limitations` is the same report for what does NOT stop an install. `CatFactoryHookController` is
209
+ reached only when a session binds a hook, so a deployment missing it installs, serves and answers
210
+ exactly as before and refuses `approvals_subscribe()`; calling that a blocker would turn a working
211
+ deployment red, and omitting it would leave the gap to be discovered from an agent's failed call.
212
+
188
213
  It is REPORTED, never folded into the status, because a Gatekeeper serving `/rpc` and nothing else
189
214
  is a supported deployment: this package promises that door to consumers that are not a Cloudflare
190
215
  OS, and turning their liveness red on a version bump would be this route answering a question
@@ -237,7 +262,7 @@ path that matches nothing is not an error, because result shapes legitimately va
237
262
  `connect({ actorId, label? })` on the `/rpc` session resolves the actor's tier and returns the
238
263
  capability. `actorId` is the OS's own authenticated identity for the person, and it is the ONLY
239
264
  claim the Gatekeeper trusts: nothing the caller sends picks a tier. Beyond the granted operation
240
- methods, every capability carries seven reserved methods:
265
+ methods, every capability carries ten reserved methods:
241
266
 
242
267
  - `tier()`: who the caller is acting as (actor, tier name, description, key scope).
243
268
  - `bindings()`: the granted operations, each with its scope floor, consequence (cautious default
@@ -251,6 +276,22 @@ methods, every capability carries seven reserved methods:
251
276
  - `approvals_list()`, `approvals_inspect(cardId)`, `approvals_answer(cardId, input)`: the
252
277
  approval inbox; see the template README for the flow and the three answer outcomes.
253
278
  - `runs_watched()`: the run-lifecycle projection built from the `run.*` webhook events.
279
+ - `approvals_subscribe(callback)`, `runs_subscribe(callback)`: bind a hook, so the two projections
280
+ above are PUSHED. The callback needs one method (`onApprovalCard(card)` / `onRunEvent(state)`),
281
+ and a card is pushed on every transition it makes, settlement by a terminal run event included.
282
+ Both refuse on the `/rpc` door, which brings no approval queue to register a hook with and
283
+ nothing to authorize a delivery against; the refusal names the two reads that answer the same
284
+ question. A workspace that does not take the binding (its queue serves no hooks, or a person
285
+ declined) is a `hook_bind_refused` carrying the cause verbatim, because those two need opposite
286
+ fixes and nothing at this seam can tell them apart.
287
+ - `hooks_bound()`: what this account has enabled, with what each hook has been pushed
288
+ (`deliveries`), what it could not be pushed (`missed`), what the workspace refused (`failures`)
289
+ and whether it is still `live`. A hook goes quiet when the durable object is evicted between
290
+ deliveries, because the workspace's callback source is a stub and cannot be stored; that reads as
291
+ `live: false` with a rising `missed`, and the remedy is to bind again. Re-binding from the same
292
+ gadget RE-ARMS the same registration rather than adding a second: a hook is identified by where
293
+ its deliveries land, and its counters carry over, since they are the history that prompted the
294
+ re-arm.
254
295
 
255
296
  Refusals from a live Gatekeeper are `GatekeeperError`s carrying a machine-readable `reason`
256
297
  (`unknown_actor`, `card_not_found`, `ambiguous_park`, …), the same role the platform's own
@@ -0,0 +1,18 @@
1
+ import type { GatekeeperBinding } from '@cat-factory/gatekeeper-bindings';
2
+ /**
3
+ * Every argument name an operation reads, in the order a caller would learn them.
4
+ *
5
+ * Exported because `approvals_inspect` and the session types describe the same set from the same
6
+ * binding, and a second derivation of "what may I pass" is how a published shape and an enforced
7
+ * one drift.
8
+ */
9
+ export declare function declaredArguments(binding: GatekeeperBinding): string[];
10
+ /**
11
+ * Refuse a call whose arguments the operation does not declare, or that omits one it requires.
12
+ *
13
+ * Returns the bag so the call site reads as a narrowing rather than as a statement with a side
14
+ * effect. An `undefined` value is treated as absent throughout, which is what a caller building a
15
+ * bag from optional fields produces and what the SDK's own forwarding already does with it.
16
+ */
17
+ export declare function checkedArguments(binding: GatekeeperBinding, args: Record<string, unknown>): Record<string, unknown>;
18
+ //# sourceMappingURL=arguments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AAMzE;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAMtE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmCzB"}
@@ -0,0 +1,75 @@
1
+ // Checking a call's arguments against what the operation DECLARES, before anything happens.
2
+ //
3
+ // The published contract asks a gatekeeper to validate RPC arguments against the declared
4
+ // signature and reject a call carrying one the receiver does not declare. The reference
5
+ // implementations generate that check from their own signatures; ours is generated already, one
6
+ // layer down: every binding in `@cat-factory/gatekeeper-bindings` carries its path parameters, its
7
+ // query parameters with which are required, and whether it takes a body. So the check is derived
8
+ // from the same table the session's `.d.ts` and the policy compiler read, and an operation whose
9
+ // shape changes brings its own validation with it.
10
+ //
11
+ // The reason to have it at all is the SILENT DROP. `invoke` forwards the arguments it recognises
12
+ // and ignores the rest, so an agent asking `tasks_list_by_service` to filter by a parameter that
13
+ // operation does not take used to get an unfiltered list and no word about it: a wrong answer
14
+ // shaped exactly like a right one. A near-miss spelling is the same failure with a plainer cause.
15
+ //
16
+ // It runs on BOTH doors, ahead of the approval queue and ahead of the key broker. That order is
17
+ // the point: a call that cannot succeed should not mint a credential, should not spend a
18
+ // workspace's approval on an action that would 400, and should not reach the deployment at all.
19
+ // Refusing it is a behaviour change for a caller that was sending an argument nothing read, which
20
+ // is exactly the caller this check exists for.
21
+ //
22
+ // What it does NOT check is what a value may BE. That is the deployment's judgement, it is stated
23
+ // in the spec these bindings are generated from, and its refusal already names the field; a second
24
+ // copy of it here would be free to disagree with the first.
25
+ import { GatekeeperError } from './errors.js';
26
+ /** The one argument key that is never a parameter: the request body `invoke` forwards. */
27
+ const BODY = 'body';
28
+ /**
29
+ * Every argument name an operation reads, in the order a caller would learn them.
30
+ *
31
+ * Exported because `approvals_inspect` and the session types describe the same set from the same
32
+ * binding, and a second derivation of "what may I pass" is how a published shape and an enforced
33
+ * one drift.
34
+ */
35
+ export function declaredArguments(binding) {
36
+ return [
37
+ ...binding.pathParams,
38
+ ...binding.queryParams.map((param) => param.name),
39
+ ...(binding.hasBody ? [BODY] : []),
40
+ ];
41
+ }
42
+ /**
43
+ * Refuse a call whose arguments the operation does not declare, or that omits one it requires.
44
+ *
45
+ * Returns the bag so the call site reads as a narrowing rather than as a statement with a side
46
+ * effect. An `undefined` value is treated as absent throughout, which is what a caller building a
47
+ * bag from optional fields produces and what the SDK's own forwarding already does with it.
48
+ */
49
+ export function checkedArguments(binding, args) {
50
+ const declared = declaredArguments(binding);
51
+ const supplied = Object.entries(args).filter(([, value]) => value !== undefined);
52
+ const undeclared = supplied.map(([name]) => name).filter((name) => !declared.includes(name));
53
+ if (undeclared.length > 0) {
54
+ throw new GatekeeperError('undeclared_argument', `'${binding.name}' does not take ${quoted(undeclared)}, so ${undeclared.length === 1 ? 'it would be' : 'they would be'} ` +
55
+ `dropped rather than sent. It takes ${declared.length === 0 ? 'no arguments' : quoted(declared)}.`);
56
+ }
57
+ for (const name of binding.pathParams) {
58
+ const value = args[name];
59
+ if (typeof value !== 'string' || value.length === 0) {
60
+ throw new GatekeeperError('missing_argument', `'${binding.name}' needs '${name}': it is part of the route (\`${binding.path}\`), so ` +
61
+ 'there is no call to make without it.');
62
+ }
63
+ }
64
+ for (const param of binding.queryParams) {
65
+ if (param.required && args[param.name] === undefined) {
66
+ throw new GatekeeperError('missing_argument', `'${binding.name}' needs '${param.name}': the deployment refuses the call without it, ` +
67
+ 'because it says which question is being asked rather than narrowing the answer.');
68
+ }
69
+ }
70
+ return args;
71
+ }
72
+ function quoted(names) {
73
+ return names.map((name) => `'${name}'`).join(', ');
74
+ }
75
+ //# sourceMappingURL=arguments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { RpcTarget } from 'capnweb';
2
2
  import type { GatekeeperBinding } from '@cat-factory/gatekeeper-bindings';
3
3
  import type { Actor, KeyBroker } from './keys.js';
4
+ import { type HookTopic } from './os/hooks.js';
4
5
  import { type CompiledTier } from './policy/compile.js';
5
6
  import type { ApprovalCard, GatekeeperState } from './state.js';
6
7
  /**
@@ -36,6 +37,15 @@ export interface SessionGovernance {
36
37
  * instead of returning, so a refused action cannot read as a call that returned nothing.
37
38
  */
38
39
  act<T>(binding: GatekeeperBinding, args: Record<string, unknown>, perform: () => Promise<T>): Promise<T>;
40
+ /**
41
+ * Register a callback the workspace will be pushed to, once it has approved the registration.
42
+ *
43
+ * On the seam rather than beside it because binding a hook is a request to the SAME queue every
44
+ * call passes through, and because the door with no queue is exactly the door with no hooks: a
45
+ * `/rpc` session has nowhere to hand a callback and nothing to authorize the deliveries against,
46
+ * so it refuses and names the projection it would have been accelerating.
47
+ */
48
+ subscribe(topic: HookTopic, callback: unknown): Promise<void>;
39
49
  /**
40
50
  * The session is gone: release everything it was holding on the workspace's behalf.
41
51
  *
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AAWzE,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAGjD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAY,MAAM,YAAY,CAAA;AAoBzE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjF;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,GAAG,CAAC,CAAC,EACH,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CAAA;IACb;;;;;;OAMG;IACH,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,EAAE,YAAY,CAAA;IAClB,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAA;IACzC,wFAAwF;IACxF,UAAU,CAAC,EAAE,iBAAiB,CAAA;CAC/B;AAED,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAA;IAClB,2FAA2F;IAC3F,SAAS,EAAE,OAAO,CAAA;IAClB,0FAA0F;IAC1F,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAA;YACd,OAAO,EAAE,MAAM,CAAA;YACf,OAAO,EAAE,MAAM,CAAA;YACf,oGAAoG;YACpG,OAAO,EAAE,OAAO,CAAA;YAChB,MAAM,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM,CAAA;gBACZ,QAAQ,EAAE,OAAO,CAAA;gBACjB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;gBAC3B,MAAM,EAAE,MAAM,CAAA;aACf,EAAE,CAAA;SACJ,EAAE,CAAA;KACJ,EAAE,CAAA;IACH,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS,CAmKpE"}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AAYzE,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAEjD,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AAElF,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAY,MAAM,YAAY,CAAA;AAuBzE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjF;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,GAAG,CAAC,CAAC,EACH,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CAAA;IACb;;;;;;;OAOG;IACH,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7D;;;;;;OAMG;IACH,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,EAAE,YAAY,CAAA;IAClB,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAA;IACzC,wFAAwF;IACxF,UAAU,CAAC,EAAE,iBAAiB,CAAA;CAC/B;AAED,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAA;IAClB,2FAA2F;IAC3F,SAAS,EAAE,OAAO,CAAA;IAClB,0FAA0F;IAC1F,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAA;YACd,OAAO,EAAE,MAAM,CAAA;YACf,OAAO,EAAE,MAAM,CAAA;YACf,oGAAoG;YACpG,OAAO,EAAE,OAAO,CAAA;YAChB,MAAM,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM,CAAA;gBACZ,QAAQ,EAAE,OAAO,CAAA;gBACjB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;gBAC3B,MAAM,EAAE,MAAM,CAAA;aACf,EAAE,CAAA;SACJ,EAAE,CAAA;KACJ,EAAE,CAAA;IACH,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS,CAgNpE"}
@@ -19,8 +19,10 @@
19
19
  // base classes, a `DataCloneError` on the first bind) is the more obvious one.
20
20
  import { RpcTarget } from 'capnweb';
21
21
  import { answerCard, assertAnswerable, pendingParks, describeStale, } from './approvals.js';
22
+ import { checkedArguments } from './arguments.js';
22
23
  import { GatekeeperError, PolicyError } from './errors.js';
23
24
  import { applyMask } from './masking.js';
25
+ import { HOOK_TOPICS } from './os/hooks.js';
24
26
  import { fenced } from './markdown.js';
25
27
  import { describeBinding } from './policy/compile.js';
26
28
  /**
@@ -38,7 +40,10 @@ const RESERVED_METHODS = [
38
40
  'approvals_list',
39
41
  'approvals_inspect',
40
42
  'approvals_answer',
43
+ 'approvals_subscribe',
41
44
  'runs_watched',
45
+ 'runs_subscribe',
46
+ 'hooks_bound',
42
47
  ];
43
48
  /**
44
49
  * Build the capability for one connected actor.
@@ -57,11 +62,16 @@ export function buildCapability(deps) {
57
62
  'method in capability.ts; a granted operation must never be shadowed by one.');
58
63
  }
59
64
  }
60
- const invoke = async (name, args) => {
65
+ const invoke = async (name, bag) => {
61
66
  const binding = granted.get(name);
62
67
  if (binding === undefined) {
63
68
  throw new GatekeeperError('binding_not_granted', `Tier '${tier.name}' does not grant '${name}'.`);
64
69
  }
70
+ // Ahead of the key broker and ahead of the queue, because a call that cannot succeed should
71
+ // mint no credential and spend no approval. An argument the operation does not declare is a
72
+ // REFUSAL rather than a drop: forwarded silently, it is a filter nobody applied and an answer
73
+ // that looks exactly like the right one.
74
+ const args = checkedArguments(binding, bag);
65
75
  const perform = async () => await deps.keys.run(deps.actor, tier.keyScope, (client) => binding.invoke(client, args));
66
76
  const governance = deps.governance;
67
77
  if (governance === undefined)
@@ -118,6 +128,34 @@ export function buildCapability(deps) {
118
128
  // `withheld()` is the degrade-loudly half: an agent that cannot tell "your policy hides this"
119
129
  // from "this deployment does not have it" reports the wrong one to whoever has to fix it.
120
130
  proto.withheld = () => tier.withheld;
131
+ /**
132
+ * Bind a callback for one topic, or refuse in the terms of the door the caller came in by.
133
+ *
134
+ * The refusal is the interesting half. `/rpc` brings no approval queue, so there is nothing to
135
+ * register a hook with and nothing to authorize its deliveries against; answering with a
136
+ * silently-never-fires registration would be the worst available outcome, and answering
137
+ * "unsupported" without naming `approvals_list()` would send a caller looking for a feature
138
+ * rather than for the two methods that already answer the same question.
139
+ */
140
+ const subscribe = async (topic, callback) => {
141
+ const governance = deps.governance;
142
+ if (governance === undefined) {
143
+ throw new GatekeeperError('hooks_unavailable', `This session was opened on a door with no approval queue, so ${HOOK_TOPICS[topic].sessionMethod}() ` +
144
+ 'has nowhere to register a callback and no way to authorize what it would push. Read ' +
145
+ '`approvals_list()` and `runs_watched()` instead: they carry exactly what a hook pushes.');
146
+ }
147
+ await governance.subscribe(topic, callback);
148
+ };
149
+ proto.approvals_subscribe = async (callback) => subscribe('approval_card', callback);
150
+ proto.runs_subscribe = async (callback) => subscribe('run_event', callback);
151
+ // What this account has enabled, and whether each one's live half survived. A hook that stopped
152
+ // firing is otherwise indistinguishable from a deployment where nothing happened, which is the
153
+ // reading a workspace must never be left to make on its own.
154
+ proto.hooks_bound = async () => {
155
+ const hooks = await deps.state.listHooks(deps.actor.id);
156
+ await observeLocal('List the hooks bound for this account', `${hooks.length} hook(s) this workspace enabled, with what each has been pushed and what it missed.`);
157
+ return hooks;
158
+ };
121
159
  proto.approvals_list = async () => {
122
160
  const cards = await deps.state.listCards();
123
161
  await observeLocal('List the open approval cards', `${cards.length} card(s) the paired deployment raised and delivered to this Gatekeeper.`);
@@ -1 +1 @@
1
- {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts CHANGED
@@ -39,6 +39,16 @@ export declare function requireVar(env: GatekeeperEnv, binding: StringBinding):
39
39
  * reads as a healthy Gatekeeper.
40
40
  */
41
41
  export declare function missingBindings(env: GatekeeperEnv): Binding[];
42
+ /**
43
+ * The durable object holding everything this pairing knows, addressed the ONE way.
44
+ *
45
+ * Named for the deployment it is paired with, so pointing this Worker at a different cat-factory
46
+ * gets a different object rather than inheriting the previous one's cards, hooks and minted keys.
47
+ * It is a function rather than a line inside `Gatekeeper` because the hook controller reaches the
48
+ * same object without assembling a Gatekeeper at all, and a second spelling of the name would be
49
+ * a second object holding half the state.
50
+ */
51
+ export declare function stateFor(env: GatekeeperEnv): DurableObjectStub<GatekeeperState>;
42
52
  /** The refusal an operator can act on: every unset binding, each with how to set it. */
43
53
  export declare function describeMissingBindings(missing: readonly Binding[]): string;
44
54
  export {};
package/dist/env.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,WAAW,aAAa;IAC5B,mFAAmF;IACnF,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAA;IAClB,kGAAkG;IAClG,gBAAgB,EAAE,MAAM,CAAA;IACxB,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAA;CAC/C;AAED,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAsB7D,KAAK,OAAO,GAAG,MAAM,aAAa,CAAA;AAgBlC,2DAA2D;AAC3D,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IAEzB,YAAY,OAAO,EAAE,OAAO,EAI3B;CACF;AAED,KAAK,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAE9C,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAI7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,EAAE,CAG7D;AAYD,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAG3E"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,WAAW,aAAa;IAC5B,mFAAmF;IACnF,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAA;IAClB,kGAAkG;IAClG,gBAAgB,EAAE,MAAM,CAAA;IACxB,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAA;CAC/C;AAED,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAsB7D,KAAK,OAAO,GAAG,MAAM,aAAa,CAAA;AAgBlC,2DAA2D;AAC3D,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IAEzB,YAAY,OAAO,EAAE,OAAO,EAI3B;CACF;AAED,KAAK,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAE9C,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAI7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,EAAE,CAG7D;AAYD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,aAAa,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAE/E;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAG3E"}
package/dist/env.js CHANGED
@@ -82,6 +82,18 @@ function isSet(env, binding) {
82
82
  const value = env[binding];
83
83
  return typeof value === 'string' && value.length > 0;
84
84
  }
85
+ /**
86
+ * The durable object holding everything this pairing knows, addressed the ONE way.
87
+ *
88
+ * Named for the deployment it is paired with, so pointing this Worker at a different cat-factory
89
+ * gets a different object rather than inheriting the previous one's cards, hooks and minted keys.
90
+ * It is a function rather than a line inside `Gatekeeper` because the hook controller reaches the
91
+ * same object without assembling a Gatekeeper at all, and a second spelling of the name would be
92
+ * a second object holding half the state.
93
+ */
94
+ export function stateFor(env) {
95
+ return env.STATE.get(env.STATE.idFromName(requireVar(env, 'CAT_FACTORY_BASE_URL')));
96
+ }
85
97
  /** The refusal an operator can act on: every unset binding, each with how to set it. */
86
98
  export function describeMissingBindings(missing) {
87
99
  const remedies = missing.map((binding) => `${binding} (${howToSet(binding)})`).join('; ');
package/dist/env.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,mDAAmD;AACnD,EAAE;AACF,kGAAkG;AAClG,kGAAkG;AAClG,8FAA8F;AAC9F,6FAA6F;AAC7F,2FAA2F;AAC3F,mDAAmD;AACnD,EAAE;AACF,kGAAkG;AAClG,iGAAiG;AACjG,+EAA+E;AA0B/E;;;;;;;;;GASG;AACH,MAAM,aAAa,GAAG;IACpB,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE,KAAK;IACjB,UAAU,EAAE,KAAK;IACjB,gBAAgB,EAAE,QAAQ;IAC1B,cAAc,EAAE,QAAQ;IACxB,eAAe,EAAE,QAAQ;IACzB,KAAK,EAAE,gBAAgB;CACoC,CAAA;AAI7D,mFAAmF;AACnF,SAAS,QAAQ,CAAC,OAAgB;IAChC,gGAAgG;IAChG,2DAA2D;IAC3D,QAAQ,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,KAAK,KAAK;YACR,OAAO,kCAAkC,CAAA;QAC3C,KAAK,QAAQ;YACX,OAAO,qCAAqC,OAAO,4BAA4B,CAAA;QACjF,KAAK,gBAAgB;YACnB,OAAO,oFAAoF,CAAA;IAC/F,CAAC;AACH,CAAC;AAED,2DAA2D;AAC3D,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,OAAO,CAAS;IAEzB,YAAY,OAAgB;QAC1B,KAAK,CAAC,GAAG,OAAO,0CAA0C,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC/E,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CACF;AAID,2DAA2D;AAC3D,MAAM,UAAU,UAAU,CAAC,GAAkB,EAAE,OAAsB;IACnE,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,CAAA;IACnF,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,GAAkB;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAc,CAAA;IACxD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,KAAK,CAAC,GAAkB,EAAE,OAAgB;IACjD,IAAI,aAAa,CAAC,OAAO,CAAC,KAAK,gBAAgB,EAAE,CAAC;QAChD,sFAAsF;QACtF,+FAA+F;QAC/F,OAAO,OAAO,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,UAAU,CAAA;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;AACtD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,uBAAuB,CAAC,OAA2B;IACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,KAAK,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzF,OAAO,gFAAgF,QAAQ,GAAG,CAAA;AACpG,CAAC"}
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -22,8 +22,18 @@ export type GatekeeperReason = 'unknown_actor' | 'unknown_tier' | 'binding_not_g
22
22
  | 'session_ended'
23
23
  /** The URL the workspace asked for is not one this Gatekeeper serves. */
24
24
  | 'no_such_resource'
25
- /** Sharing an observation onward was refused, which is this Gatekeeper's default. */
25
+ /** Sharing an observation onward was refused: the observer could not read all of it directly. */
26
26
  | 'sharing_refused'
27
+ /** Sharing was refused because the observer could not be identified at all. */
28
+ | 'sharing_unverifiable'
29
+ /** The call carries an argument the operation does not declare, so it would have been dropped. */
30
+ | 'undeclared_argument'
31
+ /** The call omits an argument the operation requires. */
32
+ | 'missing_argument'
33
+ /** This door serves no hooks: it has no approval queue to register one with. */
34
+ | 'hooks_unavailable'
35
+ /** The workspace's own side did not take a hook binding, and said why. */
36
+ | 'hook_bind_refused'
27
37
  /** The deployment's entry module does not export something the OS object model needs. */
28
38
  | 'missing_export';
29
39
  /** A refusal the caller (or the OS deployment operating it) acts on. */
@@ -31,4 +41,13 @@ export declare class GatekeeperError extends Error {
31
41
  readonly reason: GatekeeperReason;
32
42
  constructor(reason: GatekeeperReason, message: string);
33
43
  }
44
+ /**
45
+ * A failure as a refusal or a record carries it: one line, never an object nothing can render.
46
+ *
47
+ * Here rather than beside each caller because three of them (a hook push, a bind the workspace did
48
+ * not take, a verifier that could not be questioned) fold a cause into prose a person reads, and
49
+ * three copies of the same two lines is how they drift into disagreeing about what an
50
+ * `AggregateError` or a thrown string looks like.
51
+ */
52
+ export declare function describeError(error: unknown): string;
34
53
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,uEAAuE;AACvE,qBAAa,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,mEAAmE;AACnE,MAAM,MAAM,gBAAgB,GACxB,eAAe,GACf,cAAc,GACd,qBAAqB,GACrB,gBAAgB,GAChB,uBAAuB,GACvB,oBAAoB;AACtB,mFAAmF;GACjF,gBAAgB;AAClB,sEAAsE;GACpE,cAAc;AAChB,0EAA0E;GACxE,gBAAgB;AAClB,uFAAuF;GACrF,oBAAoB;AACtB,kFAAkF;GAChF,qBAAqB;AACvB,mFAAmF;GACjF,iBAAiB;AACnB,gGAAgG;GAC9F,gBAAgB;AAClB,sFAAsF;GACpF,eAAe;AACjB,yEAAyE;GACvE,kBAAkB;AACpB,qFAAqF;GACnF,iBAAiB;AACnB,yFAAyF;GACvF,gBAAgB,CAAA;AAEpB,wEAAwE;AACxE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IAEjC,YAAY,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAIpD;CACF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,uEAAuE;AACvE,qBAAa,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,mEAAmE;AACnE,MAAM,MAAM,gBAAgB,GACxB,eAAe,GACf,cAAc,GACd,qBAAqB,GACrB,gBAAgB,GAChB,uBAAuB,GACvB,oBAAoB;AACtB,mFAAmF;GACjF,gBAAgB;AAClB,sEAAsE;GACpE,cAAc;AAChB,0EAA0E;GACxE,gBAAgB;AAClB,uFAAuF;GACrF,oBAAoB;AACtB,kFAAkF;GAChF,qBAAqB;AACvB,mFAAmF;GACjF,iBAAiB;AACnB,gGAAgG;GAC9F,gBAAgB;AAClB,sFAAsF;GACpF,eAAe;AACjB,yEAAyE;GACvE,kBAAkB;AACpB,iGAAiG;GAC/F,iBAAiB;AACnB,+EAA+E;GAC7E,sBAAsB;AACxB,kGAAkG;GAChG,qBAAqB;AACvB,yDAAyD;GACvD,kBAAkB;AACpB,gFAAgF;GAC9E,mBAAmB;AACrB,0EAA0E;GACxE,mBAAmB;AACrB,yFAAyF;GACvF,gBAAgB,CAAA;AAEpB,wEAAwE;AACxE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IAEjC,YAAY,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAIpD;CACF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD"}
package/dist/errors.js CHANGED
@@ -27,4 +27,15 @@ export class GatekeeperError extends Error {
27
27
  this.reason = reason;
28
28
  }
29
29
  }
30
+ /**
31
+ * A failure as a refusal or a record carries it: one line, never an object nothing can render.
32
+ *
33
+ * Here rather than beside each caller because three of them (a hook push, a bind the workspace did
34
+ * not take, a verifier that could not be questioned) fold a cause into prose a person reads, and
35
+ * three copies of the same two lines is how they drift into disagreeing about what an
36
+ * `AggregateError` or a thrown string looks like.
37
+ */
38
+ export function describeError(error) {
39
+ return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
40
+ }
30
41
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,6FAA6F;AAC7F,mGAAmG;AACnG,mGAAmG;AACnG,2EAA2E;AAC3E,EAAE;AACF,gGAAgG;AAChG,kGAAkG;AAClG,iGAAiG;AACjG,oEAAoE;AAEpE,uEAAuE;AACvE,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF;AAiCD,wEAAwE;AACxE,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAkB;IAEjC,YAAY,MAAwB,EAAE,OAAe;QACnD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,6FAA6F;AAC7F,mGAAmG;AACnG,mGAAmG;AACnG,2EAA2E;AAC3E,EAAE;AACF,gGAAgG;AAChG,kGAAkG;AAClG,iGAAiG;AACjG,oEAAoE;AAEpE,uEAAuE;AACvE,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF;AA2CD,wEAAwE;AACxE,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAkB;IAEjC,YAAY,MAAwB,EAAE,OAAe;QACnD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACnF,CAAC"}
@@ -1,12 +1,28 @@
1
1
  import { type SessionGovernance } from './capability.js';
2
2
  import { type GatekeeperEnv } from './env.js';
3
3
  import { type Actor } from './keys.js';
4
+ import type { HookTopic } from './os/hooks.js';
4
5
  import { type CompiledTier, type GatekeeperPolicy } from './policy/compile.js';
5
6
  import { type VerificationResult } from './webhook/signature.js';
6
7
  /** Why a delivery was refused, drawn from the verifier so the two cannot drift. */
7
8
  type RejectionReason = Extract<VerificationResult, {
8
9
  ok: false;
9
10
  }>['reason'];
11
+ /**
12
+ * What the receiver handed to the hook fan-out, which is DISPATCH and never delivery.
13
+ *
14
+ * The distinction is the whole reason this shape changed. The fan-out runs behind the
15
+ * acknowledgement, so at the moment this is reported no push has been made and any count of them
16
+ * would be a zero standing in for a number nobody has yet: the one reading a receiver must never
17
+ * offer, because it is indistinguishable from a delivery no hook took. What each push DID land on
18
+ * its own registration's counters, which `hooks_bound()` publishes.
19
+ */
20
+ export interface HookDispatchReceipt {
21
+ /** How many payloads this delivery produced. Zero when no topic covers it. */
22
+ pushes: number;
23
+ /** The distinct topics they carry, so the platform's delivery log names what was dispatched. */
24
+ topics: HookTopic[];
25
+ }
10
26
  /** What taking delivery of one webhook POST did. */
11
27
  export type DeliveryOutcome = {
12
28
  handled: 'rejected';
@@ -20,6 +36,7 @@ export type DeliveryOutcome = {
20
36
  handled: 'accepted';
21
37
  deliveryId: string;
22
38
  effect: 'opened' | 'superseded' | 'run-event' | 'none';
39
+ hooks: HookDispatchReceipt;
23
40
  };
24
41
  export declare class Gatekeeper {
25
42
  #private;
@@ -84,6 +101,15 @@ export declare class Gatekeeper {
84
101
  * would be the wrong shape there: not having opted in is a state, not a fault.
85
102
  */
86
103
  get autoProvisionedTierName(): string | null;
104
+ /**
105
+ * Whether this deployment minted the named account.
106
+ *
107
+ * Asked by the ONE caller that is handed an account id from outside (`addObserver`, over an
108
+ * observer's verifier) and has to resolve a tier for it. Every other account id in this package
109
+ * arrives on `ctx.props` of a stub this Gatekeeper handed the workspace, so it was minted here
110
+ * by construction and asking again would be a lookup with no question behind it.
111
+ */
112
+ recognizesAccount(accountId: string): Promise<boolean>;
87
113
  /** The origin of the cat-factory deployment this Gatekeeper is paired with. */
88
114
  get deployment(): string;
89
115
  /**
@@ -116,8 +142,12 @@ export declare class Gatekeeper {
116
142
  * Deduping in a call of its own would be worse than useless: a marker committed before the card
117
143
  * write turns a failed write into a `duplicate` on the platform's retry, so the approval never
118
144
  * reaches the inbox and nothing anywhere reports that it did not.
145
+ *
146
+ * `defer` is how the fan-out is kept OFF that path, and it is a parameter rather than something
147
+ * read here because the lifetime being extended is the Worker invocation's, which only the
148
+ * handler holds.
119
149
  */
120
- takeDelivery(request: Request, now: number): Promise<DeliveryOutcome>;
150
+ takeDelivery(request: Request, now: number, defer: (work: Promise<unknown>) => void): Promise<DeliveryOutcome>;
121
151
  }
122
152
  export {};
123
153
  //# sourceMappingURL=gatekeeper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gatekeeper.d.ts","sourceRoot":"","sources":["../src/gatekeeper.ts"],"names":[],"mappings":"AAWA,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,WAAW,CAAA;AACjD,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAgBhF,mFAAmF;AACnF,KAAK,eAAe,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,QAAQ,CAAC,CAAA;AAE3E,oDAAoD;AACpD,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GAChD;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC5C;IACE,OAAO,EAAE,UAAU,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,QAAQ,GAAG,YAAY,GAAG,WAAW,GAAG,MAAM,CAAA;CACvD,CAAA;AAEL,qBAAa,UAAU;;IAMrB,OAAO,eAiBN;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAEtE;IAED,mEAAmE;IACnE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIxC;IAED;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,iBAAiB,+BAEzD;IAED;;;;;;OAMG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,+BAMpE;IAYD;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAUrC;IAED;;;;;;;OAOG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAU9C;IAED;;;;;;;OAOG;IACH,iBAAiB,IAAI,YAAY,CAUhC;IAED;;;;;;OAMG;IACH,IAAI,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAE3C;IAED,+EAA+E;IAC/E,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAEjF;IAED;;;;;;OAMG;IACG,MAAM,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CA2B1D;IAED;;;;;;;;;OASG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA0B1E;CACF"}
1
+ {"version":3,"file":"gatekeeper.d.ts","sourceRoot":"","sources":["../src/gatekeeper.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@
9
9
  // forking it.
10
10
  import { CatFactoryClient } from '@cat-factory/sdk';
11
11
  import { buildCapability } from './capability.js';
12
- import { requireVar } from './env.js';
12
+ import { requireVar, stateFor } from './env.js';
13
13
  import { GatekeeperError } from './errors.js';
14
14
  import { KeyBroker } from './keys.js';
15
15
  import { autoProvisionedTier, compilePolicy, tierForAccount, tierForActor, } from './policy/compile.js';
@@ -36,10 +36,7 @@ export class Gatekeeper {
36
36
  this.#policy = policy;
37
37
  const baseUrl = requireVar(env, 'CAT_FACTORY_BASE_URL');
38
38
  const clientFor = (apiKey) => new CatFactoryClient({ baseUrl, apiKey, userAgent: USER_AGENT });
39
- // One durable object per PAIRED DEPLOYMENT, named for the origin it is paired with. The name
40
- // is the pairing's own identity, so pointing this Worker at a different cat-factory gets a
41
- // different object rather than inheriting the previous one's cards and minted keys.
42
- this.#state = env.STATE.get(env.STATE.idFromName(baseUrl));
39
+ this.#state = stateFor(env);
43
40
  this.#keys = new KeyBroker({
44
41
  state: this.#state,
45
42
  provisioning: clientFor(requireVar(env, 'PROVISIONING_KEY')),
@@ -149,6 +146,17 @@ export class Gatekeeper {
149
146
  get autoProvisionedTierName() {
150
147
  return this.#policy.autoProvisionedTier;
151
148
  }
149
+ /**
150
+ * Whether this deployment minted the named account.
151
+ *
152
+ * Asked by the ONE caller that is handed an account id from outside (`addObserver`, over an
153
+ * observer's verifier) and has to resolve a tier for it. Every other account id in this package
154
+ * arrives on `ctx.props` of a stub this Gatekeeper handed the workspace, so it was minted here
155
+ * by construction and asking again would be a lookup with no question behind it.
156
+ */
157
+ async recognizesAccount(accountId) {
158
+ return await this.#state.hasAccount(accountId);
159
+ }
152
160
  /** The origin of the cat-factory deployment this Gatekeeper is paired with. */
153
161
  get deployment() {
154
162
  return requireVar(this.#env, 'CAT_FACTORY_BASE_URL');
@@ -206,8 +214,12 @@ export class Gatekeeper {
206
214
  * Deduping in a call of its own would be worse than useless: a marker committed before the card
207
215
  * write turns a failed write into a `duplicate` on the platform's retry, so the approval never
208
216
  * reaches the inbox and nothing anywhere reports that it did not.
217
+ *
218
+ * `defer` is how the fan-out is kept OFF that path, and it is a parameter rather than something
219
+ * read here because the lifetime being extended is the Worker invocation's, which only the
220
+ * handler holds.
209
221
  */
210
- async takeDelivery(request, now) {
222
+ async takeDelivery(request, now, defer) {
211
223
  const rawBody = await request.text();
212
224
  const verdict = await verifyDelivery(request.headers, rawBody, requireVar(this.#env, 'WEBHOOK_SECRET'), now);
213
225
  if (!verdict.ok)
@@ -222,12 +234,30 @@ export class Gatekeeper {
222
234
  const delivery = readDelivery(parsed);
223
235
  if (delivery === null)
224
236
  return { handled: 'unparseable' };
225
- const applied = await this.#state.applyDelivery(delivery.deliveryId, cardEffectOf(delivery), now);
237
+ const effect = cardEffectOf(delivery);
238
+ const applied = await this.#state.applyDelivery(delivery.deliveryId, effect, now);
226
239
  if (!applied.applied)
227
240
  return { handled: 'duplicate', deliveryId: delivery.deliveryId };
228
- return { handled: 'accepted', deliveryId: delivery.deliveryId, effect: applied.effect };
241
+ // AFTER the write and BESIDE the acknowledgement, never in front of it. The card is the
242
+ // durable truth and the push is the accelerator over it, so a workspace that hangs or refuses
243
+ // must cost a notification and never the record. Awaiting the fan-out here made it cost both:
244
+ // one slow workspace times the delivery out, the platform retries to protect a write that had
245
+ // already committed, and the retry is deduped into pushing nothing at all, so the notification
246
+ // the wait was supposed to guarantee is the one thing certain to be lost.
247
+ if (applied.pushes.length > 0)
248
+ defer(this.#state.dispatchHooks(applied.pushes, now));
249
+ return {
250
+ handled: 'accepted',
251
+ deliveryId: delivery.deliveryId,
252
+ effect: applied.effect,
253
+ hooks: receiptFor(applied.pushes),
254
+ };
229
255
  }
230
256
  }
257
+ /** What was handed to the fan-out, summarised for the platform's own delivery log. */
258
+ function receiptFor(pushes) {
259
+ return { pushes: pushes.length, topics: [...new Set(pushes.map((push) => push.topic))] };
260
+ }
231
261
  /**
232
262
  * Compare two secrets without an early exit on the first differing character.
233
263
  *