@hediet/linkrpc 0.0.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.
Files changed (39) hide show
  1. package/README.md +383 -0
  2. package/dist/chunks/_empty-crypto-Bi0tGx5K.js +8 -0
  3. package/dist/chunks/boundedTrafficSubscription-1L592xc7.js +1126 -0
  4. package/dist/chunks/boundedTrafficSubscription-1L592xc7.js.map +1 -0
  5. package/dist/chunks/hub.interfaces-BzWfsVT2.js +526 -0
  6. package/dist/chunks/hub.interfaces-BzWfsVT2.js.map +1 -0
  7. package/dist/chunks/hubAccess-DwTZPiI8.d.ts +79 -0
  8. package/dist/chunks/hubAccess-DwTZPiI8.d.ts.map +1 -0
  9. package/dist/chunks/hubFacade-CQflVkVC.js +85 -0
  10. package/dist/chunks/hubFacade-CQflVkVC.js.map +1 -0
  11. package/dist/chunks/hubFacade-Dkgw2pTi.d.ts +101 -0
  12. package/dist/chunks/hubFacade-Dkgw2pTi.d.ts.map +1 -0
  13. package/dist/chunks/linkRpcConnection-CtlQmetO.d.ts +3623 -0
  14. package/dist/chunks/linkRpcConnection-CtlQmetO.d.ts.map +1 -0
  15. package/dist/chunks/rolldown-runtime-4LSo1kEK.js +17 -0
  16. package/dist/chunks/src-D3NUIwyo.js +7795 -0
  17. package/dist/chunks/src-D3NUIwyo.js.map +1 -0
  18. package/dist/hub/client/index.d.ts +50 -0
  19. package/dist/hub/client/index.d.ts.map +1 -0
  20. package/dist/hub/client/index.js +97 -0
  21. package/dist/hub/client/index.js.map +1 -0
  22. package/dist/hub/common/index.d.ts +1189 -0
  23. package/dist/hub/common/index.d.ts.map +1 -0
  24. package/dist/hub/common/index.js +267 -0
  25. package/dist/hub/common/index.js.map +1 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +7 -0
  28. package/dist/inspection/index.d.ts +66 -0
  29. package/dist/inspection/index.d.ts.map +1 -0
  30. package/dist/inspection/index.js +6 -0
  31. package/dist/node.d.ts +548 -0
  32. package/dist/node.d.ts.map +1 -0
  33. package/dist/node.js +1087 -0
  34. package/dist/node.js.map +1 -0
  35. package/dist/web.d.ts +44 -0
  36. package/dist/web.d.ts.map +1 -0
  37. package/dist/web.js +58 -0
  38. package/dist/web.js.map +1 -0
  39. package/package.json +59 -0
