@hediet/linkrpc 0.0.2 → 0.0.3

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 (33) hide show
  1. package/README.md +141 -3
  2. package/dist/chunks/{hub.interfaces-Bf4VfWNX.js → hub.interfaces-BWqqhgtT.js} +2 -2
  3. package/dist/chunks/{hub.interfaces-Bf4VfWNX.js.map → hub.interfaces-BWqqhgtT.js.map} +1 -1
  4. package/dist/chunks/{hubAccess-C06qAKao.d.ts → hubAccess-DKl7hDrh.d.ts} +2 -2
  5. package/dist/chunks/{hubAccess-C06qAKao.d.ts.map → hubAccess-DKl7hDrh.d.ts.map} +1 -1
  6. package/dist/chunks/{hubFacade-DtQpGpUy.d.ts → hubFacade-CLgLIvBa.d.ts} +2 -2
  7. package/dist/chunks/{hubFacade-DtQpGpUy.d.ts.map → hubFacade-CLgLIvBa.d.ts.map} +1 -1
  8. package/dist/chunks/{hubFacade-BIB9CoAv.js → hubFacade-rlsBq0ZU.js} +2 -2
  9. package/dist/chunks/{hubFacade-BIB9CoAv.js.map → hubFacade-rlsBq0ZU.js.map} +1 -1
  10. package/dist/chunks/{boundedTrafficSubscription-XZ1KwXZC.js → inspectionHost-BA08eF6h.js} +766 -4
  11. package/dist/chunks/inspectionHost-BA08eF6h.js.map +1 -0
  12. package/dist/chunks/{linkRpcConnection-BadD37ok.d.ts → linkRpcConnection-C_Gs4nZ9.d.ts} +2061 -1682
  13. package/dist/chunks/linkRpcConnection-C_Gs4nZ9.d.ts.map +1 -0
  14. package/dist/chunks/{src-CAhXne71.js → src-BaCs8mWd.js} +2512 -2657
  15. package/dist/chunks/src-BaCs8mWd.js.map +1 -0
  16. package/dist/hub/client/index.d.ts +3 -3
  17. package/dist/hub/client/index.js +3 -3
  18. package/dist/hub/common/index.d.ts +2 -325
  19. package/dist/hub/common/index.d.ts.map +1 -1
  20. package/dist/hub/common/index.js +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +3 -3
  23. package/dist/inspection/index.d.ts +87 -2
  24. package/dist/inspection/index.d.ts.map +1 -1
  25. package/dist/inspection/index.js +2 -2
  26. package/dist/node.d.ts +3 -3
  27. package/dist/node.js +4 -4
  28. package/dist/web.d.ts +2 -2
  29. package/dist/web.js +3 -3
  30. package/package.json +7 -2
  31. package/dist/chunks/boundedTrafficSubscription-XZ1KwXZC.js.map +0 -1
  32. package/dist/chunks/linkRpcConnection-BadD37ok.d.ts.map +0 -1
  33. package/dist/chunks/src-CAhXne71.js.map +0 -1
package/README.md CHANGED
@@ -132,6 +132,140 @@ g.shout({ msg: 'boom' }); // fire-and-forget notif
132
132
  Pass the wrong shape and TypeScript stops you at compile time; if a bad value reaches the wire
133
133
  anyway, the provider rejects it with a JSON-RPC `-32602 invalidParams`.
134
134
 
