@cat-factory/gatekeeper-worker 0.4.3 → 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 (101) hide show
  1. package/README.md +100 -13
  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 +55 -0
  7. package/dist/capability.d.ts.map +1 -1
  8. package/dist/capability.js +99 -5
  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 +32 -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 +78 -3
  19. package/dist/gatekeeper.d.ts.map +1 -1
  20. package/dist/gatekeeper.js +127 -13
  21. package/dist/gatekeeper.js.map +1 -1
  22. package/dist/index.d.ts +18 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +19 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/markdown.d.ts +12 -0
  27. package/dist/markdown.d.ts.map +1 -0
  28. package/dist/markdown.js +28 -0
  29. package/dist/markdown.js.map +1 -0
  30. package/dist/os/account.d.ts +27 -0
  31. package/dist/os/account.d.ts.map +1 -0
  32. package/dist/os/account.js +130 -0
  33. package/dist/os/account.js.map +1 -0
  34. package/dist/os/descriptions.d.ts +43 -0
  35. package/dist/os/descriptions.d.ts.map +1 -0
  36. package/dist/os/descriptions.js +100 -0
  37. package/dist/os/descriptions.js.map +1 -0
  38. package/dist/os/discoverability.d.ts +42 -0
  39. package/dist/os/discoverability.d.ts.map +1 -0
  40. package/dist/os/discoverability.js +63 -0
  41. package/dist/os/discoverability.js.map +1 -0
  42. package/dist/os/exports.d.ts +55 -0
  43. package/dist/os/exports.d.ts.map +1 -0
  44. package/dist/os/exports.js +93 -0
  45. package/dist/os/exports.js.map +1 -0
  46. package/dist/os/hook-controller.d.ts +14 -0
  47. package/dist/os/hook-controller.d.ts.map +1 -0
  48. package/dist/os/hook-controller.js +53 -0
  49. package/dist/os/hook-controller.js.map +1 -0
  50. package/dist/os/hooks.d.ts +200 -0
  51. package/dist/os/hooks.d.ts.map +1 -0
  52. package/dist/os/hooks.js +253 -0
  53. package/dist/os/hooks.js.map +1 -0
  54. package/dist/os/protocol.d.ts +193 -0
  55. package/dist/os/protocol.d.ts.map +1 -0
  56. package/dist/os/protocol.js +22 -0
  57. package/dist/os/protocol.js.map +1 -0
  58. package/dist/os/queue.d.ts +99 -0
  59. package/dist/os/queue.d.ts.map +1 -0
  60. package/dist/os/queue.js +240 -0
  61. package/dist/os/queue.js.map +1 -0
  62. package/dist/os/resource-core.d.ts +115 -0
  63. package/dist/os/resource-core.d.ts.map +1 -0
  64. package/dist/os/resource-core.js +172 -0
  65. package/dist/os/resource-core.js.map +1 -0
  66. package/dist/os/resource.d.ts +16 -0
  67. package/dist/os/resource.d.ts.map +1 -0
  68. package/dist/os/resource.js +70 -0
  69. package/dist/os/resource.js.map +1 -0
  70. package/dist/os/resources.d.ts +11 -0
  71. package/dist/os/resources.d.ts.map +1 -0
  72. package/dist/os/resources.js +26 -0
  73. package/dist/os/resources.js.map +1 -0
  74. package/dist/os/session-types.d.ts +6 -0
  75. package/dist/os/session-types.d.ts.map +1 -0
  76. package/dist/os/session-types.js +110 -0
  77. package/dist/os/session-types.js.map +1 -0
  78. package/dist/os/sharing.d.ts +35 -0
  79. package/dist/os/sharing.d.ts.map +1 -0
  80. package/dist/os/sharing.js +135 -0
  81. package/dist/os/sharing.js.map +1 -0
  82. package/dist/os/vendor.d.ts +14 -0
  83. package/dist/os/vendor.d.ts.map +1 -0
  84. package/dist/os/vendor.js +102 -0
  85. package/dist/os/vendor.js.map +1 -0
  86. package/dist/policy/compile.d.ts +38 -0
  87. package/dist/policy/compile.d.ts.map +1 -1
  88. package/dist/policy/compile.js +42 -4
  89. package/dist/policy/compile.js.map +1 -1
  90. package/dist/policy/index.d.ts +1 -1
  91. package/dist/policy/index.d.ts.map +1 -1
  92. package/dist/policy/index.js +1 -1
  93. package/dist/policy/index.js.map +1 -1
  94. package/dist/state.d.ts +80 -1
  95. package/dist/state.d.ts.map +1 -1
  96. package/dist/state.js +234 -6
  97. package/dist/state.js.map +1 -1
  98. package/dist/worker.d.ts.map +1 -1
  99. package/dist/worker.js +28 -6
  100. package/dist/worker.js.map +1 -1
  101. package/package.json +3 -3