@@ -0,0 +1,526 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { C as defineInterface, N as requestType } from "./boundedTrafficSubscription-1L592xc7.js";
6
+ import { array, boolean, discriminatedUnion, enum as enum$1, extend, literal, minLength, number, object, optional, record, string, union, unknown } from "zod/mini";
7
+ //#region src/hub/common/hub.interfaces.ts
8
+ const zMemberPattern = union([object({ exact: string() }), object({ prefix: string() })]);
9
+ /**
10
+ * Optional per-permission invocation preview the requester suggests for
11
+ * "Allow once" consent UX. When present, the user can bind the resulting
12
+ * capability to this exact (method, params, interfaceHash) tuple.
13
+ *
14
+ * `nonce` and `signedAtMs` are consumer-chosen and identify the exact call
15
+ * attempt the cap will authorise. The host hashes the same canonical
16
+ * bytes the consumer will sign; the gate re-derives the hash from the
17
+ * inbound call and compares. The consumer MUST use the same
18
+ * nonce+signedAtMs when it actually issues the call (`@hediet/linkrpc`'s
19
+ * {@link JsonRpcChannel.setCapProvider} hook does this automatically).
20
+ *
21
+ * Everything in `params` is shown to the user verbatim.
22
+ */
23
+ const zCallIntent = object({
24
+ /** Fully-qualified method name the requester intends to call. */
25
+ method: string(),
26
+ /** Exact params the requester intends to send. */
27
+ params: optional(unknown()),
28
+ /** Optional schema hash assertion the call carries inside the signed payload. */
29
+ interfaceHash: optional(string()),
30
+ /** base64url-encoded nonce bytes the consumer will sign with. */
31
+ nonce: string(),
32
+ /** Unix milliseconds the consumer will sign with. */
33
+ signedAtMs: number(),
34
+ /** Optional one-line summary the shell displays next to params. */
35
+ summary: optional(string()),
36
+ /** Requester's preferred default action (`once` if omitted). */
37
+ suggestion: optional(enum$1([
38
+ "once",
39
+ "shortLived",
40
+ "longLived",
41
+ "persistent"
42
+ ]))
43
+ });
44
+ const zParamMatcher = union([
45
+ object({ exact: unknown() }),
46
+ object({ enum: array(unknown()) }),
47
+ object({ prefix: string() }),
48
+ object({ subsetOf: array(string()) }),
49
+ object({ any: literal(true) })
50
+ ]);
51
+ const zCallBindHash = object({
52
+ alg: literal("sha256"),
53
+ payloadHash: string()
54
+ });
55
+ /** Wire shape of `TargetPattern` from `@hediet/linkrpc`. */
56
+ const zTargetPattern = object({
57
+ serviceId: zMemberPattern,
58
+ interfaceId: zMemberPattern,
59
+ interfaceHash: optional(string()),
60
+ members: array(zMemberPattern)
61
+ });
62
+ /**
63
+ * Wire shape of `Permission` from `@hediet/linkrpc/identity/capability`.
64
+ * Used by `hubAccess::requestAccess` so the consumer can describe exactly
65
+ * what authority it wants — including wildcard service ids
66
+ * (`target.serviceId: { prefix: "" }`). `canInvoke`/`canDelegate` default
67
+ * to `false` (fail closed).
68
+ */
69
+ const zPermission = object({
70
+ target: zTargetPattern,
71
+ canInvoke: optional(boolean()),
72
+ canDelegate: optional(boolean()),
73
+ params: optional(record(string(), zParamMatcher)),
74
+ callBind: optional(zCallBindHash)
75
+ });
76
+ /**
77
+ * A `requestAccess` permission carrying the consent-only {@link zCallIntent}
78
+ * preview alongside the authority it requests. The host strips `callIntent`
79
+ * before minting the signed capability.
80
+ */
81
+ const zRequestPermission = extend(zPermission, { callIntent: optional(zCallIntent) });
82
+ /**
83
+ * Who is asking, plus the `principal` that becomes the minted capability's
84
+ * `audience`/target. The hub uses `principal` directly (it is no longer derived
85
+ * from the call's verified signer): a cap minted for a `principal` is only usable
86
+ * by the holder of that principal's key, enforced at call time
87
+ * (`permits` checks `audience === call.signer`).
88
+ */
89
+ const zConsumer = object({
90
+ name: string(),
91
+ /** Capability audience/target — the consumer's own PrincipalId. */
92
+ principal: string(),
93
+ origin: optional(string()),
94
+ purpose: optional(string())
95
+ });
96
+ /**
97
+ * Wire shape of `SignedCapability` from `@hediet/linkrpc`. Mirrors the
98
+ * structural type without pulling zod into the identity package. Keep in
99
+ * sync with `Capability` / `SignedCapability` there.
100
+ *
101
+ * A capability is now a flat object (its fields) plus a `$hubrpcSignature`
102
+ * map carrying the issuer's `capability` signature. Delegation links to a
103
+ * single `parentHash` (the parent's `signedHash("capability", ...)`).
104
+ */
105
+ const zSignedCapability = object({
106
+ issuer: string(),
107
+ audience: string(),
108
+ permissions: array(zPermission),
109
+ expiresAtMs: optional(number()),
110
+ parentHash: optional(string()),
111
+ nonce: string(),
112
+ $hubrpcSignature: object({
113
+ capability: optional(object({
114
+ keyId: string(),
115
+ sig: string()
116
+ })),
117
+ call: optional(object({
118
+ keyId: string(),
119
+ sig: string()
120
+ }))
121
+ })
122
+ });
123
+ /** Lifetime hint for a minted capability. Shared across hubAccess + the manifest. */
124
+ const zDuration = enum$1([
125
+ "once",
126
+ "shortLived",
127
+ "longLived",
128
+ "persistent"
129
+ ]);
130
+ /** One interface a slot's chosen service must implement. */
131
+ const zInterfaceRef = object({
132
+ id: string(),
133
+ hash: optional(string()),
134
+ /** Default true. */
135
+ required: optional(boolean())
136
+ });
137
+ /** One member (method) the consumer intends to call on a slot's interface. */
138
+ const zMemberRequest = object({
139
+ interfaceId: string(),
140
+ member: zMemberPattern,
141
+ /** Default true. */
142
+ required: optional(boolean())
143
+ });
144
+ /**
145
+ * A consumer's need for ONE service: the interfaces it must speak and the
146
+ * members it intends to call. The discovery side of both `hubAccess::request`
147
+ * (sent as a call param) and `hubAccessManifest` (published as state).
148
+ */
149
+ const zSlotRequest = object({
150
+ interfaces: array(zInterfaceRef),
151
+ members: optional(array(zMemberRequest))
152
+ });
153
+ /** The resolution of one slot: exactly one chosen service. */
154
+ const zResolvedSlot = object({
155
+ serviceId: string(),
156
+ satisfiedInterfaces: array(string())
157
+ });
158
+ /**
159
+ * Minimal JSON-document patch op, addressed by an RFC 6901 JSON Pointer.
160
+ * `path: ""` targets the whole document; a pointer like `/granted/secretStore`
161
+ * targets one entry. Used by `hubAccessManifest::setCurrent` to replace the
162
+ * entire granted document or a single entry.
163
+ */
164
+ const zManifestPatch = discriminatedUnion("op", [object({
165
+ op: literal("set"),
166
+ path: string(),
167
+ value: unknown()
168
+ }), object({
169
+ op: literal("remove"),
170
+ path: string()
171
+ })]);
172
+ /**
173
+ * `hubServiceIdRegistry::registerServiceId` — a participant claims a prefix
174
+ * **outside** its provenance-granted namespace.
175
+ *
176
+ * Reached under the hub's own service id (form-3
177
+ * `<hubServiceId>::hubServiceIdRegistry::registerServiceId`) and gated by an
178
+ * admin-rooted capability. For claims **within** the connection's granted
179
+ * namespace, use the cheaper, capability-free `hubGrantedServiceId::register`
180
+ * instead.
181
+ */
182
+ const hubServiceIdRegistryInterface = defineInterface({
183
+ id: "hubServiceIdRegistry",
184
+ description: "Claim a serviceId prefix on the hub."
185
+ }, { registerServiceId: requestType(object({ requestedPrefix: string().check(minLength(1)) }), object({})) });
186
+ /**
187
+ * `hubGrantedServiceId` — the ungated connection surface, served at the
188
+ * connection root on each participant's overlay (so it is reachable directly,
189
+ * never forwarded, and needs no capability of its own). Two jobs:
190
+ *
191
+ * - `get` (unsigned) reports the topology facts the hub decided for this
192
+ * connection — where it is and what it may claim.
193
+ * - `register` (provenance-gated) claims a prefix **within**
194
+ * this connection's granted namespace — the capability-free claim path.
195
+ * Claims outside the namespace go through the admin-gated
196
+ * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.
197
+ * - `getHubServiceId` (unsigned) reports the serviceId prefix the hub mounts
198
+ * its own global services under — the prefix to address the admin-gated
199
+ * registry and reflection endpoints through. Served at the connection root
200
+ * so a participant can discover it **before** it knows where the hub lives.
201
+ *
202
+ * The hub's consent front door (`hubAccess::*`) is served at the connection
203
+ * root too, so it needs no bootstrap capability and is reached directly.
204
+ */
205
+ const hubGrantedServiceIdInterface = defineInterface({
206
+ id: "hubGrantedServiceId",
207
+ description: "Connection facts and capability-free serviceId claims."
208
+ }, {
209
+ /**
210
+ * Connection facts (unsigned). The participant pulls, on each
211
+ * (re)connect, the topology facts the hub has decided for this
212
+ * connection:
213
+ *
214
+ * - `grantedServiceIdNamespace` — the absolute serviceId region this
215
+ * connection's provenance may claim (anything at/under it). May be
216
+ * the empty string, meaning "claim nothing freely".
217
+ */
218
+ get: requestType(object({}), object({ grantedServiceIdNamespace: string() })),
219
+ /**
220
+ * The serviceId prefix the hub mounts its own global services under
221
+ * (default `'hub'`). Use it to address the admin-gated
222
+ * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door and the
223
+ * hub's reflection endpoints. Served at the connection root (unsigned),
224
+ * so a participant can learn it without first knowing where the hub
225
+ * lives.
226
+ */
227
+ getHubServiceId: requestType(object({}), object({ hubServiceId: string() })),
228
+ /**
229
+ * Claim a serviceId prefix **within** this connection's provenance-
230
+ * granted namespace (see `get().grantedServiceIdNamespace`). No
231
+ * capability needed — the grant already happened out-of-band at attach
232
+ * time. The requested `serviceId` must equal the granted namespace or be
233
+ * nested beneath it; anything else is rejected (claim it through the
234
+ * admin-gated `<hubServiceId>::hubServiceIdRegistry::registerServiceId`
235
+ * door instead).
236
+ */
237
+ register: requestType(object({ serviceId: string().check(minLength(1)) }), object({}))
238
+ });
239
+ /**
240
+ * `hubAccess::request` — a consumer (e.g. a sandboxed web editor) asks the
241
+ * hub for scoped access to one or more services.
242
+ *
243
+ * Consumers describe their needs as named *dependencies* ("slots"): each
244
+ * slot lists the interfaces the chosen service must implement and the
245
+ * methods the consumer wants to call. The hub resolves candidate services
246
+ * from its participant directory, then forwards the bundle to a host-
247
+ * supplied handler (see `Hub` options) that shows the user a single
248
+ * prompt. The handler picks a concrete service per slot and approves a
249
+ * subset of the requested methods.
250
+ *
251
+ * In v1 the response carries only the resolution (which serviceId was
252
+ * chosen per slot). Once the hub holds a signing identity it will also
253
+ * return a `SignedCapability` the consumer attaches to subsequent calls.
254
+ * Until then, dispatch is not gated on the grant — see plan-access.md.
255
+ */
256
+ const hubAccessInterface = defineInterface({
257
+ id: "hubAccess",
258
+ description: "Consumer requests scoped access to services on the hub."
259
+ }, {
260
+ request: requestType(object({
261
+ consumer: zConsumer,
262
+ dependencies: record(string(), zSlotRequest),
263
+ duration: optional(zDuration)
264
+ }), discriminatedUnion("status", [
265
+ object({
266
+ status: literal("granted"),
267
+ slots: record(string(), zResolvedSlot),
268
+ /**
269
+ * One or more `SignedCapability`s issued by the hub
270
+ * (audience = consumer NodeId). Consumers attach them
271
+ * via `$hubrpc.capabilities` on subsequent calls. Empty
272
+ * array is legal (hub with no signing identity / tests).
273
+ *
274
+ * Plural so a handler can return per-slot caps with
275
+ * different `exp`/caveats; typical handlers return a
276
+ * single cap covering every granted member.
277
+ */
278
+ capabilities: array(zSignedCapability)
279
+ }),
280
+ object({
281
+ status: literal("denied"),
282
+ reason: optional(string())
283
+ }),
284
+ object({
285
+ status: literal("noCandidates"),
286
+ /** Slot ids that have zero matching candidates. */
287
+ slots: array(string())
288
+ })
289
+ ])),
290
+ /**
291
+ * Service-pinned widening of an existing grant. The consumer asks
292
+ * the hub for additional members on a `serviceId` they already
293
+ * deal with — same audience (their NodeId) and (intended) same
294
+ * `rootIssuer` as the prior grant. The hub never picks the service
295
+ * for the consumer here: `serviceId` is an input, not a result.
296
+ *
297
+ * On grant the response carries a fresh `SignedCapability` whose
298
+ * attenuations cover **only** the granted delta. Bag-compatible
299
+ * with the prior cap; combine via `merge` (when it exists) or
300
+ * just keep both in `$hubrpc.capabilities`.
301
+ *
302
+ * Distinguished from `request` so the consent UI can render a
303
+ * different affordance ("X already has read access on `github`,
304
+ * grant `update` as well?" instead of from-zero selection).
305
+ *
306
+ * TODO(hub-ledger): enforce "consumer has prior history on this
307
+ * service" — see `hub.ts:_handleAccessExtend`. v1 forwards
308
+ * directly to the host's `onAccessExtend` without consulting the
309
+ * `_grants` ledger; this is by design while we settle on the
310
+ * persistence model.
311
+ */
312
+ extend: requestType(object({
313
+ consumer: zConsumer,
314
+ /**
315
+ * Service to widen the grant on. MUST equal the
316
+ * `serviceId` of a previously-issued attenuation for this
317
+ * consumer NodeId. v1 does not validate this.
318
+ */
319
+ serviceId: string(),
320
+ /**
321
+ * The delta. Same shape as `request`'s slot.members. Each
322
+ * entry MUST refer to an interface the consumer has been
323
+ * introduced to on `serviceId` via a prior `request`.
324
+ */
325
+ added: array(zMemberRequest),
326
+ duration: optional(zDuration)
327
+ }), discriminatedUnion("status", [object({
328
+ status: literal("granted"),
329
+ serviceId: string(),
330
+ /** Members actually granted (handler may approve a subset). */
331
+ granted: array(object({
332
+ interfaceId: string(),
333
+ member: zMemberPattern
334
+ })),
335
+ /**
336
+ * Capability covering only the granted delta. Audience
337
+ * = consumer NodeId. Bag-compatible with the prior
338
+ * cap on this service.
339
+ */
340
+ capabilities: optional(array(zSignedCapability))
341
+ }), object({
342
+ status: literal("denied"),
343
+ reason: optional(string())
344
+ })])),
345
+ /**
346
+ * `hubAccess::requestAccess` — direct capability request. The
347
+ * consumer specifies the exact attenuations it wants. No
348
+ * service-discovery, no candidate resolution: the consumer
349
+ * already knows which `(serviceId, interfaceId, members)` it
350
+ * needs, including wildcards (e.g. `serviceId: { prefix: "" }`
351
+ * to ask for an interface anywhere).
352
+ *
353
+ * Compared to `request`:
354
+ * - `request` does directory-based discovery, picks one service
355
+ * per slot, and returns a cap pinned to that service. Use
356
+ * when the consumer says "give me SOME service that does X".
357
+ * - `requestAccess` is verbatim. Use when the consumer says
358
+ * "give me exactly these attenuations". Especially useful for
359
+ * reflection (`hubrpc.directory::list` on any service) and
360
+ * for on-demand per-method grants from an explorer-style UI.
361
+ *
362
+ * The user prompt shows the exact `Capability` the hub will sign
363
+ * on Allow, same byte-equality guarantee as `request`/`extend`.
364
+ */
365
+ requestAccess: requestType(object({
366
+ consumer: zConsumer,
367
+ permissions: array(zRequestPermission).check(minLength(1)),
368
+ duration: optional(zDuration)
369
+ }), discriminatedUnion("status", [object({
370
+ status: literal("granted"),
371
+ capabilities: array(zSignedCapability)
372
+ }), object({
373
+ status: literal("denied"),
374
+ reason: optional(string())
375
+ })]))
376
+ });
377
+ /**
378
+ * The root issuer(s) whose signature the participant will accept on the minted
379
+ * capability. A capability is only usable by its holder if it chains to a root
380
+ * that the *target* service trusts — and not every service trusts every root.
381
+ * So the participant declares, per entry, which minting root(s) would produce a
382
+ * cap it can actually use; the admin must mint with one of them (or decline).
383
+ *
384
+ * Tri-state, by design:
385
+ * - **omitted** (`undefined`) — unspecified. The participant doesn't know /
386
+ * doesn't constrain the root; the admin picks. (The common, lenient default.)
387
+ * - **non-empty** (`["id:abc", …]`) — mint with one of *these* roots; a cap
388
+ * rooted elsewhere is useless to the participant.
389
+ * - **empty** (`[]`) — "no root is acceptable", i.e. nothing can satisfy this.
390
+ * Almost certainly a bug (it can never be granted); kept representable so a
391
+ * tool can detect and flag it rather than silently treating it as "any".
392
+ */
393
+ const zAcceptableRootIds = array(string());
394
+ /**
395
+ * A desired access entry the participant publishes. Two kinds, mirroring the
396
+ * two discovery-vs-verbatim halves of `hubAccess`:
397
+ *
398
+ * - `discover` — "find me a service implementing X" (same shape as a
399
+ * `hubAccess::request` slot). The admin resolves one concrete service.
400
+ * - `direct` — "grant exactly these permissions" (same shape as
401
+ * `hubAccess::requestAccess`). The serviceId is already in each permission's
402
+ * target; no discovery.
403
+ */
404
+ const zManifestRequest = discriminatedUnion("kind", [extend(zSlotRequest, {
405
+ kind: literal("discover"),
406
+ /** Who is asking; `principal` is the audience minted caps must target. */
407
+ consumer: zConsumer,
408
+ /** Human rationale shown to the admin ("seal tokens at rest"). */
409
+ reason: optional(string()),
410
+ duration: optional(zDuration),
411
+ /** Root issuer(s) that must mint this cap. See {@link zAcceptableRootIds}. */
412
+ acceptableRootIds: optional(zAcceptableRootIds),
413
+ /**
414
+ * Host-authored provenance bag, stamped at `registerHubAccessAtRoot`
415
+ * (NOT taken from the consumer's request params — so it cannot be
416
+ * spoofed). An open `record<string, unknown>` so a host can attach
417
+ * whatever origin info it observed about the requesting transport (e.g.
418
+ * `{ sourceTransportId }` to route a local consent UI). Meaningful only
419
+ * to a consumer that KNOWS this manifest is local; an aggregating
420
+ * manifest MUST re-scope or omit it.
421
+ */
422
+ origin: optional(record(string(), unknown()))
423
+ }), object({
424
+ kind: literal("direct"),
425
+ /** Who is asking; `principal` is the audience minted caps must target. */
426
+ consumer: zConsumer,
427
+ reason: optional(string()),
428
+ permissions: array(zRequestPermission).check(minLength(1)),
429
+ duration: optional(zDuration),
430
+ /** Root issuer(s) that must mint this cap. See {@link zAcceptableRootIds}. */
431
+ acceptableRootIds: optional(zAcceptableRootIds),
432
+ /** Host-authored provenance bag. See the `discover` variant. */
433
+ origin: optional(record(string(), unknown()))
434
+ })]);
435
+ /**
436
+ * The current (granted) value of one entry. For `discover` it carries the single
437
+ * chosen service (mirroring `hubAccess::request`'s resolved slot) plus the caps;
438
+ * for `direct` just the caps (the serviceId is in each permission's target).
439
+ */
440
+ const zGrantedEntry = discriminatedUnion("kind", [extend(zResolvedSlot, {
441
+ kind: literal("discover"),
442
+ capabilities: array(zSignedCapability)
443
+ }), object({
444
+ kind: literal("direct"),
445
+ capabilities: array(zSignedCapability)
446
+ })]);
447
+ /**
448
+ * The current value of one entry: `granted` (caps, plus the chosen service for
449
+ * `discover`) or `denied` (with an optional reason). An entry *absent* from the
450
+ * current document is **undecided** — distinct from a terminal `denied`, which
451
+ * lets an approver say "no" (and why) instead of silently withholding.
452
+ */
453
+ const zCurrentEntry = discriminatedUnion("status", [object({
454
+ status: literal("granted"),
455
+ granted: zGrantedEntry
456
+ }), object({
457
+ status: literal("denied"),
458
+ reason: optional(string())
459
+ })]);
460
+ /**
461
+ * `hubAccessManifest` — the declarative twin of {@link hubAccessInterface}.
462
+ *
463
+ * Where `hubAccess` is the imperative, just-in-time door a consumer *calls* (and
464
+ * the hub serves at the connection root), `hubAccessManifest` is **served by the
465
+ * participant** under its own serviceId, so it appears in `hubrpc.directory::list`
466
+ * — its very presence is the request. A participant publishes its DESIRED access
467
+ * entries (keyed by id, like `request`'s `dependencies`); an admin discovers
468
+ * them via the directory, mints capabilities **with its own identity** (a
469
+ * configured hub capability root), and writes the CURRENT/granted state back via
470
+ * patches. The participant reads the granted entries and attaches the caps to
471
+ * its later calls.
472
+ *
473
+ * Reconcile model (desired vs. current), aligned with the hub's other surfaces:
474
+ * - `getDesired` / `watchDesired` — the participant's declared needs.
475
+ * - `getCurrent` / `setCurrent` / `watchCurrent` — the admin-written grants.
476
+ *
477
+ * `watch*` follows the coarse empty-tick convention of `hubrpc.directory::watch`:
478
+ * a tick means "re-`get` now", keeping the server stateless (no per-item deltas).
479
+ */
480
+ const hubAccessManifestInterface = defineInterface({
481
+ id: "hubAccessManifest",
482
+ description: "Participant-served declarative access: publish DESIRED access entries (discover | direct), an admin mints capabilities and writes the CURRENT granted state back. The reconcile twin of hubAccess::{request,requestAccess}."
483
+ }, {
484
+ /** The full desired document: who is asking and the entries it wants. */
485
+ getDesired: requestType(object({}), object({
486
+ /**
487
+ * entryId → desired entry, each carrying its own `consumer`. A
488
+ * per-participant manifest's entries all share one consumer; a hub
489
+ * broker aggregates entries from many consumers in one flat map.
490
+ */
491
+ requested: record(string(), zManifestRequest),
492
+ /** Bumped whenever `requested` changes; lets watchers dedupe ticks. */
493
+ revision: number()
494
+ })).withStream({ client: object({}) }),
495
+ /**
496
+ * Coarse change tap on the desired document. Emits an empty tick when
497
+ * `requested` may have changed; the caller re-`getDesired`. Resolves when
498
+ * the caller cancels. Mirrors `hubrpc.directory::watch`.
499
+ */
500
+ watchDesired: requestType(object({}), object({})).withStream({ server: object({}) }),
501
+ /** The full current document: entryId → granted/denied (absent ⇒ undecided). */
502
+ getCurrent: requestType(object({}), object({
503
+ /** entryId → current value (granted | denied). */
504
+ current: record(string(), zCurrentEntry),
505
+ /** Bumped on every successful `setCurrent`. */
506
+ revision: number()
507
+ })),
508
+ /**
509
+ * Apply patches to the current document. Replace the whole document with
510
+ * `{ op: 'set', path: '', value }`, or a single entry with
511
+ * `{ op: 'set', path: '/current/<entryId>', value }` (a `zCurrentEntry`:
512
+ * granted or denied). Admin-only in practice (gated by a capability
513
+ * rooted at an accepted issuer).
514
+ */
515
+ setCurrent: requestType(object({ patches: array(zManifestPatch) }), object({ revision: number() })).withStream({ client: object({}) }),
516
+ /**
517
+ * Coarse change tap on the current document. Emits an empty tick when
518
+ * `current` may have changed; the participant re-`getCurrent` and applies
519
+ * any new capabilities. Resolves when the caller cancels.
520
+ */
521
+ watchCurrent: requestType(object({}), object({})).withStream({ server: object({}) })
522
+ });
523
+ //#endregion
524
+ export { hubServiceIdRegistryInterface as i, hubAccessManifestInterface as n, hubGrantedServiceIdInterface as r, hubAccessInterface as t };
525
+
526
+ //# sourceMappingURL=hub.interfaces-BzWfsVT2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub.interfaces-BzWfsVT2.js","names":["zEnum"],"sources":["../../src/hub/common/hub.interfaces.ts"],"sourcesContent":["import { array, boolean, discriminatedUnion, enum as zEnum, extend, literal, minLength, number, object, optional, record, string, union, unknown } from 'zod/mini';\nimport { defineInterface, requestType, type InterfaceClient } from '../../index';\n\nconst zMemberPattern = union([\n object({ exact: string() }),\n object({ prefix: string() }),\n]);\n\n/**\n * Optional per-permission invocation preview the requester suggests for\n * \"Allow once\" consent UX. When present, the user can bind the resulting\n * capability to this exact (method, params, interfaceHash) tuple.\n *\n * `nonce` and `signedAtMs` are consumer-chosen and identify the exact call\n * attempt the cap will authorise. The host hashes the same canonical\n * bytes the consumer will sign; the gate re-derives the hash from the\n * inbound call and compares. The consumer MUST use the same\n * nonce+signedAtMs when it actually issues the call (`@hediet/linkrpc`'s\n * {@link JsonRpcChannel.setCapProvider} hook does this automatically).\n *\n * Everything in `params` is shown to the user verbatim.\n */\nconst zCallIntent = object({\n /** Fully-qualified method name the requester intends to call. */\n method: string(),\n /** Exact params the requester intends to send. */\n params: optional(unknown()),\n /** Optional schema hash assertion the call carries inside the signed payload. */\n interfaceHash: optional(string()),\n /** base64url-encoded nonce bytes the consumer will sign with. */\n nonce: string(),\n /** Unix milliseconds the consumer will sign with. */\n signedAtMs: number(),\n /** Optional one-line summary the shell displays next to params. */\n summary: optional(string()),\n /** Requester's preferred default action (`once` if omitted). */\n suggestion: optional(zEnum(['once', 'shortLived', 'longLived', 'persistent'])),\n});\n\nconst zParamMatcher = union([\n object({ exact: unknown() }),\n object({ enum: array(unknown()) }),\n object({ prefix: string() }),\n object({ subsetOf: array(string()) }),\n object({ any: literal(true) }),\n]);\n\nconst zCallBindHash = object({\n alg: literal('sha256'),\n payloadHash: string(),\n});\n\n/** Wire shape of `TargetPattern` from `@hediet/linkrpc`. */\nconst zTargetPattern = object({\n serviceId: zMemberPattern,\n interfaceId: zMemberPattern,\n interfaceHash: optional(string()),\n members: array(zMemberPattern),\n});\n\n/**\n * Wire shape of `Permission` from `@hediet/linkrpc/identity/capability`.\n * Used by `hubAccess::requestAccess` so the consumer can describe exactly\n * what authority it wants — including wildcard service ids\n * (`target.serviceId: { prefix: \"\" }`). `canInvoke`/`canDelegate` default\n * to `false` (fail closed).\n */\nconst zPermission = object({\n target: zTargetPattern,\n canInvoke: optional(boolean()),\n canDelegate: optional(boolean()),\n params: optional(record(string(), zParamMatcher)),\n callBind: optional(zCallBindHash),\n});\n\n/**\n * A `requestAccess` permission carrying the consent-only {@link zCallIntent}\n * preview alongside the authority it requests. The host strips `callIntent`\n * before minting the signed capability.\n */\nconst zRequestPermission = extend(zPermission, {\n callIntent: optional(zCallIntent),\n});\n\n/**\n * Who is asking, plus the `principal` that becomes the minted capability's\n * `audience`/target. The hub uses `principal` directly (it is no longer derived\n * from the call's verified signer): a cap minted for a `principal` is only usable\n * by the holder of that principal's key, enforced at call time\n * (`permits` checks `audience === call.signer`).\n */\nconst zConsumer = object({\n name: string(),\n /** Capability audience/target — the consumer's own PrincipalId. */\n principal: string(),\n origin: optional(string()),\n purpose: optional(string()),\n});\n\n/**\n * Wire shape of `SignedCapability` from `@hediet/linkrpc`. Mirrors the\n * structural type without pulling zod into the identity package. Keep in\n * sync with `Capability` / `SignedCapability` there.\n *\n * A capability is now a flat object (its fields) plus a `$hubrpcSignature`\n * map carrying the issuer's `capability` signature. Delegation links to a\n * single `parentHash` (the parent's `signedHash(\"capability\", ...)`).\n */\nconst zSignedCapability = object({\n issuer: string(),\n audience: string(),\n permissions: array(zPermission),\n expiresAtMs: optional(number()),\n parentHash: optional(string()),\n nonce: string(),\n $hubrpcSignature: object({\n capability: optional(object({ keyId: string(), sig: string() })),\n call: optional(object({ keyId: string(), sig: string() })),\n }),\n});\n\n/** Lifetime hint for a minted capability. Shared across hubAccess + the manifest. */\nconst zDuration = zEnum(['once', 'shortLived', 'longLived', 'persistent']);\n\n// ---- discovery slot shapes (shared by hubAccess.request and hubAccessManifest) ----\n\n/** One interface a slot's chosen service must implement. */\nconst zInterfaceRef = object({\n id: string(),\n hash: optional(string()),\n /** Default true. */\n required: optional(boolean()),\n});\n\n/** One member (method) the consumer intends to call on a slot's interface. */\nconst zMemberRequest = object({\n interfaceId: string(),\n member: zMemberPattern,\n /** Default true. */\n required: optional(boolean()),\n});\n\n/**\n * A consumer's need for ONE service: the interfaces it must speak and the\n * members it intends to call. The discovery side of both `hubAccess::request`\n * (sent as a call param) and `hubAccessManifest` (published as state).\n */\nconst zSlotRequest = object({\n interfaces: array(zInterfaceRef),\n members: optional(array(zMemberRequest)),\n});\n\n/** The resolution of one slot: exactly one chosen service. */\nconst zResolvedSlot = object({\n serviceId: string(),\n satisfiedInterfaces: array(string()),\n});\n\n/**\n * Minimal JSON-document patch op, addressed by an RFC 6901 JSON Pointer.\n * `path: \"\"` targets the whole document; a pointer like `/granted/secretStore`\n * targets one entry. Used by `hubAccessManifest::setCurrent` to replace the\n * entire granted document or a single entry.\n */\nconst zManifestPatch = discriminatedUnion('op', [\n object({ op: literal('set'), path: string(), value: unknown() }),\n object({ op: literal('remove'), path: string() }),\n]);\n\n/**\n * `hubServiceIdRegistry::registerServiceId` — a participant claims a prefix\n * **outside** its provenance-granted namespace.\n *\n * Reached under the hub's own service id (form-3\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId`) and gated by an\n * admin-rooted capability. For claims **within** the connection's granted\n * namespace, use the cheaper, capability-free `hubGrantedServiceId::register`\n * instead.\n */\nexport const hubServiceIdRegistryInterface = defineInterface(\n {\n id: 'hubServiceIdRegistry',\n description: 'Claim a serviceId prefix on the hub.',\n },\n {\n registerServiceId: requestType(\n object({\n requestedPrefix: string().check(minLength(1)),\n }),\n object({}),\n ),\n },\n);\n\n\n/**\n * `hubGrantedServiceId` — the ungated connection surface, served at the\n * connection root on each participant's overlay (so it is reachable directly,\n * never forwarded, and needs no capability of its own). Two jobs:\n *\n * - `get` (unsigned) reports the topology facts the hub decided for this\n * connection — where it is and what it may claim.\n * - `register` (provenance-gated) claims a prefix **within**\n * this connection's granted namespace — the capability-free claim path.\n * Claims outside the namespace go through the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.\n * - `getHubServiceId` (unsigned) reports the serviceId prefix the hub mounts\n * its own global services under — the prefix to address the admin-gated\n * registry and reflection endpoints through. Served at the connection root\n * so a participant can discover it **before** it knows where the hub lives.\n *\n * The hub's consent front door (`hubAccess::*`) is served at the connection\n * root too, so it needs no bootstrap capability and is reached directly.\n */\nexport const hubGrantedServiceIdInterface = defineInterface(\n {\n id: 'hubGrantedServiceId',\n description: 'Connection facts and capability-free serviceId claims.',\n },\n {\n /**\n * Connection facts (unsigned). The participant pulls, on each\n * (re)connect, the topology facts the hub has decided for this\n * connection:\n *\n * - `grantedServiceIdNamespace` — the absolute serviceId region this\n * connection's provenance may claim (anything at/under it). May be\n * the empty string, meaning \"claim nothing freely\".\n */\n get: requestType(\n object({}),\n object({\n grantedServiceIdNamespace: string(),\n }),\n ),\n\n /**\n * The serviceId prefix the hub mounts its own global services under\n * (default `'hub'`). Use it to address the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door and the\n * hub's reflection endpoints. Served at the connection root (unsigned),\n * so a participant can learn it without first knowing where the hub\n * lives.\n */\n getHubServiceId: requestType(\n object({}),\n object({\n hubServiceId: string(),\n }),\n ),\n\n /**\n * Claim a serviceId prefix **within** this connection's provenance-\n * granted namespace (see `get().grantedServiceIdNamespace`). No\n * capability needed — the grant already happened out-of-band at attach\n * time. The requested `serviceId` must equal the granted namespace or be\n * nested beneath it; anything else is rejected (claim it through the\n * admin-gated `<hubServiceId>::hubServiceIdRegistry::registerServiceId`\n * door instead).\n */\n register: requestType(\n object({ serviceId: string().check(minLength(1)) }),\n object({}),\n ),\n },\n);\n\n/**\n * `hubAccess::request` — a consumer (e.g. a sandboxed web editor) asks the\n * hub for scoped access to one or more services.\n *\n * Consumers describe their needs as named *dependencies* (\"slots\"): each\n * slot lists the interfaces the chosen service must implement and the\n * methods the consumer wants to call. The hub resolves candidate services\n * from its participant directory, then forwards the bundle to a host-\n * supplied handler (see `Hub` options) that shows the user a single\n * prompt. The handler picks a concrete service per slot and approves a\n * subset of the requested methods.\n *\n * In v1 the response carries only the resolution (which serviceId was\n * chosen per slot). Once the hub holds a signing identity it will also\n * return a `SignedCapability` the consumer attaches to subsequent calls.\n * Until then, dispatch is not gated on the grant — see plan-access.md.\n */\nexport const hubAccessInterface = defineInterface(\n {\n id: 'hubAccess',\n description: 'Consumer requests scoped access to services on the hub.',\n },\n {\n request: requestType(\n object({\n consumer: zConsumer,\n dependencies: record(string(), zSlotRequest),\n duration: optional(zDuration),\n }),\n discriminatedUnion('status', [\n object({\n status: literal('granted'),\n slots: record(string(), zResolvedSlot),\n /**\n * One or more `SignedCapability`s issued by the hub\n * (audience = consumer NodeId). Consumers attach them\n * via `$hubrpc.capabilities` on subsequent calls. Empty\n * array is legal (hub with no signing identity / tests).\n *\n * Plural so a handler can return per-slot caps with\n * different `exp`/caveats; typical handlers return a\n * single cap covering every granted member.\n */\n capabilities: array(zSignedCapability),\n }),\n object({\n status: literal('denied'),\n reason: optional(string()),\n }),\n object({\n status: literal('noCandidates'),\n /** Slot ids that have zero matching candidates. */\n slots: array(string()),\n }),\n ]),\n ),\n\n /**\n * Service-pinned widening of an existing grant. The consumer asks\n * the hub for additional members on a `serviceId` they already\n * deal with — same audience (their NodeId) and (intended) same\n * `rootIssuer` as the prior grant. The hub never picks the service\n * for the consumer here: `serviceId` is an input, not a result.\n *\n * On grant the response carries a fresh `SignedCapability` whose\n * attenuations cover **only** the granted delta. Bag-compatible\n * with the prior cap; combine via `merge` (when it exists) or\n * just keep both in `$hubrpc.capabilities`.\n *\n * Distinguished from `request` so the consent UI can render a\n * different affordance (\"X already has read access on `github`,\n * grant `update` as well?\" instead of from-zero selection).\n *\n * TODO(hub-ledger): enforce \"consumer has prior history on this\n * service\" — see `hub.ts:_handleAccessExtend`. v1 forwards\n * directly to the host's `onAccessExtend` without consulting the\n * `_grants` ledger; this is by design while we settle on the\n * persistence model.\n */\n extend: requestType(\n object({\n consumer: zConsumer,\n /**\n * Service to widen the grant on. MUST equal the\n * `serviceId` of a previously-issued attenuation for this\n * consumer NodeId. v1 does not validate this.\n */\n serviceId: string(),\n /**\n * The delta. Same shape as `request`'s slot.members. Each\n * entry MUST refer to an interface the consumer has been\n * introduced to on `serviceId` via a prior `request`.\n */\n added: array(zMemberRequest),\n duration: optional(zDuration),\n }),\n discriminatedUnion('status', [\n object({\n status: literal('granted'),\n serviceId: string(),\n /** Members actually granted (handler may approve a subset). */\n granted: array(\n object({\n interfaceId: string(),\n member: zMemberPattern,\n }),\n ),\n /**\n * Capability covering only the granted delta. Audience\n * = consumer NodeId. Bag-compatible with the prior\n * cap on this service.\n */\n capabilities: optional(array(zSignedCapability)),\n }),\n object({\n status: literal('denied'),\n reason: optional(string()),\n }),\n // TODO(hub-ledger): additional variants once the host's\n // grant ledger is persisted:\n // - { status: \"unknownService\", serviceId }\n // - { status: \"unknownInterface\", serviceId, interfaceIds }\n // Reject without ever prompting the user when the consumer\n // is asking to widen a service it has no prior grant on.\n ]),\n ),\n\n /**\n * `hubAccess::requestAccess` — direct capability request. The\n * consumer specifies the exact attenuations it wants. No\n * service-discovery, no candidate resolution: the consumer\n * already knows which `(serviceId, interfaceId, members)` it\n * needs, including wildcards (e.g. `serviceId: { prefix: \"\" }`\n * to ask for an interface anywhere).\n *\n * Compared to `request`:\n * - `request` does directory-based discovery, picks one service\n * per slot, and returns a cap pinned to that service. Use\n * when the consumer says \"give me SOME service that does X\".\n * - `requestAccess` is verbatim. Use when the consumer says\n * \"give me exactly these attenuations\". Especially useful for\n * reflection (`hubrpc.directory::list` on any service) and\n * for on-demand per-method grants from an explorer-style UI.\n *\n * The user prompt shows the exact `Capability` the hub will sign\n * on Allow, same byte-equality guarantee as `request`/`extend`.\n */\n requestAccess: requestType(\n object({\n consumer: zConsumer,\n permissions: array(zRequestPermission).check(minLength(1)),\n duration: optional(zDuration),\n }),\n discriminatedUnion('status', [\n object({\n status: literal('granted'),\n capabilities: array(zSignedCapability),\n }),\n object({\n status: literal('denied'),\n reason: optional(string()),\n }),\n ]),\n ),\n },\n);\n\n// ════════════════════════════════════════════════════════════════════════\n// hubAccessManifest — the declarative twin of `hubAccess`.\n// ════════════════════════════════════════════════════════════════════════\n\n/**\n * The root issuer(s) whose signature the participant will accept on the minted\n * capability. A capability is only usable by its holder if it chains to a root\n * that the *target* service trusts — and not every service trusts every root.\n * So the participant declares, per entry, which minting root(s) would produce a\n * cap it can actually use; the admin must mint with one of them (or decline).\n *\n * Tri-state, by design:\n * - **omitted** (`undefined`) — unspecified. The participant doesn't know /\n * doesn't constrain the root; the admin picks. (The common, lenient default.)\n * - **non-empty** (`[\"id:abc\", …]`) — mint with one of *these* roots; a cap\n * rooted elsewhere is useless to the participant.\n * - **empty** (`[]`) — \"no root is acceptable\", i.e. nothing can satisfy this.\n * Almost certainly a bug (it can never be granted); kept representable so a\n * tool can detect and flag it rather than silently treating it as \"any\".\n */\nconst zAcceptableRootIds = array(string());\n\n/**\n * A desired access entry the participant publishes. Two kinds, mirroring the\n * two discovery-vs-verbatim halves of `hubAccess`:\n *\n * - `discover` — \"find me a service implementing X\" (same shape as a\n * `hubAccess::request` slot). The admin resolves one concrete service.\n * - `direct` — \"grant exactly these permissions\" (same shape as\n * `hubAccess::requestAccess`). The serviceId is already in each permission's\n * target; no discovery.\n */\nconst zManifestRequest = discriminatedUnion('kind', [\n extend(zSlotRequest, {\n kind: literal('discover'),\n /** Who is asking; `principal` is the audience minted caps must target. */\n consumer: zConsumer,\n /** Human rationale shown to the admin (\"seal tokens at rest\"). */\n reason: optional(string()),\n duration: optional(zDuration),\n /** Root issuer(s) that must mint this cap. See {@link zAcceptableRootIds}. */\n acceptableRootIds: optional(zAcceptableRootIds),\n /**\n * Host-authored provenance bag, stamped at `registerHubAccessAtRoot`\n * (NOT taken from the consumer's request params — so it cannot be\n * spoofed). An open `record<string, unknown>` so a host can attach\n * whatever origin info it observed about the requesting transport (e.g.\n * `{ sourceTransportId }` to route a local consent UI). Meaningful only\n * to a consumer that KNOWS this manifest is local; an aggregating\n * manifest MUST re-scope or omit it.\n */\n origin: optional(record(string(), unknown())),\n }),\n object({\n kind: literal('direct'),\n /** Who is asking; `principal` is the audience minted caps must target. */\n consumer: zConsumer,\n reason: optional(string()),\n permissions: array(zRequestPermission).check(minLength(1)),\n duration: optional(zDuration),\n /** Root issuer(s) that must mint this cap. See {@link zAcceptableRootIds}. */\n acceptableRootIds: optional(zAcceptableRootIds),\n /** Host-authored provenance bag. See the `discover` variant. */\n origin: optional(record(string(), unknown())),\n }),\n]);\n\n/**\n * The current (granted) value of one entry. For `discover` it carries the single\n * chosen service (mirroring `hubAccess::request`'s resolved slot) plus the caps;\n * for `direct` just the caps (the serviceId is in each permission's target).\n */\nconst zGrantedEntry = discriminatedUnion('kind', [\n extend(zResolvedSlot, {\n kind: literal('discover'),\n capabilities: array(zSignedCapability),\n }),\n object({\n kind: literal('direct'),\n capabilities: array(zSignedCapability),\n }),\n]);\n\n/**\n * The current value of one entry: `granted` (caps, plus the chosen service for\n * `discover`) or `denied` (with an optional reason). An entry *absent* from the\n * current document is **undecided** — distinct from a terminal `denied`, which\n * lets an approver say \"no\" (and why) instead of silently withholding.\n */\nconst zCurrentEntry = discriminatedUnion('status', [\n object({ status: literal('granted'), granted: zGrantedEntry }),\n object({ status: literal('denied'), reason: optional(string()) }),\n]);\n\n/**\n * `hubAccessManifest` — the declarative twin of {@link hubAccessInterface}.\n *\n * Where `hubAccess` is the imperative, just-in-time door a consumer *calls* (and\n * the hub serves at the connection root), `hubAccessManifest` is **served by the\n * participant** under its own serviceId, so it appears in `hubrpc.directory::list`\n * — its very presence is the request. A participant publishes its DESIRED access\n * entries (keyed by id, like `request`'s `dependencies`); an admin discovers\n * them via the directory, mints capabilities **with its own identity** (a\n * configured hub capability root), and writes the CURRENT/granted state back via\n * patches. The participant reads the granted entries and attaches the caps to\n * its later calls.\n *\n * Reconcile model (desired vs. current), aligned with the hub's other surfaces:\n * - `getDesired` / `watchDesired` — the participant's declared needs.\n * - `getCurrent` / `setCurrent` / `watchCurrent` — the admin-written grants.\n *\n * `watch*` follows the coarse empty-tick convention of `hubrpc.directory::watch`:\n * a tick means \"re-`get` now\", keeping the server stateless (no per-item deltas).\n */\nexport const hubAccessManifestInterface = defineInterface(\n {\n id: 'hubAccessManifest',\n description:\n 'Participant-served declarative access: publish DESIRED access entries '\n + '(discover | direct), an admin mints capabilities and writes the CURRENT '\n + 'granted state back. The reconcile twin of hubAccess::{request,requestAccess}.',\n },\n {\n // ---- desired (participant-authored; the admin reads) ----------------\n /** The full desired document: who is asking and the entries it wants. */\n getDesired: requestType(\n object({}),\n object({\n /**\n * entryId → desired entry, each carrying its own `consumer`. A\n * per-participant manifest's entries all share one consumer; a hub\n * broker aggregates entries from many consumers in one flat map.\n */\n requested: record(string(), zManifestRequest),\n /** Bumped whenever `requested` changes; lets watchers dedupe ticks. */\n revision: number(),\n }),\n ).withStream({ client: object({}) }),\n /**\n * Coarse change tap on the desired document. Emits an empty tick when\n * `requested` may have changed; the caller re-`getDesired`. Resolves when\n * the caller cancels. Mirrors `hubrpc.directory::watch`.\n */\n watchDesired: requestType(\n object({}),\n object({}),\n ).withStream({ server: object({}) }),\n\n // ---- current / granted (admin-authored; the participant reads) ------\n /** The full current document: entryId → granted/denied (absent ⇒ undecided). */\n getCurrent: requestType(\n object({}),\n object({\n /** entryId → current value (granted | denied). */\n current: record(string(), zCurrentEntry),\n /** Bumped on every successful `setCurrent`. */\n revision: number(),\n }),\n ),\n /**\n * Apply patches to the current document. Replace the whole document with\n * `{ op: 'set', path: '', value }`, or a single entry with\n * `{ op: 'set', path: '/current/<entryId>', value }` (a `zCurrentEntry`:\n * granted or denied). Admin-only in practice (gated by a capability\n * rooted at an accepted issuer).\n */\n setCurrent: requestType(\n object({ patches: array(zManifestPatch) }),\n object({ revision: number() }),\n ).withStream({ client: object({}) }),\n /**\n * Coarse change tap on the current document. Emits an empty tick when\n * `current` may have changed; the participant re-`getCurrent` and applies\n * any new capabilities. Resolves when the caller cancels.\n */\n watchCurrent: requestType(\n object({}),\n object({}),\n ).withStream({ server: object({}) }),\n },\n);\n\n/**\n * The typed client shape of {@link hubAccessManifestInterface} — the exact\n * object `connection.get(hubAccessManifestInterface)` (or\n * `connection.service(id).get(...)`) returns. Approvers depend on this contract,\n * not on a concrete connection: the same approver runs against a local in-memory\n * host (loopback connection), a remote hub's served manifest, or a future\n * aggregating implementation with no code change.\n */\nexport type IHubAccessManifest = InterfaceClient<typeof hubAccessManifestInterface>;\n\n/** One typed entry from `hubAccessManifest::getDesired().requested`. */\nexport type HubAccessManifestRequest =\n Awaited<ReturnType<IHubAccessManifest['getDesired']>>['requested'][string];\n\n/** One typed value accepted at `/current/<entryId>` by `setCurrent`. */\nexport type HubAccessManifestDecision =\n Awaited<ReturnType<IHubAccessManifest['getCurrent']>>['current'][string];\n"],"mappings":";;;;;;;AAGA,MAAM,iBAAiB,MAAM,CACzB,OAAO,EAAE,OAAO,OAAO,EAAE,CAAC,GAC1B,OAAO,EAAE,QAAQ,OAAO,EAAE,CAAC,CAC/B,CAAC;;;;;;;;;;;;;;;AAgBD,MAAM,cAAc,OAAO;;CAEvB,QAAQ,OAAO;;CAEf,QAAQ,SAAS,QAAQ,CAAC;;CAE1B,eAAe,SAAS,OAAO,CAAC;;CAEhC,OAAO,OAAO;;CAEd,YAAY,OAAO;;CAEnB,SAAS,SAAS,OAAO,CAAC;;CAE1B,YAAY,SAASA,OAAM;EAAC;EAAQ;EAAc;EAAa;CAAY,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,gBAAgB,MAAM;CACxB,OAAO,EAAE,OAAO,QAAQ,EAAE,CAAC;CAC3B,OAAO,EAAE,MAAM,MAAM,QAAQ,CAAC,EAAE,CAAC;CACjC,OAAO,EAAE,QAAQ,OAAO,EAAE,CAAC;CAC3B,OAAO,EAAE,UAAU,MAAM,OAAO,CAAC,EAAE,CAAC;CACpC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,gBAAgB,OAAO;CACzB,KAAK,QAAQ,QAAQ;CACrB,aAAa,OAAO;AACxB,CAAC;;AAGD,MAAM,iBAAiB,OAAO;CAC1B,WAAW;CACX,aAAa;CACb,eAAe,SAAS,OAAO,CAAC;CAChC,SAAS,MAAM,cAAc;AACjC,CAAC;;;;;;;;AASD,MAAM,cAAc,OAAO;CACvB,QAAQ;CACR,WAAW,SAAS,QAAQ,CAAC;CAC7B,aAAa,SAAS,QAAQ,CAAC;CAC/B,QAAQ,SAAS,OAAO,OAAO,GAAG,aAAa,CAAC;CAChD,UAAU,SAAS,aAAa;AACpC,CAAC;;;;;;AAOD,MAAM,qBAAqB,OAAO,aAAa,EAC3C,YAAY,SAAS,WAAW,EACpC,CAAC;;;;;;;;AASD,MAAM,YAAY,OAAO;CACrB,MAAM,OAAO;;CAEb,WAAW,OAAO;CAClB,QAAQ,SAAS,OAAO,CAAC;CACzB,SAAS,SAAS,OAAO,CAAC;AAC9B,CAAC;;;;;;;;;;AAWD,MAAM,oBAAoB,OAAO;CAC7B,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,aAAa,MAAM,WAAW;CAC9B,aAAa,SAAS,OAAO,CAAC;CAC9B,YAAY,SAAS,OAAO,CAAC;CAC7B,OAAO,OAAO;CACd,kBAAkB,OAAO;EACrB,YAAY,SAAS,OAAO;GAAE,OAAO,OAAO;GAAG,KAAK,OAAO;EAAE,CAAC,CAAC;EAC/D,MAAM,SAAS,OAAO;GAAE,OAAO,OAAO;GAAG,KAAK,OAAO;EAAE,CAAC,CAAC;CAC7D,CAAC;AACL,CAAC;;AAGD,MAAM,YAAYA,OAAM;CAAC;CAAQ;CAAc;CAAa;AAAY,CAAC;;AAKzE,MAAM,gBAAgB,OAAO;CACzB,IAAI,OAAO;CACX,MAAM,SAAS,OAAO,CAAC;;CAEvB,UAAU,SAAS,QAAQ,CAAC;AAChC,CAAC;;AAGD,MAAM,iBAAiB,OAAO;CAC1B,aAAa,OAAO;CACpB,QAAQ;;CAER,UAAU,SAAS,QAAQ,CAAC;AAChC,CAAC;;;;;;AAOD,MAAM,eAAe,OAAO;CACxB,YAAY,MAAM,aAAa;CAC/B,SAAS,SAAS,MAAM,cAAc,CAAC;AAC3C,CAAC;;AAGD,MAAM,gBAAgB,OAAO;CACzB,WAAW,OAAO;CAClB,qBAAqB,MAAM,OAAO,CAAC;AACvC,CAAC;;;;;;;AAQD,MAAM,iBAAiB,mBAAmB,MAAM,CAC5C,OAAO;CAAE,IAAI,QAAQ,KAAK;CAAG,MAAM,OAAO;CAAG,OAAO,QAAQ;AAAE,CAAC,GAC/D,OAAO;CAAE,IAAI,QAAQ,QAAQ;CAAG,MAAM,OAAO;AAAE,CAAC,CACpD,CAAC;;;;;;;;;;;AAYD,MAAa,gCAAgC,gBACzC;CACI,IAAI;CACJ,aAAa;AACjB,GACA,EACI,mBAAmB,YACf,OAAO,EACH,iBAAiB,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,EAChD,CAAC,GACD,OAAO,CAAC,CAAC,CACb,EACJ,CACJ;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,+BAA+B,gBACxC;CACI,IAAI;CACJ,aAAa;AACjB,GACA;;;;;;;;;;CAUI,KAAK,YACD,OAAO,CAAC,CAAC,GACT,OAAO,EACH,2BAA2B,OAAO,EACtC,CAAC,CACL;;;;;;;;;CAUA,iBAAiB,YACb,OAAO,CAAC,CAAC,GACT,OAAO,EACH,cAAc,OAAO,EACzB,CAAC,CACL;;;;;;;;;;CAWA,UAAU,YACN,OAAO,EAAE,WAAW,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,GAClD,OAAO,CAAC,CAAC,CACb;AACJ,CACJ;;;;;;;;;;;;;;;;;;AAmBA,MAAa,qBAAqB,gBAC9B;CACI,IAAI;CACJ,aAAa;AACjB,GACA;CACI,SAAS,YACL,OAAO;EACH,UAAU;EACV,cAAc,OAAO,OAAO,GAAG,YAAY;EAC3C,UAAU,SAAS,SAAS;CAChC,CAAC,GACD,mBAAmB,UAAU;EACzB,OAAO;GACH,QAAQ,QAAQ,SAAS;GACzB,OAAO,OAAO,OAAO,GAAG,aAAa;;;;;;;;;;;GAWrC,cAAc,MAAM,iBAAiB;EACzC,CAAC;EACD,OAAO;GACH,QAAQ,QAAQ,QAAQ;GACxB,QAAQ,SAAS,OAAO,CAAC;EAC7B,CAAC;EACD,OAAO;GACH,QAAQ,QAAQ,cAAc;;GAE9B,OAAO,MAAM,OAAO,CAAC;EACzB,CAAC;CACL,CAAC,CACL;;;;;;;;;;;;;;;;;;;;;;;CAwBA,QAAQ,YACJ,OAAO;EACH,UAAU;;;;;;EAMV,WAAW,OAAO;;;;;;EAMlB,OAAO,MAAM,cAAc;EAC3B,UAAU,SAAS,SAAS;CAChC,CAAC,GACD,mBAAmB,UAAU,CACzB,OAAO;EACH,QAAQ,QAAQ,SAAS;EACzB,WAAW,OAAO;;EAElB,SAAS,MACL,OAAO;GACH,aAAa,OAAO;GACpB,QAAQ;EACZ,CAAC,CACL;;;;;;EAMA,cAAc,SAAS,MAAM,iBAAiB,CAAC;CACnD,CAAC,GACD,OAAO;EACH,QAAQ,QAAQ,QAAQ;EACxB,QAAQ,SAAS,OAAO,CAAC;CAC7B,CAAC,CAOL,CAAC,CACL;;;;;;;;;;;;;;;;;;;;;CAsBA,eAAe,YACX,OAAO;EACH,UAAU;EACV,aAAa,MAAM,kBAAkB,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC;EACzD,UAAU,SAAS,SAAS;CAChC,CAAC,GACD,mBAAmB,UAAU,CACzB,OAAO;EACH,QAAQ,QAAQ,SAAS;EACzB,cAAc,MAAM,iBAAiB;CACzC,CAAC,GACD,OAAO;EACH,QAAQ,QAAQ,QAAQ;EACxB,QAAQ,SAAS,OAAO,CAAC;CAC7B,CAAC,CACL,CAAC,CACL;AACJ,CACJ;;;;;;;;;;;;;;;;;AAsBA,MAAM,qBAAqB,MAAM,OAAO,CAAC;;;;;;;;;;;AAYzC,MAAM,mBAAmB,mBAAmB,QAAQ,CAChD,OAAO,cAAc;CACjB,MAAM,QAAQ,UAAU;;CAExB,UAAU;;CAEV,QAAQ,SAAS,OAAO,CAAC;CACzB,UAAU,SAAS,SAAS;;CAE5B,mBAAmB,SAAS,kBAAkB;;;;;;;;;;CAU9C,QAAQ,SAAS,OAAO,OAAO,GAAG,QAAQ,CAAC,CAAC;AAChD,CAAC,GACD,OAAO;CACH,MAAM,QAAQ,QAAQ;;CAEtB,UAAU;CACV,QAAQ,SAAS,OAAO,CAAC;CACzB,aAAa,MAAM,kBAAkB,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC;CACzD,UAAU,SAAS,SAAS;;CAE5B,mBAAmB,SAAS,kBAAkB;;CAE9C,QAAQ,SAAS,OAAO,OAAO,GAAG,QAAQ,CAAC,CAAC;AAChD,CAAC,CACL,CAAC;;;;;;AAOD,MAAM,gBAAgB,mBAAmB,QAAQ,CAC7C,OAAO,eAAe;CAClB,MAAM,QAAQ,UAAU;CACxB,cAAc,MAAM,iBAAiB;AACzC,CAAC,GACD,OAAO;CACH,MAAM,QAAQ,QAAQ;CACtB,cAAc,MAAM,iBAAiB;AACzC,CAAC,CACL,CAAC;;;;;;;AAQD,MAAM,gBAAgB,mBAAmB,UAAU,CAC/C,OAAO;CAAE,QAAQ,QAAQ,SAAS;CAAG,SAAS;AAAc,CAAC,GAC7D,OAAO;CAAE,QAAQ,QAAQ,QAAQ;CAAG,QAAQ,SAAS,OAAO,CAAC;AAAE,CAAC,CACpE,CAAC;;;;;;;;;;;;;;;;;;;;;AAsBD,MAAa,6BAA6B,gBACtC;CACI,IAAI;CACJ,aACI;AAGR,GACA;;CAGI,YAAY,YACR,OAAO,CAAC,CAAC,GACT,OAAO;;;;;;EAMH,WAAW,OAAO,OAAO,GAAG,gBAAgB;;EAE5C,UAAU,OAAO;CACrB,CAAC,CACL,CAAC,CAAC,WAAW,EAAE,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC;;;;;;CAMnC,cAAc,YACV,OAAO,CAAC,CAAC,GACT,OAAO,CAAC,CAAC,CACb,CAAC,CAAC,WAAW,EAAE,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC;;CAInC,YAAY,YACR,OAAO,CAAC,CAAC,GACT,OAAO;;EAEH,SAAS,OAAO,OAAO,GAAG,aAAa;;EAEvC,UAAU,OAAO;CACrB,CAAC,CACL;;;;;;;;CAQA,YAAY,YACR,OAAO,EAAE,SAAS,MAAM,cAAc,EAAE,CAAC,GACzC,OAAO,EAAE,UAAU,OAAO,EAAE,CAAC,CACjC,CAAC,CAAC,WAAW,EAAE,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC;;;;;;CAMnC,cAAc,YACV,OAAO,CAAC,CAAC,GACT,OAAO,CAAC,CAAC,CACb,CAAC,CAAC,WAAW,EAAE,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC;AACvC,CACJ"}