135
+ ## Static contracts and reusable bindings
136
+
137
+ `StaticHubSchemaDocument`, `InterfaceRef`, and `parseStaticHubSchema` are library
138
+ APIs, independent of the CLI. A document contains `interfaceSchemas` and optional
139
+ `services`, `defaultInterface`, and `bareInterfaces`:
140
+
141
+ ```ts
142
+ const ref = { interfaceId: greeter.info.id, interfaceHash: greeter.schemaHash };
143
+ const contract = parseStaticHubSchema({
144
+ interfaceSchemas: [greeter.toSchema()],
145
+ services: [{ serviceId: '', interfaces: [ref] }],
146
+ defaultInterface: ref,
147
+ bareInterfaces: [{ interface: ref, prefix: 'Runtime.' }],
148
+ });
149
+ ```
150
+
151
+ Every reference must resolve to an exact id/hash pair, and every declared schema
152
+ hash is verified. Duplicate services, interfaces within a service, and bare
153
+ prefixes are rejected. Overlapping prefixes retain longest-prefix routing;
154
+ an empty bare prefix may coexist with `defaultInterface` only for the same ref.
155
+ The default and a root-qualified interface with the same id must also use the
156
+ same hash; different versions under named services remain independent.
157
+ Schema-only and bare-only documents do not need `services`.
158
+
159
+ The same interface definition can be used with immutable typed descriptors:
160
+
161
+ ```ts
162
+ import { interfaceTarget, defaultInterfaceTarget, bareInterfaceTarget } from '@hediet/linkrpc';
163
+
164
+ const root = interfaceTarget(greeter); // test.greeter::hello
165
+ const service = interfaceTarget(greeter, { serviceId: 'app' }); // app::test.greeter::hello
166
+ const preset = defaultInterfaceTarget(greeter); // hello, LinkRPC metadata
167
+ const foreign = bareInterfaceTarget(greeter, { prefix: 'Runtime.' }); // Runtime.hello, no metadata
168
+
169
+ await connection.get(service).hello({ name: 'world' });
170
+ connection.register(service, { hello: ({ name }) => ({ greeting: name }), shout: () => {} });
171
+ ```
172
+
173
+ `get` and `register` accept all descriptors. Existing definition-based overloads,
174
+ `service()`, `getBare()`, and `bareInterfaceTarget()` remain supported. Default
175
+ targets retain interface-hash metadata and streaming; bare targets deliberately
176
+ omit metadata and reject streaming clients. Registering a default or bare target
177
+ also installs its qualified interface registration, exactly as existing bare
178
+ registration does. Do not register its root alias a second time. Duplicate
179
+ registrations and occupied prefixes still fail atomically; disposal removes the
180
+ registration and its binding.
181
+
182
+ `generateTsContract(contract, options)` produces a single TypeScript module with
183
+ one definition per schema and separate bindings (no duplicated interface types).
184
+ It composes `generateTsInterface` and preserves canonical wire schemas. Options
185
+ include `linkRpcImport`, `interfaceNames` keyed by `id@hash`, and `bindingNames`
186
+ keyed by `root:id@hash`, `service:serviceId:id@hash`, `default`, or `bare:prefix`.
187
+ Derived export names are deterministic; ambiguous names require explicit
188
+ overrides rather than order-dependent suffixes. Unknown overrides are errors.
189
+
190
+ `exportStaticHubSchema(channel, { serviceId?, maxDepth?, timeoutMs? })` reflects
191
+ directory interfaces, `defaults.get`, and `defaults.listBindings`, retrieves and
192
+ verifies schemas, and returns this same document. Missing reflection, inaccessible
193
+ or depth-limited directories, truncation, incomplete defaults, and schema failures
194
+ are errors, not partial successful contracts. `serviceId` selects the reflection
195
+ scope; default/bare descriptors describe the preset routes reported by that
196
+ scope and must be used against the corresponding endpoint. Diagnostic directory
197
+ graphs are not part of the static contract.
198
+
199
+ ## Inspecting independently owned connections
200
+
201
+ `InspectionHost` exposes one topology and traffic view through any number of
202
+ LinkRPC connections. It does not route application messages and does not require
203
+ a Hub. Tracking a connection and exposing inspection are separate operations:
204
+
205
+ ```ts
206
+ import { InspectionHost } from '@hediet/linkrpc/inspection';
207
+
208
+ const inspection = new InspectionHost({ nodeId: 'main', label: 'Main process' });
209
+
210
+ // cdpClient is a LinkRpcConnection over a CDP adapter.
211
+ const tracked = inspection.trackConnection(cdpClient, {
212
+ portId: 'cdp-1',
213
+ label: 'Chrome connection',
214
+ peer: { nodeId: 'chrome', portId: 'debugger' },
215
+ transport: { type: 'websocket' },
216
+ });
217
+
218
+ // Repeat for each frontend connection; they share the same inspection host.
219
+ const binding = inspection.expose(frontendConnection, {
220
+ serviceId: 'main.inspection',
221
+ });
222
+ frontendConnection.enableReflection();
223
+ ```
224
+
225
+ The remote frontend uses the standard inspection interfaces:
226
+
227
+ ```ts
228
+ import { topologyInterface, trafficInterface } from '@hediet/linkrpc/inspection';
229
+
230
+ const service = frontendClient.service('main.inspection');
231
+ const graph = await service.get(topologyInterface).getGraph({});
232
+ const watch = service.get(trafficInterface).watch({}, {
233
+ onMessage: event => console.log(event),
234
+ });
235
+
236
+ // Later:
237
+ await watch.cancel();
238
+ await watch;
239
+ ```
240
+
241
+ - Tracked connections share the host's node identity and have distinct port IDs.
242
+ Peer identity is optional; without it, the graph includes the local port but
243
+ does not invent a remote node or probe a foreign protocol.
244
+ - `watchGraph` emits invalidation ticks; re-fetch `getGraph` after each tick.
245
+ Adding/removing sources and bindings, closing tracked connections, and source
246
+ topology changes invalidate the graph.
247
+ - `watch` omits payloads. `watchWithPayloads` explicitly requests capped payloads.
248
+ Use the connection's normal authentication/authorization policy to restrict
249
+ inspection access; topology IDs are not security identities.
250
+ - Each subscriber has independent filtering and a bounded queue with overflow
251
+ reporting. Watch-control flows remain tracked even without subscribers, so
252
+ inspection streams never recursively observe themselves. Ordinary frontend
253
+ traffic is not included unless that connection is explicitly tracked.
254
+ - `binding.dispose()` unregisters that exposure and ends its watches.
255
+ `tracked.dispose()` removes that connection from inspection.
256
+ `inspection.dispose()` removes all exposures and observations.
257
+ None of these closes application connections. `LinkRpcConnection.close()`
258
+ automatically removes its bindings and tracked ports; adapters must still
259
+ propagate transport shutdown to the connection's lifecycle.
260
+ - CDP traffic is observed above the adapter: events contain normalized JSON-RPC
261
+ messages and logical request IDs, not exact CDP WebSocket frames.
262
+
263
+ For custom producers, `addSource` accepts an `InspectionSource` supplying topology
264
+ snapshots, topology invalidations, and normalized traffic. The Hub uses this same
265
+ host through a routing-source adapter. `connection.enableInspection()` remains
266
+ the convenience API for inspecting just that endpoint, using the same shared
267
+ RPC implementation.
268
+
135
269
  ## Typed application errors