@@ -0,0 +1,115 @@
1
+ import type { GatekeeperEnv } from '../env.js';
2
+ import type { GatekeeperPolicy } from '../policy/compile.js';
3
+ import type { ActionKind, ApprovalQueue, ResourceDescription, ResourceObject } from './protocol.js';
4
+ /**
5
+ * What the account imbues a resource object with when it hands the class to the workspace.
6
+ *
7
+ * The account and NOTHING else. The URL the workspace matched is deliberately not here: under this
8
+ * Gatekeeper's own model a resource IS the paired workspace, so every URL that matches the pattern
9
+ * binds the same one and the matched URL decides nothing. Carrying it would be state whose only
10
+ * effect is that the next reader has to work out it decides nothing, and it had already been
11
+ * assigned the pattern rather than the match without anything noticing. A consumer that genuinely
12
+ * needs the bound URL adds it back WITH the reader that wants it, which is also the change that
13
+ * would say which of the two it meant.
14
+ */
15
+ export interface ResourceProps {
16
+ /** The account this resource is bound for. Every key minted through it is stamped with this. */
17
+ accountId: string;
18
+ }
19
+ /**
20
+ * What a resource needs beyond its own environment: the Worker's exports.
21
+ *
22
+ * A hook's controller is one of this Worker's own named exports, resolved as
23
+ * `ctx.exports.CatFactoryHookController` against the DEPLOYMENT's entry module, and the shell is
24
+ * the only place that bag exists. It is a dependency rather than a lookup so this core stays
25
+ * drivable in process, where the suite supplies its own.
26
+ */
27
+ export interface ResourceDependencies {
28
+ /** The Worker's own exports, as the object model reaches them. */
29
+ exports: unknown;
30
+ }
31
+ /** One bound resource: the session it opens, its types, and the action lifecycle behind it. */
32
+ export declare class ResourceCore implements ResourceObject {
33
+ #private;
34
+ constructor(env: GatekeeperEnv, policy: GatekeeperPolicy, props: ResourceProps, deps: ResourceDependencies);
35
+ describe(): Promise<ResourceDescription>;
36
+ /**
37
+ * The session's own types, rendered for the tier this account holds.
38
+ *
39
+ * Tier-specific rather than a copy of the vendor's, because this is the one the contract points a
40
+ * caller at: `ResourceDescription.tsType` must name an export of THIS method's output, and a
41
+ * session carries exactly its granted operations.
42
+ */
43
+ getTypeScriptTypes(): Promise<string>;
44
+ /**
45
+ * Open a governed session.
46
+ *
47
+ * The queue is not optional and not a decoration: every operation the returned object carries
48
+ * funnels through the one `invoke` closure, which submits actions to this queue and authorizes
49
+ * observations against it. The tier policy underneath is the FLOOR, so an operation the policy
50
+ * never granted is absent from the object rather than something the queue has to refuse.
51
+ *
52
+ * The queue passed here is OWNED by the session that comes back: it is released, along with
53
+ * every action that session left undecided, when the session is disposed. A caller reaching this
54
+ * over RPC therefore hands in a reference of its own rather than the parameter it received (see
55
+ * `resource.ts`), because the parameter's lifetime ends when this call returns and the session's
56
+ * does not.
57
+ */
58
+ startSession(approvalQueue: ApprovalQueue): Promise<unknown>;
59
+ /**
60
+ * How many submitted actions this object is still holding, across every live session.
61
+ *
62
+ * Exposed for the same reason the ledger counts them: the ONE unbounded thing about a long-lived
63
+ * resource object is this set, and a count that does not fall back to zero when the sessions are
64
+ * gone is the leak rather than a slow day.
65
+ */
66
+ get pendingActionCount(): number;
67
+ /**
68
+ * The action kinds this Gatekeeper may auto-apply, if the user opted into the kind.
69
+ *
70
+ * Derived from the same table and the same consequence reading `describeAction` stamps onto each
71
+ * submission, so a pre-approval UI listing kinds before any action exists and the `autoApprovable`
72
+ * flag on an action that has been submitted cannot disagree.
73
+ *
74
+ * TODAY THIS IS EMPTY, and that is the honest answer rather than a gap. The public surface
75
+ * annotates a consequence only where the stakes are real money or a merged pull request, so every
76
+ * other mutation is unannotated, and the table's documented reading of an unannotated mutation is
77
+ * that it is destructive. Offering those for unattended auto-approval would mean inverting that
78
+ * default here, which is precisely the misreading `resolveConsequence` exists to stop. If the
79
+ * surface ever states that a write is safe, it appears here with no further decision.
80
+ */
81
+ getAutoApprovableActions(): Promise<ActionKind[]>;
82
+ /** The workspace approved an action: perform it, and hand the result to the waiting call. */
83
+ applyAction(action: number): Promise<void>;
84
+ /** The workspace rejected an action: the waiting call throws and nothing is performed. */
85
+ rejectAction(action: number): Promise<void>;
86
+ /**
87
+ * Reverting is not something this Gatekeeper can do, which every action it submits already states
88
+ * (`implementsRevert: false`).
89
+ *
90
+ * It answers rather than throwing because the caller is the workspace UI on behalf of a person who
91
+ * wants their change undone: a message naming what they have to do themselves is the useful
92
+ * answer, where an exception would surface as a failed revert they might retry.
93
+ */
94
+ revertAction(_action: number): Promise<{
95
+ message: string;
96
+ canRetry: false;
97
+ }>;
98
+ /**
99
+ * Share this resource's observations onward, if the observer could have read them all directly.
100
+ *
101
+ * The contract's requirement, answered rather than declined: the observer names an account this
102
+ * deployment minted, its policy resolves that account's tier, and the share is admitted only
103
+ * when that tier reaches everything the tier THIS resource is bound at reaches. `sharing.ts`
104
+ * holds the tests and why each is the one the contract asks for, including why the account has
105
+ * to be recognised before its tier means anything.
106
+ *
107
+ * Nothing is recorded about an admitted observer, and that is a property of the rule rather than
108
+ * an omission: every accepted observer can read everything this resource could ever have
109
+ * observed, so there is never an observation to exclude from them afterwards.
110
+ */
111
+ addObserver(id: string, user: unknown): Promise<void>;
112
+ /** Idempotent by contract: nothing is recorded about an observer, so nothing is forgotten. */
113
+ removeObserver(_id: string): Promise<void>;
114
+ }
115
+ //# sourceMappingURL=resource-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-core.d.ts","sourceRoot":"","sources":["../../src/os/resource-core.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,KAAK,EAAgB,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAG1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAKnG;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,gGAAgG;IAChG,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,+FAA+F;AAC/F,qBAAa,YAAa,YAAW,cAAc;;IAOjD,YACE,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,oBAAoB,EAM3B;IAEK,QAAQ,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAW7C;IAED;;;;;;OAMG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1C;IAED;;;;;;;;;;;;;OAaG;IACG,YAAY,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBjE;IAED;;;;;;OAMG;IACH,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED;;;;;;;;;;;;;OAaG;IACG,wBAAwB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAKtD;IAED,6FAA6F;IACvF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;IAED,0FAA0F;IACpF,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhD;IAED;;;;;;;OAOG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,CAAA;KAAE,CAAC,CAOjF;IAED;;;;;;;;;;;;OAYG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAW1D;IAED,8FAA8F;IACxF,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;CASpD"}
@@ -0,0 +1,172 @@
1
+ // What a bound resource DOES, separated from the Durable Object it lives in.
2
+ //
3
+ // The split is not ceremony. A Durable Object can only be constructed by workerd from a real
4
+ // `DurableObjectState`, and the props-imbued class this Gatekeeper hands the workspace is opaque by
5
+ // design (the workspace instantiates it, through machinery that is its own). So a suite that could
6
+ // only reach this behaviour through the object would be reduced to asserting that a class was
7
+ // returned. Everything worth getting wrong lives here instead, where it is ordinary code with
8
+ // ordinary dependencies, and `resource.ts` is the shell that supplies `ctx.props` and holds one of
9
+ // these for the object's lifetime.
10
+ //
11
+ // Holding ONE per object is what the action ledger needs: the workspace settles an action by
12
+ // calling `applyAction` on the resource, so a core rebuilt per call would lose the pending action
13
+ // the decision is about.
14
+ import { Gatekeeper } from '../gatekeeper.js';
15
+ import { actionKindOf } from './descriptions.js';
16
+ import { loopbackExport } from './exports.js';
17
+ import { ActionLedger, queueGovernance } from './queue.js';
18
+ import { assertObserverMaySee, identifyObserver } from './sharing.js';
19
+ import { renderTierSessionTypes, SESSION_INTERFACE_NAME } from './session-types.js';
20
+ /** One bound resource: the session it opens, its types, and the action lifecycle behind it. */
21
+ export class ResourceCore {
22
+ #env;
23
+ #policy;
24
+ #props;
25
+ #deps;
26
+ #ledger = new ActionLedger();
27
+ constructor(env, policy, props, deps) {
28
+ this.#env = env;
29
+ this.#policy = policy;
30
+ this.#props = props;
31
+ this.#deps = deps;
32
+ }
33
+ async describe() {
34
+ const tier = this.#tier();
35
+ return {
36
+ url: this.#gatekeeper().deployment,
37
+ title: 'cat-factory workspace',
38
+ snippet: `File work, start runs and answer what they park on, at policy tier '${tier.name}': ` +
39
+ `${tier.description}`,
40
+ suggestedBindingName: 'catFactory',
41
+ tsType: SESSION_INTERFACE_NAME,
42
+ };
43
+ }
44
+ /**
45
+ * The session's own types, rendered for the tier this account holds.
46
+ *
47
+ * Tier-specific rather than a copy of the vendor's, because this is the one the contract points a
48
+ * caller at: `ResourceDescription.tsType` must name an export of THIS method's output, and a
49
+ * session carries exactly its granted operations.
50
+ */
51
+ async getTypeScriptTypes() {
52
+ return renderTierSessionTypes(this.#tier());
53
+ }
54
+ /**
55
+ * Open a governed session.
56
+ *
57
+ * The queue is not optional and not a decoration: every operation the returned object carries
58
+ * funnels through the one `invoke` closure, which submits actions to this queue and authorizes
59
+ * observations against it. The tier policy underneath is the FLOOR, so an operation the policy
60
+ * never granted is absent from the object rather than something the queue has to refuse.
61
+ *
62
+ * The queue passed here is OWNED by the session that comes back: it is released, along with
63
+ * every action that session left undecided, when the session is disposed. A caller reaching this
64
+ * over RPC therefore hands in a reference of its own rather than the parameter it received (see
65
+ * `resource.ts`), because the parameter's lifetime ends when this call returns and the session's
66
+ * does not.
67
+ */
68
+ async startSession(approvalQueue) {
69
+ const gatekeeper = this.#gatekeeper();
70
+ const accountId = this.#props.accountId;
71
+ return gatekeeper.capabilityForAccount(accountId, queueGovernance({
72
+ queue: approvalQueue,
73
+ ledger: this.#ledger.openSession(),
74
+ subject: {
75
+ accountId,
76
+ tier: gatekeeper.tierForAccount(accountId).name,
77
+ deployment: gatekeeper.deployment,
78
+ },
79
+ // Resolved per bind rather than once per session: the refusal for a deployment missing
80
+ // the export belongs to the call that needed it, and a session that binds no hook is one
81
+ // this Gatekeeper has no reason to refuse at all.
82
+ controllerFor: (props) => loopbackExport(this.#deps.exports, 'hookController', props),
83
+ }));
84
+ }
85
+ /**
86
+ * How many submitted actions this object is still holding, across every live session.
87
+ *
88
+ * Exposed for the same reason the ledger counts them: the ONE unbounded thing about a long-lived
89
+ * resource object is this set, and a count that does not fall back to zero when the sessions are
90
+ * gone is the leak rather than a slow day.
91
+ */
92
+ get pendingActionCount() {
93
+ return this.#ledger.pendingCount;
94
+ }
95
+ /**
96
+ * The action kinds this Gatekeeper may auto-apply, if the user opted into the kind.
97
+ *
98
+ * Derived from the same table and the same consequence reading `describeAction` stamps onto each
99
+ * submission, so a pre-approval UI listing kinds before any action exists and the `autoApprovable`
100
+ * flag on an action that has been submitted cannot disagree.
101
+ *
102
+ * TODAY THIS IS EMPTY, and that is the honest answer rather than a gap. The public surface
103
+ * annotates a consequence only where the stakes are real money or a merged pull request, so every
104
+ * other mutation is unannotated, and the table's documented reading of an unannotated mutation is
105
+ * that it is destructive. Offering those for unattended auto-approval would mean inverting that
106
+ * default here, which is precisely the misreading `resolveConsequence` exists to stop. If the
107
+ * surface ever states that a write is safe, it appears here with no further decision.
108
+ */
109
+ async getAutoApprovableActions() {
110
+ return this.#tier()
111
+ .granted.filter((binding) => !binding.readOnly)
112
+ .filter((binding) => (binding.consequence?.destructive ?? true) === false)
113
+ .map(actionKindOf);
114
+ }
115
+ /** The workspace approved an action: perform it, and hand the result to the waiting call. */
116
+ async applyAction(action) {
117
+ await this.#ledger.apply(action);
118
+ }
119
+ /** The workspace rejected an action: the waiting call throws and nothing is performed. */
120
+ async rejectAction(action) {
121
+ this.#ledger.reject(action);
122
+ }
123
+ /**
124
+ * Reverting is not something this Gatekeeper can do, which every action it submits already states
125
+ * (`implementsRevert: false`).
126
+ *
127
+ * It answers rather than throwing because the caller is the workspace UI on behalf of a person who
128
+ * wants their change undone: a message naming what they have to do themselves is the useful
129
+ * answer, where an exception would surface as a failed revert they might retry.
130
+ */
131
+ async revertAction(_action) {
132
+ return {
133
+ message: 'This Gatekeeper cannot revert a cat-factory operation. A started run is stopped from the ' +
134
+ 'board or with `tasks_stop`; a merged pull request is reverted in the repository, not here.',
135
+ canRetry: false,
136
+ };
137
+ }
138
+ /**
139
+ * Share this resource's observations onward, if the observer could have read them all directly.
140
+ *
141
+ * The contract's requirement, answered rather than declined: the observer names an account this
142
+ * deployment minted, its policy resolves that account's tier, and the share is admitted only
143
+ * when that tier reaches everything the tier THIS resource is bound at reaches. `sharing.ts`
144
+ * holds the tests and why each is the one the contract asks for, including why the account has
145
+ * to be recognised before its tier means anything.
146
+ *
147
+ * Nothing is recorded about an admitted observer, and that is a property of the rule rather than
148
+ * an omission: every accepted observer can read everything this resource could ever have
149
+ * observed, so there is never an observation to exclude from them afterwards.
150
+ */
151
+ async addObserver(id, user) {
152
+ const gatekeeper = this.#gatekeeper();
153
+ const observerAccount = await identifyObserver(user, {
154
+ recognize: (accountId) => gatekeeper.recognizesAccount(accountId),
155
+ });
156
+ assertObserverMaySee({
157
+ observerId: id,
158
+ observerAccount,
159
+ owner: this.#tier(),
160
+ observer: gatekeeper.tierForAccount(observerAccount),
161
+ });
162
+ }
163
+ /** Idempotent by contract: nothing is recorded about an observer, so nothing is forgotten. */
164
+ async removeObserver(_id) { }
165
+ #gatekeeper() {
166
+ return Gatekeeper.create(this.#env, this.#policy);
167
+ }
168
+ #tier() {
169
+ return this.#gatekeeper().tierForAccount(this.#props.accountId);
170
+ }
171
+ }
172
+ //# sourceMappingURL=resource-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-core.js","sourceRoot":"","sources":["../../src/os/resource-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { GatekeeperEnv } from '../env.js';
2
+ import type { GatekeeperPolicy } from '../policy/compile.js';
3
+ import type { ResourceObject } from './protocol.js';
4
+ import { type ResourceProps } from './resource-core.js';
5
+ export type { ResourceProps } from './resource-core.js';
6
+ /**
7
+ * Build the resource Durable Object class over a deployment's policy.
8
+ *
9
+ * A factory rather than a class, for the reason `createGatekeeperWorker` is one: the policy is the
10
+ * deployment's and arrives as an argument, so a class that imported one would own the file the
11
+ * operator is supposed to write.
12
+ */
13
+ export declare function createGatekeeperResource(options: {
14
+ policy: GatekeeperPolicy;
15
+ }): new (ctx: DurableObjectState<ResourceProps>, env: GatekeeperEnv) => ResourceObject;
16
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/os/resource.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAkD,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnG,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAErE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,gBAAgB,CAAA;CACzB,GAAG,KAAK,GAAG,EAAE,kBAAkB,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,aAAa,KAAK,cAAc,CAqDrF"}
@@ -0,0 +1,70 @@
1
+ // The per-resource object the workspace binds: a Durable Object serving one paired cat-factory
2
+ // workspace to one account.
3
+ //
4
+ // WHAT A RESOURCE IS, decided here and recorded in the initiative tracker: the PAIRED cat-factory
5
+ // WORKSPACE, named by a URLPattern over the deployment origin. It follows from the credential
6
+ // rather than being a modelling preference. This Worker holds one provisioning key, a cat-factory
7
+ // key is scoped to exactly one workspace, and `STATE` is already keyed on the deployment origin for
8
+ // the same reason. So one Gatekeeper Worker serves one resource, and an OS deployment that wants
9
+ // two workspaces runs two Gatekeepers with two bindings, which is also the only arrangement in
10
+ // which the two workspaces' credentials sit in different secret stores.
11
+ //
12
+ // Everything below is a FACADE. The policy compilation, the key broker, the durable state and the
13
+ // approval answerers are the same single implementation the `/rpc` door reaches; what differs is
14
+ // the door, and the governance that door brings with it. This file is the SHELL: it supplies
15
+ // `ctx.props` and holds one `ResourceCore`, which is where the behaviour lives.
16
+ import { DurableObject } from 'cloudflare:workers';
17
+ import { holdQueue } from './queue.js';
18
+ import { ResourceCore } from './resource-core.js';
19
+ /**
20
+ * Build the resource Durable Object class over a deployment's policy.
21
+ *
22
+ * A factory rather than a class, for the reason `createGatekeeperWorker` is one: the policy is the
23
+ * deployment's and arrives as an argument, so a class that imported one would own the file the
24
+ * operator is supposed to write.
25
+ */
26
+ export function createGatekeeperResource(options) {
27
+ const { policy } = options;
28
+ return class CatFactoryResource extends DurableObject {
29
+ // ONE core for the object's lifetime, because the action ledger inside it is what a later
30
+ // `applyAction` settles: a core rebuilt per call would have forgotten the action the decision
31
+ // is about. Field initializers run after the base constructor, so `ctx` and `env` are set.
32
+ //
33
+ // The exports bag is handed down because this shell is the only thing that has one: a hook's
34
+ // controller is one of the Worker's own named exports, resolved against the DEPLOYMENT's entry
35
+ // module, and the core is deliberately drivable without a Durable Object at all.
36
+ #core = new ResourceCore(this.env, policy, this.ctx.props, {
37
+ exports: this.ctx.exports,
38
+ });
39
+ async describe() {
40
+ return this.#core.describe();
41
+ }
42
+ async getTypeScriptTypes() {
43
+ return this.#core.getTypeScriptTypes();
44
+ }
45
+ // The one method where being the SHELL is not delegation: this is where the RPC boundary is,
46
+ // so this is where the queue's lifetime is taken over from the call that carried it in.
47
+ async startSession(approvalQueue) {
48
+ return this.#core.startSession(holdQueue(approvalQueue));
49
+ }
50
+ async getAutoApprovableActions() {
51
+ return this.#core.getAutoApprovableActions();
52
+ }
53
+ async applyAction(action) {
54
+ return this.#core.applyAction(action);
55
+ }
56
+ async rejectAction(action) {
57
+ return this.#core.rejectAction(action);
58
+ }
59
+ async revertAction(action) {
60
+ return this.#core.revertAction(action);
61
+ }
62
+ async addObserver(id, user) {
63
+ return this.#core.addObserver(id, user);
64
+ }
65
+ async removeObserver(id) {
66
+ return this.#core.removeObserver(id);
67
+ }
68
+ };
69
+ }
70
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/os/resource.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,4BAA4B;AAC5B,EAAE;AACF,kGAAkG;AAClG,8FAA8F;AAC9F,kGAAkG;AAClG,oGAAoG;AACpG,iGAAiG;AACjG,+FAA+F;AAC/F,wEAAwE;AACxE,EAAE;AACF,kGAAkG;AAClG,iGAAiG;AACjG,6FAA6F;AAC7F,gFAAgF;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAIlD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAIrE;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAExC;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAE1B,OAAO,MAAM,kBAAmB,SAAQ,aAA2C;QACjF,0FAA0F;QAC1F,8FAA8F;QAC9F,2FAA2F;QAC3F,EAAE;QACF,6FAA6F;QAC7F,+FAA+F;QAC/F,iFAAiF;QACxE,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;YAClE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO;SAC1B,CAAC,CAAA;QAEF,KAAK,CAAC,QAAQ;YACZ,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAA;QAC9B,CAAC;QAED,KAAK,CAAC,kBAAkB;YACtB,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAA;QACxC,CAAC;QAED,6FAA6F;QAC7F,wFAAwF;QACxF,KAAK,CAAC,YAAY,CAAC,aAA4B;YAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAA;QAC1D,CAAC;QAED,KAAK,CAAC,wBAAwB;YAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAA;QAC9C,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,MAAc;YAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QACvC,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;QACxC,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;QACxC,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,EAAU,EAAE,IAAa;YACzC,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QACzC,CAAC;QAED,KAAK,CAAC,cAAc,CAAC,EAAU;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;QACtC,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { SupportedResource } from './protocol.js';
2
+ /**
3
+ * The single resource: the paired cat-factory workspace, named by a pattern over its origin.
4
+ *
5
+ * The pattern is anchored on the deployment's ORIGIN with a wildcard path, which is what makes a
6
+ * board URL a person pastes (`https://cat-factory.example.com/w/…`) bind to this Gatekeeper. It is
7
+ * not `grantable`: there is nothing to grant separately, because the account's access is the
8
+ * provisioning key this Worker already holds.
9
+ */
10
+ export declare function supportedResourceFor(deployment: string): SupportedResource;
11
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/os/resources.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEtD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAW1E"}
@@ -0,0 +1,26 @@
1
+ // What this Gatekeeper serves, as the workspace's own resource vocabulary.
2
+ //
3
+ // One function, in a file of its own, because three callers need the SAME answer and a second
4
+ // spelling of the URL pattern would be a resource an account advertises and a bind cannot match:
5
+ // the vendor lists it, the account lists it and matches a URL against it, and the resource object
6
+ // describes itself with it.
7
+ /**
8
+ * The single resource: the paired cat-factory workspace, named by a pattern over its origin.
9
+ *
10
+ * The pattern is anchored on the deployment's ORIGIN with a wildcard path, which is what makes a
11
+ * board URL a person pastes (`https://cat-factory.example.com/w/…`) bind to this Gatekeeper. It is
12
+ * not `grantable`: there is nothing to grant separately, because the account's access is the
13
+ * provisioning key this Worker already holds.
14
+ */
15
+ export function supportedResourceFor(deployment) {
16
+ const origin = new URL(deployment).origin;
17
+ return {
18
+ urlPattern: `${origin}/*`,
19
+ title: 'cat-factory workspace',
20
+ description: 'The cat-factory workspace this Gatekeeper is paired with: file tasks, start runs, watch ' +
21
+ 'them, and answer the decisions they park on. One Gatekeeper serves one workspace, because ' +
22
+ 'the provisioning key it holds is scoped to one.',
23
+ grantable: false,
24
+ };
25
+ }
26
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/os/resources.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,8FAA8F;AAC9F,iGAAiG;AACjG,kGAAkG;AAClG,4BAA4B;AAI5B;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACrD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAA;IACzC,OAAO;QACL,UAAU,EAAE,GAAG,MAAM,IAAI;QACzB,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,0FAA0F;YAC1F,4FAA4F;YAC5F,iDAAiD;QACnD,SAAS,EAAE,KAAK;KACjB,CAAA;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { CompiledTier } from '../policy/compile.js';
2
+ /** The type name a resource declares as its `tsType`, and the interface the `.d.ts` exports. */
3
+ export declare const SESSION_INTERFACE_NAME = "CatFactoryWorkspace";
4
+ /** Render the session `.d.ts` for one compiled tier. */
5
+ export declare function renderTierSessionTypes(tier: CompiledTier): string;
6
+ //# sourceMappingURL=session-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-types.d.ts","sourceRoot":"","sources":["../../src/os/session-types.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,gGAAgG;AAChG,eAAO,MAAM,sBAAsB,wBAAwB,CAAA;AAuF3D,wDAAwD;AACxD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAUjE"}
@@ -0,0 +1,110 @@
1
+ // The `.d.ts` a session serves through `getTypeScriptTypes()`, composed for one tier.
2
+ //
3
+ // The per-operation signatures are GENERATED (`@cat-factory/gatekeeper-bindings`'s
4
+ // `SESSION_METHOD_SIGNATURES`, rendered by `pnpm gen:sdk` from the same spec the bindings table
5
+ // comes from), so the types an agent codes against cannot describe a surface the deployment does
6
+ // not serve. What is composed here is the tier's own subset plus the reserved methods, because a
7
+ // session carries exactly what its policy granted: a file naming the whole surface would promise
8
+ // methods the object does not have.
9
+ //
10
+ // The reserved methods are written out here rather than generated because they are this package's,
11
+ // not the deployment's: they exist at exactly the same version as this file.
12
+ import { renderSessionTypes } from '@cat-factory/gatekeeper-bindings';
13
+ /** The type name a resource declares as its `tsType`, and the interface the `.d.ts` exports. */
14
+ export const SESSION_INTERFACE_NAME = 'CatFactoryWorkspace';
15
+ /**
16
+ * The methods every session carries whatever its policy: who the caller is, what they hold, what
17
+ * they do not, and the approval inbox.
18
+ *
19
+ * `withheld()` is the one worth reading twice. An agent that cannot tell "your policy hides this"
20
+ * from "no policy could grant this" from "ask for it another way" reports the wrong one to whoever
21
+ * has to fix it, which is why it is on the object rather than in a document.
22
+ */
23
+ const RESERVED_MEMBERS = [
24
+ ` /** Who this session acts as, and the policy tier that account resolved to. */
25
+ tier(): Promise<{ actorId: string; tier: string; description: string; keyScope: string }>
26
+ `,
27
+ ` /**
28
+ * Every operation this session carries, with the scope floor and consequence of each.
29
+ */
30
+ bindings(): Promise<
31
+ {
32
+ name: string
33
+ summary: string
34
+ minScope: string
35
+ readOnly: boolean
36
+ destructive: boolean
37
+ idempotent: boolean
38
+ pathParams: readonly string[]
39
+ queryParams: readonly { name: string; required: boolean }[]
40
+ hasBody: boolean
41
+ }[]
42
+ >
43
+ `,
44
+ ` /**
45
+ * Every operation this session does NOT carry, and why: \`not_in_policy\` and
46
+ * \`denied_by_policy\` are your operator's decision, \`above_key_scope\` needs a higher tier,
47
+ * and \`not_relayable\` cannot cross a session call at all (ask for it another way).
48
+ */
49
+ withheld(): Promise<{ name: string; reason: string; detail: string }[]>
50
+ `,
51
+ ` /** The approval cards the paired deployment has raised and this Gatekeeper still holds open. */
52
+ approvals_list(): Promise<unknown[]>
53
+ `,
54
+ ` /**
55
+ * What a card's run is ACTUALLY parked on now, with the verbs each park takes and whether this
56
+ * session holds the operation behind it. The card is a pointer; the run is the truth.
57
+ */
58
+ approvals_inspect(cardId: string): Promise<unknown>
59
+ `,
60
+ ` /**
61
+ * Answer a park. Three outcomes are distinguishable and all three matter: \`answered\` (the run
62
+ * is unparked), \`recorded\` (your vote counted, the quorum is unmet, the run is still parked)
63
+ * and \`stale\` (the run moved on).
64
+ */
65
+ approvals_answer(cardId: string, input: unknown): Promise<unknown>
66
+ `,
67
+ ` /** Every run this Gatekeeper has been pushed lifecycle events for. */
68
+ runs_watched(): Promise<unknown[]>
69
+ `,
70
+ ` /**
71
+ * Be pushed each approval card as it is raised or settled, instead of polling
72
+ * \`approvals_list()\`. The callback needs one method:
73
+ * \`onApprovalCard(card): Promise<void>\`.
74
+ *
75
+ * The workspace holds the registration and may ask a person before enabling it, so binding is
76
+ * not receiving: nothing arrives until it is enabled, and \`hooks_bound()\` is where that shows.
77
+ */
78
+ approvals_subscribe(callback: unknown): Promise<void>
79
+ `,
80
+ ` /**
81
+ * Be pushed each run lifecycle transition, instead of polling \`runs_watched()\`. The callback
82
+ * needs one method: \`onRunEvent(state): Promise<void>\`.
83
+ */
84
+ runs_subscribe(callback: unknown): Promise<void>
85
+ `,
86
+ ` /**
87
+ * Every hook this account has enabled, with what each has been pushed (\`deliveries\`), what it
88
+ * could not be pushed (\`missed\`), what the workspace's own side refused (\`failures\`) and
89
+ * whether it is still \`live\`.
90
+ *
91
+ * A hook goes quiet when this Gatekeeper's durable object is evicted between deliveries, since
92
+ * the workspace's callback source cannot be stored. That reads as \`live: false\` with a rising
93
+ * \`missed\`, and the remedy is to bind again; what was missed is still in
94
+ * \`approvals_list()\` and \`runs_watched()\`, which is why they remain the truth.
95
+ */
96
+ hooks_bound(): Promise<unknown[]>
97
+ `,
98
+ ];
99
+ /** Render the session `.d.ts` for one compiled tier. */
100
+ export function renderTierSessionTypes(tier) {
101
+ return renderSessionTypes({
102
+ interfaceName: SESSION_INTERFACE_NAME,
103
+ bindings: tier.granted.map((binding) => binding.name),
104
+ extraMembers: RESERVED_MEMBERS,
105
+ preamble: `// The session for policy tier \`${tier.name}\`: ${tier.description}\n` +
106
+ `// Calls are made with a per-account API key at scope \`${tier.keyScope}\`, and every one of\n` +
107
+ "// them passes through this workspace's approval queue.",
108
+ });
109
+ }
110
+ //# sourceMappingURL=session-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-types.js","sourceRoot":"","sources":["../../src/os/session-types.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,EAAE;AACF,mFAAmF;AACnF,gGAAgG;AAChG,iGAAiG;AACjG,iGAAiG;AACjG,iGAAiG;AACjG,oCAAoC;AACpC,EAAE;AACF,mGAAmG;AACnG,6EAA6E;AAE7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AAGrE,gGAAgG;AAChG,MAAM,CAAC,MAAM,sBAAsB,GAAG,qBAAqB,CAAA;AAE3D;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAAsB;IAC1C;;CAED;IACC;;;;;;;;;;;;;;;;CAgBD;IACC;;;;;;CAMD;IACC;;CAED;IACC;;;;;CAKD;IACC;;;;;;CAMD;IACC;;CAED;IACC;;;;;;;;;CASD;IACC;;;;;CAKD;IACC;;;;;;;;;;;CAWD;CACA,CAAA;AAED,wDAAwD;AACxD,MAAM,UAAU,sBAAsB,CAAC,IAAkB;IACvD,OAAO,kBAAkB,CAAC;QACxB,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACrD,YAAY,EAAE,gBAAgB;QAC9B,QAAQ,EACN,oCAAoC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,WAAW,IAAI;YACxE,2DAA2D,IAAI,CAAC,QAAQ,wBAAwB;YAChG,yDAAyD;KAC5D,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { CompiledTier } from '../policy/compile.js';
2
+ /** What the caller supplies so a claimed account can be checked against the ones this Gatekeeper made. */
3
+ export interface ObserverRecognition {
4
+ /** Whether this deployment minted the named account. Never a guess: an unknown id is refused. */
5
+ recognize: (accountId: string) => Promise<boolean>;
6
+ }
7
+ /**
8
+ * Resolve the account behind an observer's verifier, or refuse.
9
+ *
10
+ * The verifier is the contract's own identity token: another vendor's gatekeeper is handed one,
11
+ * and the only thing it carries is who its holder is. Ours answers `{ accountId }`, so a stub that
12
+ * answers anything else did not come from this vendor and cannot be resolved against this
13
+ * deployment's policy. Answering the right SHAPE is not the same as being one of ours, which is
14
+ * why the id is then checked against the accounts this deployment actually minted.
15
+ *
16
+ * What that does NOT establish is worth stating, because the rule above is only as strong as this:
17
+ * a verifier that names an account of ours is taken at its word. The stub is reached over RPC from
18
+ * whoever the workspace handed us, so proving the holder IS that account would take a challenge
19
+ * the published contract does not carry. What is closed here is the case that needs no
20
+ * impersonation at all, which was every honest viewer from every other vendor.
21
+ */
22
+ export declare function identifyObserver(user: unknown, deps: ObserverRecognition): Promise<string>;
23
+ /**
24
+ * Refuse the share unless the observer could have read all of it themselves.
25
+ *
26
+ * Takes the two COMPILED tiers rather than resolving them, so the rule is testable without a
27
+ * policy, a Worker or an account: what it decides is a comparison, and everything else is lookup.
28
+ */
29
+ export declare function assertObserverMaySee(deps: {
30
+ observerId: string;
31
+ observerAccount: string;
32
+ owner: CompiledTier;
33
+ observer: CompiledTier;
34
+ }): void;
35
+ //# sourceMappingURL=sharing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharing.d.ts","sourceRoot":"","sources":["../../src/os/sharing.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAUxD,0GAA0G;AAC1G,MAAM,WAAW,mBAAmB;IAClC,iGAAiG;IACjG,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsChG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,YAAY,CAAA;IACnB,QAAQ,EAAE,YAAY,CAAA;CACvB,GAAG,IAAI,CAqCP"}