@cat-factory/gatekeeper-worker 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -2
- package/dist/arguments.d.ts +18 -0
- package/dist/arguments.d.ts.map +1 -0
- package/dist/arguments.js +75 -0
- package/dist/arguments.js.map +1 -0
- package/dist/capability.d.ts +10 -0
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +39 -1
- package/dist/capability.js.map +1 -1
- package/dist/env.d.ts +10 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -1
- package/dist/errors.d.ts +20 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -1
- package/dist/gatekeeper.d.ts +31 -1
- package/dist/gatekeeper.d.ts.map +1 -1
- package/dist/gatekeeper.js +38 -8
- package/dist/gatekeeper.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/os/discoverability.d.ts +13 -1
- package/dist/os/discoverability.d.ts.map +1 -1
- package/dist/os/discoverability.js +23 -6
- package/dist/os/discoverability.js.map +1 -1
- package/dist/os/exports.d.ts +27 -0
- package/dist/os/exports.d.ts.map +1 -1
- package/dist/os/exports.js +25 -0
- package/dist/os/exports.js.map +1 -1
- package/dist/os/hook-controller.d.ts +14 -0
- package/dist/os/hook-controller.d.ts.map +1 -0
- package/dist/os/hook-controller.js +53 -0
- package/dist/os/hook-controller.js.map +1 -0
- package/dist/os/hooks.d.ts +200 -0
- package/dist/os/hooks.d.ts.map +1 -0
- package/dist/os/hooks.js +253 -0
- package/dist/os/hooks.js.map +1 -0
- package/dist/os/protocol.d.ts +43 -0
- package/dist/os/protocol.d.ts.map +1 -1
- package/dist/os/queue.d.ts +9 -0
- package/dist/os/queue.d.ts.map +1 -1
- package/dist/os/queue.js +44 -1
- package/dist/os/queue.js.map +1 -1
- package/dist/os/resource-core.d.ts +25 -10
- package/dist/os/resource-core.d.ts.map +1 -1
- package/dist/os/resource-core.js +31 -14
- package/dist/os/resource-core.js.map +1 -1
- package/dist/os/resource.d.ts.map +1 -1
- package/dist/os/resource.js +7 -1
- package/dist/os/resource.js.map +1 -1
- package/dist/os/session-types.d.ts.map +1 -1
- package/dist/os/session-types.js +28 -0
- package/dist/os/session-types.js.map +1 -1
- package/dist/os/sharing.d.ts +35 -0
- package/dist/os/sharing.d.ts.map +1 -0
- package/dist/os/sharing.js +135 -0
- package/dist/os/sharing.js.map +1 -0
- package/dist/os/vendor.d.ts +1 -1
- package/dist/os/vendor.d.ts.map +1 -1
- package/dist/os/vendor.js +8 -1
- package/dist/os/vendor.js.map +1 -1
- package/dist/state.d.ts +80 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +234 -6
- package/dist/state.js.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +4 -1
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
package/dist/os/hooks.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// PUSHING what the inbox already holds: the approval cards and run transitions a workspace would
|
|
2
|
+
// otherwise have to ask for.
|
|
3
|
+
//
|
|
4
|
+
// Nothing here is a new source of truth, and that is the whole design. A delivery arrives on the
|
|
5
|
+
// webhook, is verified, deduped and written to durable state, and only THEN is anything pushed:
|
|
6
|
+
// `approvals_list()` and `runs_watched()` go on answering the same question for a workspace that
|
|
7
|
+
// never bound a hook, and for one whose hook missed an event. So a hook is an accelerator over a
|
|
8
|
+
// projection, never the projection itself, and every failure mode below is safe in exactly that
|
|
9
|
+
// way: what a hook loses, a read still has.
|
|
10
|
+
//
|
|
11
|
+
// The lifecycle is the published contract's, and each step exists for a reason worth keeping:
|
|
12
|
+
//
|
|
13
|
+
// 1. A session calls `approvals_subscribe(callback)`. We mint a hook id, build a CONTROLLER of
|
|
14
|
+
// our own, and hand both the controller and the callback to `queue.bindHook`. We store
|
|
15
|
+
// NOTHING: the workspace may still have to ask a person, and a gatekeeper that wrote a row
|
|
16
|
+
// here would be holding registrations for hooks nobody ever approved.
|
|
17
|
+
// 2. The workspace approves and calls `enable(initiator, target)` on that controller. NOW there
|
|
18
|
+
// is state: the durable record, plus the initiator held live.
|
|
19
|
+
// 3. Each event calls `initiator.startHook()` for a FRESH callback and the queue that governs
|
|
20
|
+
// it, authorizes the delivery as the observation it is, and delivers.
|
|
21
|
+
// 4. `disable()` removes both halves. The contract asks for a permanent clean-up and means it.
|
|
22
|
+
//
|
|
23
|
+
// THE CALLBACK IS NEVER STORED, at any point. It is a parameter stub, so the runtime disposes it
|
|
24
|
+
// when the call it arrived on returns; storing one would leave a registration that looks live and
|
|
25
|
+
// throws on the first delivery, months after the mistake.
|
|
26
|
+
//
|
|
27
|
+
// THE INITIATOR IS HELD IN MEMORY, and that is a real limit rather than an oversight. A stub is a
|
|
28
|
+
// reference into another Worker and there is no way to write one to storage, so a Durable Object
|
|
29
|
+
// that is evicted between two deliveries keeps the record and loses the live half. That is why
|
|
30
|
+
// every record COUNTS its missed deliveries and why `hooks_bound()` publishes the count beside
|
|
31
|
+
// `live`: a workspace can see that its hook went quiet, and reconcile from the projection that
|
|
32
|
+
// never did. A silent stop would be the one failure this design cannot tolerate, because a
|
|
33
|
+
// workspace has no way to tell it from a deployment where nothing happened.
|
|
34
|
+
//
|
|
35
|
+
// So RE-BINDING IS THE DOCUMENTED REMEDY, and a registration is therefore keyed on where its
|
|
36
|
+
// deliveries land rather than on the id one bind minted (`registrationKey`). Re-arming a hook is
|
|
37
|
+
// the same registration coming back, not a second one beside the first.
|
|
38
|
+
import { describeError } from '../errors.js';
|
|
39
|
+
import { fenced } from '../markdown.js';
|
|
40
|
+
/**
|
|
41
|
+
* The two topics, as an exhaustive `Record`, so a third one cannot be half-added.
|
|
42
|
+
*
|
|
43
|
+
* A topic is a delivery FAMILY this Gatekeeper already receives and projects, never a new
|
|
44
|
+
* subscription upstream: what the platform sends is decided by `enroll()`, and a hook that pushed
|
|
45
|
+
* something the webhook does not carry would be a promise no delivery could keep.
|
|
46
|
+
*/
|
|
47
|
+
export const HOOK_TOPICS = {
|
|
48
|
+
approval_card: {
|
|
49
|
+
sessionMethod: 'approvals_subscribe',
|
|
50
|
+
callbackMethod: 'onApprovalCard',
|
|
51
|
+
title: 'Push cat-factory approval cards as they are raised',
|
|
52
|
+
description: 'Each time the paired cat-factory deployment reports that a run has parked on a human ' +
|
|
53
|
+
'decision, or that a card it raised has been settled elsewhere, the card is pushed to this ' +
|
|
54
|
+
'callback. It carries exactly what `approvals_list()` answers with, which stays available ' +
|
|
55
|
+
'and stays authoritative: a delivery missed while this hook was not live is still readable ' +
|
|
56
|
+
'there.',
|
|
57
|
+
},
|
|
58
|
+
run_event: {
|
|
59
|
+
sessionMethod: 'runs_subscribe',
|
|
60
|
+
callbackMethod: 'onRunEvent',
|
|
61
|
+
title: 'Push cat-factory run lifecycle transitions',
|
|
62
|
+
description: 'Each time the paired cat-factory deployment reports that a run has started, completed or ' +
|
|
63
|
+
'failed, the run’s latest state is pushed to this callback. It carries exactly what ' +
|
|
64
|
+
'`runs_watched()` answers with, which stays available and stays authoritative.',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
/** Every topic, for a caller that has to cover all of them. */
|
|
68
|
+
export const HOOK_TOPIC_NAMES = Object.keys(HOOK_TOPICS);
|
|
69
|
+
/**
|
|
70
|
+
* What IDENTIFIES a registration in storage: the place its deliveries land.
|
|
71
|
+
*
|
|
72
|
+
* Not the hook id, which is the wrong key for the one lifecycle a workspace is documented to run.
|
|
73
|
+
* The live half of a registration cannot be stored, so a durable object evicted between two
|
|
74
|
+
* deliveries keeps the record and loses the stub, and the remedy is to bind again. A bind mints a
|
|
75
|
+
* FRESH hook id, so a hook-id-keyed row made every one of those cycles a new row: the dead
|
|
76
|
+
* registration stayed forever, never live, counting a `missed` against every delivery for the rest
|
|
77
|
+
* of the deployment's life, and no reader could tell it from a hook that had genuinely gone quiet.
|
|
78
|
+
*
|
|
79
|
+
* Keying on the target makes re-binding what it reads as: the same registration, re-armed. The row
|
|
80
|
+
* is replaced, its counters carry forward (the `missed` count is the evidence the workspace acted
|
|
81
|
+
* on, so re-arming must not erase it), and the set of rows stays bounded by the gadgets a
|
|
82
|
+
* workspace actually runs rather than by how many times one was re-armed.
|
|
83
|
+
*
|
|
84
|
+
* The account comes first and is never the caller's to assert, so no target a workspace names can
|
|
85
|
+
* collide with another account's row; the remaining parts are escaped so a separator inside one of
|
|
86
|
+
* them cannot make two different targets share a key.
|
|
87
|
+
*/
|
|
88
|
+
export function registrationKey(record) {
|
|
89
|
+
return [
|
|
90
|
+
record.accountId,
|
|
91
|
+
record.topic,
|
|
92
|
+
record.target.workspaceId,
|
|
93
|
+
record.target.gadgetId === undefined ? '' : String(record.target.gadgetId),
|
|
94
|
+
]
|
|
95
|
+
.map((part) => encodeURIComponent(part))
|
|
96
|
+
.join(':');
|
|
97
|
+
}
|
|
98
|
+
/** What the approver is asked when a workspace binds a hook. */
|
|
99
|
+
export function describeHook(topic, subject) {
|
|
100
|
+
const definition = HOOK_TOPICS[topic];
|
|
101
|
+
return {
|
|
102
|
+
title: `${definition.title} (${subject.deployment})`,
|
|
103
|
+
description: `${definition.description}\n\nDeliveries are made for account \`${subject.accountId}\` at ` +
|
|
104
|
+
`policy tier \`${subject.tier}\`, and each one is authorized as an observation before it ` +
|
|
105
|
+
'is pushed.',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* What the queue is asked before ONE delivery is pushed.
|
|
110
|
+
*
|
|
111
|
+
* A hook delivery is an observation and is authorized as one, which the contract asks for and
|
|
112
|
+
* which is also the only reading that holds: the bytes are a card the paired deployment raised,
|
|
113
|
+
* and that they arrived here over a webhook rather than over a read is an implementation detail of
|
|
114
|
+
* how they got here. The refusal path is what makes it matter: a workspace that has withdrawn a
|
|
115
|
+
* person's access can stop the push without this Gatekeeper having to be told.
|
|
116
|
+
*/
|
|
117
|
+
export function describeHookDelivery(payload, record) {
|
|
118
|
+
const subject = payload.topic === 'approval_card'
|
|
119
|
+
? `The approval card \`${payload.card.cardId}\` raised for run \`${payload.card.runId}\`, ` +
|
|
120
|
+
`titled:\n\n${fenced(payload.card.title, '')}`
|
|
121
|
+
: `Run \`${payload.state.runId}\` reported \`${payload.state.event}\`.`;
|
|
122
|
+
return {
|
|
123
|
+
title: `${HOOK_TOPICS[payload.topic].title} (${record.deployment})`,
|
|
124
|
+
description: `${subject}\n\nPushed to a hook this workspace enabled for account ` +
|
|
125
|
+
`\`${record.accountId}\` at policy tier \`${record.tier}\`, from the record of what the ` +
|
|
126
|
+
`paired deployment at ${record.deployment} delivered.`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Take a reference to a stub that outlives the call it arrived on.
|
|
131
|
+
*
|
|
132
|
+
* The same loan rule `holdQueue` documents, arriving on the other parameter the contract hands
|
|
133
|
+
* over: the runtime disposes a parameter stub when the method returns, and an initiator kept for
|
|
134
|
+
* the next delivery is used long after that. The optional call is the in-process case, where the
|
|
135
|
+
* "stub" is an ordinary object with nothing to duplicate.
|
|
136
|
+
*/
|
|
137
|
+
export function holdInitiator(initiator) {
|
|
138
|
+
const stub = initiator;
|
|
139
|
+
return typeof stub.dup === 'function' ? stub.dup() : initiator;
|
|
140
|
+
}
|
|
141
|
+
/** Give back a held reference. Paired with {@link holdInitiator} and kept beside it. */
|
|
142
|
+
export function releaseInitiator(initiator) {
|
|
143
|
+
;
|
|
144
|
+
initiator[Symbol.dispose]?.();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* How long one workspace has to take one push before it is counted as a failure.
|
|
148
|
+
*
|
|
149
|
+
* A hook delivery is a call into somebody else's Worker, and the failure this bounds is the one
|
|
150
|
+
* with no natural end: a workspace that accepts the connection and never answers. Unbounded, one
|
|
151
|
+
* such hook holds the fan-out (and, on the receiver, the invocation carrying it) until the runtime
|
|
152
|
+
* kills it, and the counter update that would have SAID so never lands, so the registration reads
|
|
153
|
+
* as one nothing was ever pushed to.
|
|
154
|
+
*/
|
|
155
|
+
const PUSH_TIMEOUT_MS = 10_000;
|
|
156
|
+
/**
|
|
157
|
+
* Push one payload to one enabled hook, and report what that did.
|
|
158
|
+
*
|
|
159
|
+
* Every outcome is a REPORT rather than a throw, because the caller is a fan-out on behalf of a
|
|
160
|
+
* delivery whose record has already committed: a workspace that refuses, breaks or hangs costs a
|
|
161
|
+
* notification, and must never cost the acknowledgement the platform's retry is protecting.
|
|
162
|
+
*/
|
|
163
|
+
export async function pushToHook(payload, record, initiator) {
|
|
164
|
+
if (initiator === undefined)
|
|
165
|
+
return { outcome: 'stale' };
|
|
166
|
+
try {
|
|
167
|
+
await withDeadline(deliverThrough(initiator, payload, record), PUSH_TIMEOUT_MS);
|
|
168
|
+
return { outcome: 'delivered' };
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return { outcome: 'failed', error: describeError(error) };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Fold one push's outcome onto the record as it stands NOW.
|
|
176
|
+
*
|
|
177
|
+
* Pure, and takes the current record rather than the one the push was described from, so a caller
|
|
178
|
+
* can re-read between the two. `lastError` is cleared by a delivery on purpose: it is what a
|
|
179
|
+
* reader acts on beside `failures`, and a stale one beside a hook that has since recovered points
|
|
180
|
+
* at a fix nobody needs to make.
|
|
181
|
+
*/
|
|
182
|
+
export function applyPushOutcome(record, result, now) {
|
|
183
|
+
if (result.outcome === 'stale')
|
|
184
|
+
return { ...record, missed: record.missed + 1 };
|
|
185
|
+
if (result.outcome === 'failed') {
|
|
186
|
+
return { ...record, failures: record.failures + 1, lastError: result.error };
|
|
187
|
+
}
|
|
188
|
+
return { ...record, deliveries: record.deliveries + 1, lastDeliveryAt: now, lastError: null };
|
|
189
|
+
}
|
|
190
|
+
/** One delivery, through a callback minted for it and released with it. */
|
|
191
|
+
async function deliverThrough(initiator, payload, record) {
|
|
192
|
+
const started = await initiator.startHook();
|
|
193
|
+
try {
|
|
194
|
+
await started.approvalQueue.authorizeObservation(describeHookDelivery(payload, record));
|
|
195
|
+
await callBack(started.callback, payload);
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
releaseStarted(started);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Give up on a push that never answers, and say that is what happened.
|
|
203
|
+
*
|
|
204
|
+
* The timer is cleared on both paths: a Worker invocation stays alive while one is outstanding, so
|
|
205
|
+
* leaving them behind would hold every delivery's invocation open for the timeout even when every
|
|
206
|
+
* push answered at once.
|
|
207
|
+
*/
|
|
208
|
+
async function withDeadline(work, timeoutMs) {
|
|
209
|
+
let timer;
|
|
210
|
+
const expiry = new Promise((_resolve, reject) => {
|
|
211
|
+
timer = setTimeout(() => reject(new Error(`The workspace did not answer this hook delivery within ${timeoutMs}ms, so it was ` +
|
|
212
|
+
'counted as a failure rather than waited on.')), timeoutMs);
|
|
213
|
+
});
|
|
214
|
+
try {
|
|
215
|
+
return await Promise.race([work, expiry]);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
if (timer !== undefined)
|
|
219
|
+
clearTimeout(timer);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Call the topic's method on the workspace's callback.
|
|
224
|
+
*
|
|
225
|
+
* A callback with no such method is a FAILURE that says so, rather than a push that quietly does
|
|
226
|
+
* nothing: the workspace implements the interface this package publishes in the session types, and
|
|
227
|
+
* a mismatch between the two is exactly the thing a count of failures should make visible.
|
|
228
|
+
*/
|
|
229
|
+
async function callBack(callback, payload) {
|
|
230
|
+
const method = HOOK_TOPICS[payload.topic].callbackMethod;
|
|
231
|
+
if (callback === null || callback === undefined) {
|
|
232
|
+
throw new Error('This hook was started with no callback, so nothing could be delivered to it.');
|
|
233
|
+
}
|
|
234
|
+
const target = callback;
|
|
235
|
+
// Two things about a stub decide the shape of these three lines, and both read as pedantry until
|
|
236
|
+
// they bite. A stub answers EVERY property, so the absent-method check can only catch a plain
|
|
237
|
+
// object (which is the in-process case, and the one where a helpful message is worth having);
|
|
238
|
+
// for a real callback the missing method surfaces from the far side, as it should. And the
|
|
239
|
+
// invocation is DIRECT rather than through `Function.prototype.call`, because `deliver.call(…)`
|
|
240
|
+
// on a stub asks the far side for an operation named `onApprovalCard.call`.
|
|
241
|
+
if (target[method] === undefined) {
|
|
242
|
+
throw new Error(`The callback this hook was started with has no ${method}() method, so nothing could be ` +
|
|
243
|
+
'delivered to it.');
|
|
244
|
+
}
|
|
245
|
+
await target[method](payload.topic === 'approval_card' ? payload.card : payload.state);
|
|
246
|
+
}
|
|
247
|
+
/** Release both stubs one `startHook()` handed over. Neither outlives the delivery. */
|
|
248
|
+
function releaseStarted(started) {
|
|
249
|
+
;
|
|
250
|
+
started.callback?.[Symbol.dispose]?.();
|
|
251
|
+
started.approvalQueue?.[Symbol.dispose]?.();
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/os/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/os/protocol.d.ts
CHANGED
|
@@ -90,6 +90,41 @@ export interface ObservationAuthorizer {
|
|
|
90
90
|
/** Resolves when the read is permitted, and THROWS when it is not. */
|
|
91
91
|
authorizeObservation(description: ObservationDescription): Promise<void>;
|
|
92
92
|
}
|
|
93
|
+
/** What an approver is told about a hook the workspace is being asked to enable. */
|
|
94
|
+
export interface HookDescription {
|
|
95
|
+
title: string;
|
|
96
|
+
description: string;
|
|
97
|
+
}
|
|
98
|
+
/** Where an enabled hook's deliveries land, as the workspace names it. */
|
|
99
|
+
export interface HookTargetMetadata {
|
|
100
|
+
workspaceId: string;
|
|
101
|
+
gadgetId?: number;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* What the workspace turns a bound hook on and off through. Implemented on THIS side.
|
|
105
|
+
*
|
|
106
|
+
* A hook is not live when it is bound: the workspace may have to ask a person first, and it calls
|
|
107
|
+
* `enable` if and when they say yes. The initiator it hands over is the ONLY thing worth keeping,
|
|
108
|
+
* and `disable` means every trace of the registration goes.
|
|
109
|
+
*/
|
|
110
|
+
export interface HookController {
|
|
111
|
+
enable(initiator: HookInitiator, target: HookTargetMetadata): Promise<void>;
|
|
112
|
+
disable(): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* What an enabled hook is delivered THROUGH: a fresh callback per event, never a stored one.
|
|
116
|
+
*
|
|
117
|
+
* The callback handed to `bindHook` is a loan like every other parameter stub, so the contract
|
|
118
|
+
* gives the initiator instead: ask for a callback when there is something to deliver, and get an
|
|
119
|
+
* approval queue with it, because a delivery is a read of the paired deployment and has to be
|
|
120
|
+
* authorized exactly as `approvals_list()` is.
|
|
121
|
+
*/
|
|
122
|
+
export interface HookInitiator {
|
|
123
|
+
startHook(): Promise<{
|
|
124
|
+
callback: unknown;
|
|
125
|
+
approvalQueue: ObservationAuthorizer;
|
|
126
|
+
}>;
|
|
127
|
+
}
|
|
93
128
|
/**
|
|
94
129
|
* What the OS hands to `startSession`: the chokepoint every operation passes through.
|
|
95
130
|
*
|
|
@@ -99,6 +134,14 @@ export interface ObservationAuthorizer {
|
|
|
99
134
|
*/
|
|
100
135
|
export interface ApprovalQueue extends ObservationAuthorizer {
|
|
101
136
|
submitAction(action: number, description: ActionDescription): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Register a persistent callback, which the workspace holds and may not enable at once.
|
|
139
|
+
*
|
|
140
|
+
* The gatekeeper hands over a CONTROLLER of its own rather than keeping the callback: the
|
|
141
|
+
* callback is a parameter stub whose lifetime ends with this call, and what has to survive is
|
|
142
|
+
* the registration. Enabling arrives later on that controller.
|
|
143
|
+
*/
|
|
144
|
+
bindHook(controller: unknown, callback: unknown, description: HookDescription): Promise<void>;
|
|
102
145
|
}
|
|
103
146
|
/** What a `GATEKEEPER_*` service binding reaches. */
|
|
104
147
|
export interface VendorEntrypoint {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/os/protocol.ts"],"names":[],"mappings":"AAqBA,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yFAAyF;IACzF,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAED,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAA;CACtC;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,0FAA0F;IAC1F,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,oBAAoB,EAAE,MAAM,CAAA;IAC5B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,gBAAgB,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,yFAAyF;IACzF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,oBAAoB,CAAC,WAAW,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzE;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAc,SAAQ,qBAAqB;IAC1D,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/os/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/os/queue.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SessionGovernance } from '../capability.js';
|
|
2
2
|
import { type CallSubject } from './descriptions.js';
|
|
3
|
+
import { type HookControllerProps } from './hooks.js';
|
|
3
4
|
import type { ApprovalQueue } from './protocol.js';
|
|
4
5
|
/**
|
|
5
6
|
* One session's view of the ledger: what it may register, and the end of everything it registered.
|
|
@@ -86,5 +87,13 @@ export declare function queueGovernance(deps: {
|
|
|
86
87
|
queue: ApprovalQueue;
|
|
87
88
|
ledger: LedgerSession;
|
|
88
89
|
subject: CallSubject;
|
|
90
|
+
/**
|
|
91
|
+
* Build the controller for one hook, which is this Worker's own `CatFactoryHookController`
|
|
92
|
+
* export imbued with the registration's identity.
|
|
93
|
+
*
|
|
94
|
+
* Supplied by the caller rather than built here because only the resource object can reach
|
|
95
|
+
* `ctx.exports`, and a session that could not build one is a session on a door with no hooks.
|
|
96
|
+
*/
|
|
97
|
+
controllerFor: (props: HookControllerProps) => unknown;
|
|
89
98
|
}): SessionGovernance;
|
|
90
99
|
//# sourceMappingURL=queue.d.ts.map
|
package/dist/os/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/os/queue.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAclD;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,QAAQ,CACN,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC9B;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;IAC5C;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,gFAAgF;IAChF,GAAG,IAAI,IAAI,CAAA;CACZ;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;;IAKvB,qFAAqF;IACrF,WAAW,IAAI,aAAa,CAO3B;IAED;;;;;;;;;OASG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrC;IAED,4EAA4E;IAC5E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAQvB;IAED;;;;;;OAMG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;CAiDF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAG7D;AAaD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,KAAK,EAAE,aAAa,CAAA;IACpB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/os/queue.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzF,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAclD;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,QAAQ,CACN,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC9B;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;IAC5C;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,gFAAgF;IAChF,GAAG,IAAI,IAAI,CAAA;CACZ;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;;IAKvB,qFAAqF;IACrF,WAAW,IAAI,aAAa,CAO3B;IAED;;;;;;;;;OASG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrC;IAED,4EAA4E;IAC5E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAQvB;IAED;;;;;;OAMG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;CAiDF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAG7D;AAaD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,KAAK,EAAE,aAAa,CAAA;IACpB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,WAAW,CAAA;IACpB;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAA;CACvD,GAAG,iBAAiB,CAgGpB"}
|
package/dist/os/queue.js
CHANGED
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
// for live sessions only. Without that, an approval card nobody ever answered pinned its entry for
|
|
29
29
|
// the object's whole lifetime, and `#take`'s "the session that submitted it has ended" was a
|
|
30
30
|
// sentence nothing made true.
|
|
31
|
-
import { GatekeeperError } from '../errors.js';
|
|
31
|
+
import { describeError, GatekeeperError } from '../errors.js';
|
|
32
32
|
import { describeAction, describeObservation } from './descriptions.js';
|
|
33
|
+
import { describeHook, HOOK_TOPICS } from './hooks.js';
|
|
33
34
|
/**
|
|
34
35
|
* The submitted-but-undecided actions of one resource object, and the decisions that settle them.
|
|
35
36
|
*
|
|
@@ -185,6 +186,48 @@ export function queueGovernance(deps) {
|
|
|
185
186
|
}
|
|
186
187
|
return (await settled);
|
|
187
188
|
},
|
|
189
|
+
/**
|
|
190
|
+
* Hand the workspace a controller and the callback, and keep NEITHER.
|
|
191
|
+
*
|
|
192
|
+
* Everything about the registration rides the controller's props, so this call leaves no
|
|
193
|
+
* state behind: the workspace may take days to approve the hook, or never approve it, and a
|
|
194
|
+
* row written here would be a registration for something nobody enabled. What comes back is
|
|
195
|
+
* nothing at all, because there is nothing to report yet; `hooks_bound()` answers once the
|
|
196
|
+
* workspace has enabled it.
|
|
197
|
+
*/
|
|
198
|
+
async subscribe(topic, callback) {
|
|
199
|
+
// Reachable only in process, and kept for exactly that: an embedding suite hands over a
|
|
200
|
+
// plain object, where a missing method is a mistake worth naming. It CANNOT catch a
|
|
201
|
+
// workspace whose queue predates hooks, because a stub answers every property (the same
|
|
202
|
+
// fact `callBack` turns on), so `typeof` reads `function` for a method the far side does not
|
|
203
|
+
// implement. That case arrives below, as a failure from the far side.
|
|
204
|
+
if (typeof deps.queue.bindHook !== 'function') {
|
|
205
|
+
throw new GatekeeperError('hooks_unavailable', 'The approval queue this session was opened with offers no bindHook(), so this ' +
|
|
206
|
+
'workspace cannot hold a callback for us. Read `approvals_list()` and ' +
|
|
207
|
+
'`runs_watched()` instead: they carry exactly what a hook would push.');
|
|
208
|
+
}
|
|
209
|
+
const props = {
|
|
210
|
+
hookId: `hook_${crypto.randomUUID().replaceAll('-', '')}`,
|
|
211
|
+
topic,
|
|
212
|
+
accountId: deps.subject.accountId,
|
|
213
|
+
tier: deps.subject.tier,
|
|
214
|
+
deployment: deps.subject.deployment,
|
|
215
|
+
};
|
|
216
|
+
try {
|
|
217
|
+
await deps.queue.bindHook(deps.controllerFor(props), callback, describeHook(topic, deps.subject));
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
// A workspace whose queue has no `bindHook` and a person who declined the registration
|
|
221
|
+
// both surface here, and this Gatekeeper cannot tell them apart: the contract offers no
|
|
222
|
+
// way to ask whether hooks are servable, and the two failures cross the wire the same way.
|
|
223
|
+
// So the cause is reported VERBATIM rather than sorted into a guess, because it is the one
|
|
224
|
+
// thing that distinguishes them and the two need opposite fixes.
|
|
225
|
+
throw new GatekeeperError('hook_bind_refused', `This workspace did not take the ${HOOK_TOPICS[topic].sessionMethod}() binding ` +
|
|
226
|
+
`(${describeError(error)}). Either its approval queue serves no hooks, or the ` +
|
|
227
|
+
'registration was declined. `approvals_list()` and `runs_watched()` answer exactly ' +
|
|
228
|
+
'what the hook would have pushed, and go on doing so.');
|
|
229
|
+
}
|
|
230
|
+
},
|
|
188
231
|
close() {
|
|
189
232
|
// Order matters: the actions are refused while the queue is still ours to hold, so an
|
|
190
233
|
// awaiting caller is told the session ended rather than left on a promise whose only route
|
package/dist/os/queue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/os/queue.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,mGAAmG;AACnG,mGAAmG;AACnG,oGAAoG;AACpG,iGAAiG;AACjG,8EAA8E;AAC9E,EAAE;AACF,mFAAmF;AACnF,EAAE;AACF,iGAAiG;AACjG,qGAAqG;AACrG,6FAA6F;AAC7F,sCAAsC;AACtC,EAAE;AACF,qGAAqG;AACrG,kGAAkG;AAClG,oGAAoG;AACpG,mGAAmG;AACnG,yFAAyF;AACzF,8DAA8D;AAC9D,EAAE;AACF,gGAAgG;AAChG,gGAAgG;AAChG,8FAA8F;AAC9F,iGAAiG;AACjG,iGAAiG;AACjG,mGAAmG;AACnG,6FAA6F;AAC7F,8BAA8B;AAI9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/os/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,10 +16,22 @@ export interface ResourceProps {
|
|
|
16
16
|
/** The account this resource is bound for. Every key minted through it is stamped with this. */
|
|
17
17
|
accountId: string;
|
|
18
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
|
+
}
|
|
19
31
|
/** One bound resource: the session it opens, its types, and the action lifecycle behind it. */
|
|
20
32
|
export declare class ResourceCore implements ResourceObject {
|
|
21
33
|
#private;
|
|
22
|
-
constructor(env: GatekeeperEnv, policy: GatekeeperPolicy, props: ResourceProps);
|
|
34
|
+
constructor(env: GatekeeperEnv, policy: GatekeeperPolicy, props: ResourceProps, deps: ResourceDependencies);
|
|
23
35
|
describe(): Promise<ResourceDescription>;
|
|
24
36
|
/**
|
|
25
37
|
* The session's own types, rendered for the tier this account holds.
|
|
@@ -84,17 +96,20 @@ export declare class ResourceCore implements ResourceObject {
|
|
|
84
96
|
canRetry: false;
|
|
85
97
|
}>;
|
|
86
98
|
/**
|
|
87
|
-
*
|
|
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.
|
|
88
106
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* observed data) needs a tier for a viewer this deployment's policy has never named. A share
|
|
93
|
-
* blocked loudly beats an observation leaked quietly, so the refusal stands until there is a rule
|
|
94
|
-
* worth writing down.
|
|
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.
|
|
95
110
|
*/
|
|
96
|
-
addObserver(id: string,
|
|
97
|
-
/** Idempotent by contract: nothing
|
|
111
|
+
addObserver(id: string, user: unknown): Promise<void>;
|
|
112
|
+
/** Idempotent by contract: nothing is recorded about an observer, so nothing is forgotten. */
|
|
98
113
|
removeObserver(_id: string): Promise<void>;
|
|
99
114
|
}
|
|
100
115
|
//# sourceMappingURL=resource-core.d.ts.map
|
|
@@ -1 +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;
|
|
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"}
|
package/dist/os/resource-core.js
CHANGED
|
@@ -11,21 +11,24 @@
|
|
|
11
11
|
// Holding ONE per object is what the action ledger needs: the workspace settles an action by
|
|
12
12
|
// calling `applyAction` on the resource, so a core rebuilt per call would lose the pending action
|
|
13
13
|
// the decision is about.
|
|
14
|
-
import { GatekeeperError } from '../errors.js';
|
|
15
14
|
import { Gatekeeper } from '../gatekeeper.js';
|
|
16
15
|
import { actionKindOf } from './descriptions.js';
|
|
16
|
+
import { loopbackExport } from './exports.js';
|
|
17
17
|
import { ActionLedger, queueGovernance } from './queue.js';
|
|
18
|
+
import { assertObserverMaySee, identifyObserver } from './sharing.js';
|
|
18
19
|
import { renderTierSessionTypes, SESSION_INTERFACE_NAME } from './session-types.js';
|
|
19
20
|
/** One bound resource: the session it opens, its types, and the action lifecycle behind it. */
|
|
20
21
|
export class ResourceCore {
|
|
21
22
|
#env;
|
|
22
23
|
#policy;
|
|
23
24
|
#props;
|
|
25
|
+
#deps;
|
|
24
26
|
#ledger = new ActionLedger();
|
|
25
|
-
constructor(env, policy, props) {
|
|
27
|
+
constructor(env, policy, props, deps) {
|
|
26
28
|
this.#env = env;
|
|
27
29
|
this.#policy = policy;
|
|
28
30
|
this.#props = props;
|
|
31
|
+
this.#deps = deps;
|
|
29
32
|
}
|
|
30
33
|
async describe() {
|
|
31
34
|
const tier = this.#tier();
|
|
@@ -73,6 +76,10 @@ export class ResourceCore {
|
|
|
73
76
|
tier: gatekeeper.tierForAccount(accountId).name,
|
|
74
77
|
deployment: gatekeeper.deployment,
|
|
75
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),
|
|
76
83
|
}));
|
|
77
84
|
}
|
|
78
85
|
/**
|
|
@@ -129,21 +136,31 @@ export class ResourceCore {
|
|
|
129
136
|
};
|
|
130
137
|
}
|
|
131
138
|
/**
|
|
132
|
-
*
|
|
139
|
+
* Share this resource's observations onward, if the observer could have read them all directly.
|
|
133
140
|
*
|
|
134
|
-
* The contract
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
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.
|
|
140
150
|
*/
|
|
141
|
-
async addObserver(id,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
+
});
|
|
145
162
|
}
|
|
146
|
-
/** Idempotent by contract: nothing
|
|
163
|
+
/** Idempotent by contract: nothing is recorded about an observer, so nothing is forgotten. */
|
|
147
164
|
async removeObserver(_id) { }
|
|
148
165
|
#gatekeeper() {
|
|
149
166
|
return Gatekeeper.create(this.#env, this.#policy);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-core.js","sourceRoot":"","sources":["../../src/os/resource-core.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,EAAE;AACF,6FAA6F;AAC7F,oGAAoG;AACpG,mGAAmG;AACnG,8FAA8F;AAC9F,8FAA8F;AAC9F,mGAAmG;AACnG,mCAAmC;AACnC,EAAE;AACF,6FAA6F;AAC7F,kGAAkG;AAClG,yBAAyB;AAGzB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"resource-core.js","sourceRoot":"","sources":["../../src/os/resource-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +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,
|
|
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"}
|