136
270
 
137
271
  Checked application errors are opt-in and remain ordinary JSON-RPC errors on the wire. Declare
@@ -200,11 +334,15 @@ runtime:
200
334
 
201
335
  - **`hubrpc.directory`** — which services and interfaces this connection serves (each with its `id@hash`).
202
336
  - **`hubrpc.schemas`** — the full schema for any advertised interface.
203
- - **`hubrpc.defaults`** — the connection's preset service/interface, if any (`setPreset(iface)`).
337
+ - **`hubrpc.defaults`** — the connection's empty-prefix bare interface registration, if any.
204
338
 
205
339
  ```ts
206
- connection.register(greeter, handlers);
207
- connection.setPreset(greeter); // lets callers use the bare `hello` form
340
+ connection.register(bareInterfaceTarget(greeter), handlers);
341
+ // The interface remains available as `test.greeter::hello` and also as bare `hello`.
342
+ connection.service('acme').register(
343
+ bareInterfaceTarget(documents, { prefix: 'documents/' }),
344
+ documentHandlers,
345
+ );
208
346
  connection.enableReflection(); // directory / schemas / defaults, for free
209
347
  ```
210
348
 
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { B as requestType, C as defineInterface } from "./boundedTrafficSubscription-XZ1KwXZC.js";
5
+ import { U as defineInterface, ot as requestType } from "./inspectionHost-BA08eF6h.js";
6
6
  import { array, boolean, discriminatedUnion, enum as enum$1, extend, literal, minLength, number, object, optional, record, string, union, unknown } from "zod/mini";
7
7
  //#region src/hub/common/hub.interfaces.ts
8
8
  const zMemberPattern = union([object({ exact: string() }), object({ prefix: string() })]);
@@ -523,4 +523,4 @@ const hubAccessManifestInterface = defineInterface({
523
523
  //#endregion
524
524
  export { hubServiceIdRegistryInterface as i, hubAccessManifestInterface as n, hubGrantedServiceIdInterface as r, hubAccessInterface as t };
525
525
 
526
- //# sourceMappingURL=hub.interfaces-Bf4VfWNX.js.map
526
+ //# sourceMappingURL=hub.interfaces-BWqqhgtT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hub.interfaces-Bf4VfWNX.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":"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"}
1
+ {"version":3,"file":"hub.interfaces-BWqqhgtT.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":"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"}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { Pn as SignedCapability } from "./linkRpcConnection-BadD37ok.js";
5
+ import { Fr as SignedCapability } from "./linkRpcConnection-C_Gs4nZ9.js";
6
6
  //#region src/hub/common/hubAccess.d.ts
7
7
  /**
8
8
  * The client-facing wire shapes of the hub's capability-negotiation protocol
@@ -76,4 +76,4 @@ declare function findCoveringCapabilities(capabilities: readonly SignedCapabilit
76
76
  }): readonly SignedCapability[] | undefined;
77
77
  //#endregion
78
78
  export { HubAccessResult as a, HubAccessRequest as i, HubAccessPattern as n, findCoveringCapabilities as o, HubAccessPermission as r, HubAccessDuration as t };
79
- //# sourceMappingURL=hubAccess-C06qAKao.d.ts.map
79
+ //# sourceMappingURL=hubAccess-DKl7hDrh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hubAccess-C06qAKao.d.ts","names":[],"sources":["../../src/hub/common/hubAccess.ts"],"mappings":";;;;;;;;;;;;;KAqBY;;KAGA;WAA8B;;WAA8B;;;UAGvD;WACJ;aACI,WAAW;aACX,aAAa;aACb;aACA,kBAAkB;;;WAGtB;;WAEA;WACA,SAAS;;;UAIL;WACJ;aAAqB;aAAuB;aAA0B;;;WAEtE,sBAAsB;;WAEtB,WAAW;;;;;;;KAQZ;WAEK;;WAEA,uBAAuB;;WAEvB;;WAEA;WAA2B;;WAC3B;WAAyB;;;;;;;;;;iBAU1B,yBACZ,uBAAuB,oBACvB,oBAAoB,uBACpB;WACa;WACA;aAEL"}
1
+ {"version":3,"file":"hubAccess-DKl7hDrh.d.ts","names":[],"sources":["../../src/hub/common/hubAccess.ts"],"mappings":";;;;;;;;;;;;;KAqBY;;KAGA;WAA8B;;WAA8B;;;UAGvD;WACJ;aACI,WAAW;aACX,aAAa;aACb;aACA,kBAAkB;;;WAGtB;;WAEA;WACA,SAAS;;;UAIL;WACJ;aAAqB;aAAuB;aAA0B;;;WAEtE,sBAAsB;;WAEtB,WAAW;;;;;;;KAQZ;WAEK;;WAEA,uBAAuB;;WAEvB;;WAEA;WAA2B;;WAC3B;WAAyB;;;;;;;;;;iBAU1B,yBACZ,uBAAuB,oBACvB,oBAAoB,uBACpB;WACa;WACA;aAEL"}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { a as LinkRpcConnection } from "./linkRpcConnection-BadD37ok.js";
5
+ import { a as LinkRpcConnection } from "./linkRpcConnection-C_Gs4nZ9.js";
6
6
  //#region src/hub/client/hubFacade.d.ts
7
7
  /**
8
8
  * Description of the services a consumer will need, presented to the user
@@ -98,4 +98,4 @@ declare class Hub {
98
98
  declare function hubFromConnection(connection: LinkRpcConnection): Hub;
99
99
  //#endregion
100
100
  export { hubFromConnection as i, SlotPrerequest as n, SlotReservation as r, Hub as t };
101
- //# sourceMappingURL=hubFacade-DtQpGpUy.d.ts.map
101
+ //# sourceMappingURL=hubFacade-CLgLIvBa.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hubFacade-DtQpGpUy.d.ts","names":[],"sources":["../../src/hub/client/hubFacade.ts"],"mappings":";;;;;;;;;;;;UASiB;WACJ;aAAqB;aAAuB;;WAC5C,cAAc,SACnB;aACa;eAAgC;;aAChC;eACI;eACA;iBAAmB;;;;;;UAO3B;;EAEb,WAAW;;;;;;;;cASF;mBACoB;EAAA,YAAA,aAAa;;EAGnC,qBAAiB;;;;;;;;EASjB,gBAAgB,UAAU,iBAAiB;;;;;;;;;;;;;;;;;;;;;EA4BrC,2BACT,4BACA;aAAmB;MACpB;;;;;;;;;;;;;;;;;EAsBU,kCAAkC;aAAmB;;;;iBAetD,kBAAkB,YAAY,oBAAoB"}
1
+ {"version":3,"file":"hubFacade-CLgLIvBa.d.ts","names":[],"sources":["../../src/hub/client/hubFacade.ts"],"mappings":";;;;;;;;;;;;UASiB;WACJ;aAAqB;aAAuB;;WAC5C,cAAc,SACnB;aACa;eAAgC;;aAChC;eACI;eACA;iBAAmB;;;;;;UAO3B;;EAEb,WAAW;;;;;;;;cASF;mBACoB;EAAA,YAAA,aAAa;;EAGnC,qBAAiB;;;;;;;;EASjB,gBAAgB,UAAU,iBAAiB;;;;;;;;;;;;;;;;;;;;;EA4BrC,2BACT,4BACA;aAAmB;MACpB;;;;;;;;;;;;;;;;;EAsBU,kCAAkC;aAAmB;;;;iBAetD,kBAAkB,YAAY,oBAAoB"}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { r as hubGrantedServiceIdInterface } from "./hub.interfaces-Bf4VfWNX.js";
5
+ import { r as hubGrantedServiceIdInterface } from "./hub.interfaces-BWqqhgtT.js";
6
6
  //#region src/hub/client/hubFacade.ts
7
7
  /**
8
8
  * Thin façade over the hub's own serviceId-routed services
@@ -82,4 +82,4 @@ function hubFromConnection(connection) {
82
82
  //#endregion
83
83
  export { hubFromConnection as n, Hub as t };
84
84
 
85
- //# sourceMappingURL=hubFacade-BIB9CoAv.js.map
85
+ //# sourceMappingURL=hubFacade-rlsBq0ZU.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hubFacade-BIB9CoAv.js","names":[],"sources":["../../src/hub/client/hubFacade.ts"],"sourcesContent":["import type { LinkRpcConnection } from '../../connection/linkRpcConnection';\nimport { hubGrantedServiceIdInterface } from '../common/hub.interfaces';\n\n/**\n * Description of the services a consumer will need, presented to the user\n * up-front so access can be approved before the first call. Each named\n * *dependency* (\"slot\") lists the interfaces the chosen service must\n * implement and the members the consumer intends to call.\n */\nexport interface SlotPrerequest {\n readonly consumer: { readonly name: string; readonly purpose: string; };\n readonly dependencies: Readonly<\n Record<string, {\n readonly interfaces: readonly { readonly id: string; }[];\n readonly members: readonly {\n readonly interfaceId: string;\n readonly member: { readonly exact: string; };\n }[];\n }>\n >;\n}\n\n/** Handle for a set of slots reserved via {@link Hub.prerequestSlots}. */\nexport interface SlotReservation {\n /** Resolve the reserved slots into connected service clients. */\n resolve(): Promise<never>;\n}\n\n/**\n * Thin façade over the hub's own serviceId-routed services\n * (`hubGrantedServiceId`, `hubAccess`, …). The hub is not a single object on\n * the wire — it is a set of services the connection can `get`. This groups the\n * common connection calls so callers don't hand-route interface clients.\n */\nexport class Hub {\n constructor(private readonly _connection: LinkRpcConnection) { }\n\n /** `hubGrantedServiceId::get` — where am I and which serviceId namespace may I claim. */\n public getConnectionInfo() {\n return this._connection.get(hubGrantedServiceIdInterface).get({});\n }\n\n /**\n * Reserve the slots a consumer will need so the user can approve them\n * ahead of the first call. NOT YET IMPLEMENTED by the hub — the\n * returned reservation throws on {@link SlotReservation.resolve}.\n */\n public prerequestSlots(_request: SlotPrerequest): SlotReservation {\n return {\n resolve: async (): Promise<never> => {\n throw new Error('not implemented: hub.prerequestSlots / slot resolution');\n },\n };\n }\n\n /**\n * Claim a serviceId namespace for this connection so it may register\n * services under it, via `hubGrantedServiceId::register`.\n *\n * The claim is auto-granted from the connection's provenance when\n * `serviceIdNamespace` is at/under the connection's\n * `grantedServiceIdNamespace` (see {@link getConnectionInfo}) — no\n * signature or capability needed. Claims **outside** the granted namespace\n * are rejected here; route those through the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.\n *\n * Resolves once the namespace is owned by this connection (idempotent for\n * a namespace this connection already owns). Rejects when the hub denies\n * the claim — e.g. the namespace is owned by another identity, or the\n * caller lacks admin authority outside its granted namespace.\n *\n * `requestPermissionIfDenied` is a hint for the future interactive\n * admin-approval flow; the hub does not yet expose one, so denial always\n * surfaces as a rejection regardless of the flag.\n */\n public async registerServiceIdNamespace(\n serviceIdNamespace: string,\n _opts?: { readonly requestPermissionIfDenied?: boolean; },\n ): Promise<void> {\n await this._connection\n .get(hubGrantedServiceIdInterface)\n .register({ serviceId: serviceIdNamespace });\n }\n\n /**\n * Claim this connection's provenance-granted serviceId namespace in one\n * step: read `grantedServiceIdNamespace` via {@link getConnectionInfo},\n * then {@link registerServiceIdNamespace} it, returning the claimed\n * `serviceId` so the caller can mount services under it.\n *\n * This is the batteries-included version of the\n * `hubGrantedServiceId::get` → `hubGrantedServiceId::register` dance a\n * service-exposing participant performs right after connecting.\n *\n * Throws when the hub granted this connection no namespace (an empty\n * `grantedServiceIdNamespace`, meaning \"claim nothing freely\") — there is\n * nothing to register, and any service prefix would have to be claimed\n * through the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.\n */\n public async claimGrantedServiceIdNamespace(): Promise<{ readonly serviceId: string; }> {\n const { grantedServiceIdNamespace } = await this.getConnectionInfo();\n if (!grantedServiceIdNamespace) {\n throw new Error(\n 'hubGrantedServiceId::get returned an empty granted namespace; ' +\n 'nothing to claim (register a prefix through the admin-gated ' +\n 'hubServiceIdRegistry::registerServiceId door instead)',\n );\n }\n await this.registerServiceIdNamespace(grantedServiceIdNamespace);\n return { serviceId: grantedServiceIdNamespace };\n }\n}\n\n/** Wrap a connection in a {@link Hub} façade. */\nexport function hubFromConnection(connection: LinkRpcConnection): Hub {\n return new Hub(connection);\n}\n"],"mappings":";;;;;;;;;;;;AAkCA,IAAa,MAAb,MAAiB;CACgB;CAA7B,YAAY,aAAiD;EAAhC,KAAA,cAAA;CAAkC;;CAG/D,oBAA2B;EACvB,OAAO,KAAK,YAAY,IAAI,4BAA4B,CAAC,CAAC,IAAI,CAAC,CAAC;CACpE;;;;;;CAOA,gBAAuB,UAA2C;EAC9D,OAAO,EACH,SAAS,YAA4B;GACjC,MAAM,IAAI,MAAM,wDAAwD;EAC5E,EACJ;CACJ;;;;;;;;;;;;;;;;;;;;;CAsBA,MAAa,2BACT,oBACA,OACa;EACb,MAAM,KAAK,YACN,IAAI,4BAA4B,CAAC,CACjC,SAAS,EAAE,WAAW,mBAAmB,CAAC;CACnD;;;;;;;;;;;;;;;;;CAkBA,MAAa,iCAA2E;EACpF,MAAM,EAAE,8BAA8B,MAAM,KAAK,kBAAkB;EACnE,IAAI,CAAC,2BACD,MAAM,IAAI,MACN,iLAGJ;EAEJ,MAAM,KAAK,2BAA2B,yBAAyB;EAC/D,OAAO,EAAE,WAAW,0BAA0B;CAClD;AACJ;;AAGA,SAAgB,kBAAkB,YAAoC;CAClE,OAAO,IAAI,IAAI,UAAU;AAC7B"}
1
+ {"version":3,"file":"hubFacade-rlsBq0ZU.js","names":[],"sources":["../../src/hub/client/hubFacade.ts"],"sourcesContent":["import type { LinkRpcConnection } from '../../connection/linkRpcConnection';\nimport { hubGrantedServiceIdInterface } from '../common/hub.interfaces';\n\n/**\n * Description of the services a consumer will need, presented to the user\n * up-front so access can be approved before the first call. Each named\n * *dependency* (\"slot\") lists the interfaces the chosen service must\n * implement and the members the consumer intends to call.\n */\nexport interface SlotPrerequest {\n readonly consumer: { readonly name: string; readonly purpose: string; };\n readonly dependencies: Readonly<\n Record<string, {\n readonly interfaces: readonly { readonly id: string; }[];\n readonly members: readonly {\n readonly interfaceId: string;\n readonly member: { readonly exact: string; };\n }[];\n }>\n >;\n}\n\n/** Handle for a set of slots reserved via {@link Hub.prerequestSlots}. */\nexport interface SlotReservation {\n /** Resolve the reserved slots into connected service clients. */\n resolve(): Promise<never>;\n}\n\n/**\n * Thin façade over the hub's own serviceId-routed services\n * (`hubGrantedServiceId`, `hubAccess`, …). The hub is not a single object on\n * the wire — it is a set of services the connection can `get`. This groups the\n * common connection calls so callers don't hand-route interface clients.\n */\nexport class Hub {\n constructor(private readonly _connection: LinkRpcConnection) { }\n\n /** `hubGrantedServiceId::get` — where am I and which serviceId namespace may I claim. */\n public getConnectionInfo() {\n return this._connection.get(hubGrantedServiceIdInterface).get({});\n }\n\n /**\n * Reserve the slots a consumer will need so the user can approve them\n * ahead of the first call. NOT YET IMPLEMENTED by the hub — the\n * returned reservation throws on {@link SlotReservation.resolve}.\n */\n public prerequestSlots(_request: SlotPrerequest): SlotReservation {\n return {\n resolve: async (): Promise<never> => {\n throw new Error('not implemented: hub.prerequestSlots / slot resolution');\n },\n };\n }\n\n /**\n * Claim a serviceId namespace for this connection so it may register\n * services under it, via `hubGrantedServiceId::register`.\n *\n * The claim is auto-granted from the connection's provenance when\n * `serviceIdNamespace` is at/under the connection's\n * `grantedServiceIdNamespace` (see {@link getConnectionInfo}) — no\n * signature or capability needed. Claims **outside** the granted namespace\n * are rejected here; route those through the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.\n *\n * Resolves once the namespace is owned by this connection (idempotent for\n * a namespace this connection already owns). Rejects when the hub denies\n * the claim — e.g. the namespace is owned by another identity, or the\n * caller lacks admin authority outside its granted namespace.\n *\n * `requestPermissionIfDenied` is a hint for the future interactive\n * admin-approval flow; the hub does not yet expose one, so denial always\n * surfaces as a rejection regardless of the flag.\n */\n public async registerServiceIdNamespace(\n serviceIdNamespace: string,\n _opts?: { readonly requestPermissionIfDenied?: boolean; },\n ): Promise<void> {\n await this._connection\n .get(hubGrantedServiceIdInterface)\n .register({ serviceId: serviceIdNamespace });\n }\n\n /**\n * Claim this connection's provenance-granted serviceId namespace in one\n * step: read `grantedServiceIdNamespace` via {@link getConnectionInfo},\n * then {@link registerServiceIdNamespace} it, returning the claimed\n * `serviceId` so the caller can mount services under it.\n *\n * This is the batteries-included version of the\n * `hubGrantedServiceId::get` → `hubGrantedServiceId::register` dance a\n * service-exposing participant performs right after connecting.\n *\n * Throws when the hub granted this connection no namespace (an empty\n * `grantedServiceIdNamespace`, meaning \"claim nothing freely\") — there is\n * nothing to register, and any service prefix would have to be claimed\n * through the admin-gated\n * `<hubServiceId>::hubServiceIdRegistry::registerServiceId` door instead.\n */\n public async claimGrantedServiceIdNamespace(): Promise<{ readonly serviceId: string; }> {\n const { grantedServiceIdNamespace } = await this.getConnectionInfo();\n if (!grantedServiceIdNamespace) {\n throw new Error(\n 'hubGrantedServiceId::get returned an empty granted namespace; ' +\n 'nothing to claim (register a prefix through the admin-gated ' +\n 'hubServiceIdRegistry::registerServiceId door instead)',\n );\n }\n await this.registerServiceIdNamespace(grantedServiceIdNamespace);\n return { serviceId: grantedServiceIdNamespace };\n }\n}\n\n/** Wrap a connection in a {@link Hub} façade. */\nexport function hubFromConnection(connection: LinkRpcConnection): Hub {\n return new Hub(connection);\n}\n"],"mappings":";;;;;;;;;;;;AAkCA,IAAa,MAAb,MAAiB;CACgB;CAA7B,YAAY,aAAiD;EAAhC,KAAA,cAAA;CAAkC;;CAG/D,oBAA2B;EACvB,OAAO,KAAK,YAAY,IAAI,4BAA4B,CAAC,CAAC,IAAI,CAAC,CAAC;CACpE;;;;;;CAOA,gBAAuB,UAA2C;EAC9D,OAAO,EACH,SAAS,YAA4B;GACjC,MAAM,IAAI,MAAM,wDAAwD;EAC5E,EACJ;CACJ;;;;;;;;;;;;;;;;;;;;;CAsBA,MAAa,2BACT,oBACA,OACa;EACb,MAAM,KAAK,YACN,IAAI,4BAA4B,CAAC,CACjC,SAAS,EAAE,WAAW,mBAAmB,CAAC;CACnD;;;;;;;;;;;;;;;;;CAkBA,MAAa,iCAA2E;EACpF,MAAM,EAAE,8BAA8B,MAAM,KAAK,kBAAkB;EACnE,IAAI,CAAC,2BACD,MAAM,IAAI,MACN,iLAGJ;EAEJ,MAAM,KAAK,2BAA2B,yBAAyB;EAC/D,OAAO,EAAE,WAAW,0BAA0B;CAClD;AACJ;;AAGA,SAAgB,kBAAkB,YAAoC;CAClE,OAAO,IAAI,IAAI,UAAU;AAC7B"}