wire-mesh-core 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/adapters/frame-codec.d.cts +1 -1
  2. package/dist/adapters/frame-codec.d.mts +1 -1
  3. package/dist/adapters/node-identity.d.cts +2 -2
  4. package/dist/adapters/node-identity.d.mts +2 -2
  5. package/dist/adapters/tcp-transport.d.cts +1 -1
  6. package/dist/adapters/tcp-transport.d.mts +1 -1
  7. package/dist/adapters/tls-transport.d.cts +1 -1
  8. package/dist/adapters/tls-transport.d.mts +1 -1
  9. package/dist/domain/capability-grant.cjs +3 -2
  10. package/dist/domain/capability-grant.d.cts +3 -3
  11. package/dist/domain/capability-grant.d.mts +3 -3
  12. package/dist/domain/capability-grant.mjs +2 -1
  13. package/dist/domain/capability-request.cjs +1 -1
  14. package/dist/domain/capability-request.d.cts +2 -2
  15. package/dist/domain/capability-request.d.mts +2 -2
  16. package/dist/domain/capability-request.mjs +1 -1
  17. package/dist/domain/device-id.d.cts +1 -1
  18. package/dist/domain/device-id.d.mts +1 -1
  19. package/dist/domain/grant-candidates.cjs +47 -0
  20. package/dist/domain/grant-candidates.d.cts +26 -0
  21. package/dist/domain/grant-candidates.d.mts +26 -0
  22. package/dist/domain/grant-candidates.mjs +45 -0
  23. package/dist/domain/handshake.d.cts +1 -1
  24. package/dist/domain/handshake.d.mts +1 -1
  25. package/dist/domain/mesh-session.d.cts +3 -3
  26. package/dist/domain/mesh-session.d.mts +3 -3
  27. package/dist/domain/relay-hub.d.cts +1 -1
  28. package/dist/domain/relay-hub.d.mts +1 -1
  29. package/dist/domain/revocation-view.cjs +12 -7
  30. package/dist/domain/revocation-view.d.cts +3 -3
  31. package/dist/domain/revocation-view.d.mts +3 -3
  32. package/dist/domain/revocation-view.mjs +13 -8
  33. package/dist/domain/room-token-verification.cjs +1 -1
  34. package/dist/domain/room-token-verification.d.cts +2 -2
  35. package/dist/domain/room-token-verification.d.mts +2 -2
  36. package/dist/domain/room-token-verification.mjs +1 -1
  37. package/dist/domain/tokens.cjs +1 -1
  38. package/dist/domain/tokens.d.cts +1 -1
  39. package/dist/domain/tokens.d.mts +1 -1
  40. package/dist/domain/tokens.mjs +1 -1
  41. package/dist/generated/protocol.cjs +2 -1
  42. package/dist/generated/protocol.d.cts +1 -1
  43. package/dist/generated/protocol.d.mts +1 -1
  44. package/dist/generated/protocol.mjs +2 -1
  45. package/dist/{identity-B7YMBhMf.d.mts → identity-5LJ_B8go.d.mts} +1 -1
  46. package/dist/{identity-COdFfaW8.d.cts → identity-bg6IVGsH.d.cts} +1 -1
  47. package/dist/ports/identity.d.cts +1 -1
  48. package/dist/ports/identity.d.mts +1 -1
  49. package/dist/ports/transport.d.cts +1 -1
  50. package/dist/ports/transport.d.mts +1 -1
  51. package/dist/{protocol-B3U828E7.d.cts → protocol-l9RMR3s5.d.cts} +1 -0
  52. package/dist/{protocol-B3U828E7.d.mts → protocol-l9RMR3s5.d.mts} +1 -0
  53. package/dist/token-scope-CxHXTT3u.cjs +43 -0
  54. package/dist/token-scope-Z4bmci4M.mjs +32 -0
  55. package/dist/{tokens-DSwixfDl.d.mts → tokens-CBI54oF-.d.mts} +4 -4
  56. package/dist/{tokens-BxTxBmXt.cjs → tokens-CiNXdKJ8.cjs} +30 -43
  57. package/dist/{tokens-D2aFwPcZ.d.cts → tokens-H_mV_JCC.d.cts} +4 -4
  58. package/dist/{tokens-D9I1Pn14.mjs → tokens-VicRWTj1.mjs} +28 -35
  59. package/dist/{transport-B_diuPHT.d.mts → transport-Baipikk7.d.cts} +1 -1
  60. package/dist/{transport-BrAqN6I5.d.cts → transport-DWbvUc3L.d.mts} +1 -1
  61. package/package.json +5 -1
@@ -1,4 +1,4 @@
1
- import { D as Frame } from "../protocol-B3U828E7.cjs";
1
+ import { D as Frame } from "../protocol-l9RMR3s5.cjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
@@ -1,4 +1,4 @@
1
- import { D as Frame } from "../protocol-B3U828E7.mjs";
1
+ import { D as Frame } from "../protocol-l9RMR3s5.mjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
@@ -1,5 +1,5 @@
1
- import { P as IdentityKey, x as DeviceId } from "../protocol-B3U828E7.cjs";
2
- import { t as IdentityPort } from "../identity-COdFfaW8.cjs";
1
+ import { P as IdentityKey, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { t as IdentityPort } from "../identity-bg6IVGsH.cjs";
3
3
  import { webcrypto } from "node:crypto";
4
4
  //#region src/adapters/node-identity.d.ts
5
5
  export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
@@ -1,5 +1,5 @@
1
- import { P as IdentityKey, x as DeviceId } from "../protocol-B3U828E7.mjs";
2
- import { t as IdentityPort } from "../identity-B7YMBhMf.mjs";
1
+ import { P as IdentityKey, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { t as IdentityPort } from "../identity-5LJ_B8go.mjs";
3
3
  import { webcrypto } from "node:crypto";
4
4
  //#region src/adapters/node-identity.d.ts
5
5
  export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-BrAqN6I5.cjs";
1
+ import { r as Transport } from "../transport-Baipikk7.cjs";
2
2
  //#region src/adapters/tcp-transport.d.ts
3
3
  /** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
4
4
  export declare function createTcpTransport(): Transport;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-B_diuPHT.mjs";
1
+ import { r as Transport } from "../transport-DWbvUc3L.mjs";
2
2
  //#region src/adapters/tcp-transport.d.ts
3
3
  /** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
4
4
  export declare function createTcpTransport(): Transport;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-BrAqN6I5.cjs";
1
+ import { r as Transport } from "../transport-Baipikk7.cjs";
2
2
  //#region src/adapters/tls-transport.d.ts
3
3
  export interface TlsIdentity {
4
4
  certificatePem: string;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-B_diuPHT.mjs";
1
+ import { r as Transport } from "../transport-DWbvUc3L.mjs";
2
2
  //#region src/adapters/tls-transport.d.ts
3
3
  export interface TlsIdentity {
4
4
  certificatePem: string;
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_generated_protocol = require("../generated/protocol.cjs");
3
- const require_tokens = require("../tokens-BxTxBmXt.cjs");
3
+ const require_token_scope = require("../token-scope-CxHXTT3u.cjs");
4
+ const require_tokens = require("../tokens-CiNXdKJ8.cjs");
4
5
  //#region src/domain/capability-grant.ts
5
6
  /**
6
7
  * The generic, capability-agnostic capability-grant primitive (wire-mesh#117, spec/management.cddl) -- the unsolicited push counterpart to capability-request.ts's own ask/response primitive. Where capability-request lifts core/room's room.join shape (a pull: the requester asks, the owner mints and returns a grant on the same response) out of that one domain, capability-grant lifts room.invite's own shape (a push: the owner mints unprompted and delivers the grant in the request itself, since there is no approval round-trip to carry it back) the same way. core/room's own room-client.ts is the reference consumer: it builds sendRoomInvite as a thin wrapper over sendCapabilityGrant below, and wires createRoomRouter's dispatch onto createCapabilityGrantHandler for the receiving side.
@@ -68,7 +69,7 @@ function createCapabilityGrantHandler(options) {
68
69
  });
69
70
  return;
70
71
  }
71
- if (!require_tokens.scopeNarrows(verdict.claims.scope, incoming.scope)) {
72
+ if (!require_token_scope.scopeNarrows(verdict.claims.scope, incoming.scope)) {
72
73
  await incoming.respond({
73
74
  result: "error",
74
75
  code: "scope_mismatch"
@@ -1,8 +1,8 @@
1
- import { F as ManageCommand, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.cjs";
2
- import { t as IdentityPort } from "../identity-COdFfaW8.cjs";
1
+ import { F as ManageCommand, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { t as IdentityPort } from "../identity-bg6IVGsH.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
5
- import { a as RevocationCheck } from "../tokens-D2aFwPcZ.cjs";
5
+ import { a as RevocationCheck } from "../tokens-H_mV_JCC.cjs";
6
6
  //#region src/domain/capability-grant.d.ts
7
7
  /**
8
8
  * Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
@@ -1,8 +1,8 @@
1
- import { F as ManageCommand, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.mjs";
2
- import { t as IdentityPort } from "../identity-B7YMBhMf.mjs";
1
+ import { F as ManageCommand, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { t as IdentityPort } from "../identity-5LJ_B8go.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
5
- import { a as RevocationCheck } from "../tokens-DSwixfDl.mjs";
5
+ import { a as RevocationCheck } from "../tokens-CBI54oF-.mjs";
6
6
  //#region src/domain/capability-grant.d.ts
7
7
  /**
8
8
  * Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
@@ -1,5 +1,6 @@
1
1
  import { capabilityGrantSchema } from "../generated/protocol.mjs";
2
- import { i as verifyCapabilityToken, o as scopeNarrows } from "../tokens-D9I1Pn14.mjs";
2
+ import { n as scopeNarrows } from "../token-scope-Z4bmci4M.mjs";
3
+ import { i as verifyCapabilityToken } from "../tokens-VicRWTj1.mjs";
3
4
  //#region src/domain/capability-grant.ts
4
5
  /**
5
6
  * The generic, capability-agnostic capability-grant primitive (wire-mesh#117, spec/management.cddl) -- the unsolicited push counterpart to capability-request.ts's own ask/response primitive. Where capability-request lifts core/room's room.join shape (a pull: the requester asks, the owner mints and returns a grant on the same response) out of that one domain, capability-grant lifts room.invite's own shape (a push: the owner mints unprompted and delivers the grant in the request itself, since there is no approval round-trip to carry it back) the same way. core/room's own room-client.ts is the reference consumer: it builds sendRoomInvite as a thin wrapper over sendCapabilityGrant below, and wires createRoomRouter's dispatch onto createCapabilityGrantHandler for the receiving side.
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_generated_protocol = require("../generated/protocol.cjs");
3
- const require_tokens = require("../tokens-BxTxBmXt.cjs");
3
+ const require_tokens = require("../tokens-CiNXdKJ8.cjs");
4
4
  //#region src/domain/capability-request.ts
5
5
  /**
6
6
  * The generic, capability-agnostic capability-request / capability-grant-ok primitive (wire-mesh#78, spec/management.cddl). Lifts core/room's own room.join shape -- an ungated ask, held open, a human (or any other domain-supplied decision) accepts or refuses, acceptance mints and returns a token on the same response -- out of that one domain so any capability can reuse it, not just room:member. core/room's own room-client.ts is the reference consumer: it rewires requestToJoin/createRoomRouter's room.join handling onto requestCapability/createCapabilityRequestHandler below, supplying room-specific extension fields (its member list) through this module's own extensions mechanism rather than this module knowing anything about rooms.
@@ -1,5 +1,5 @@
1
- import { F as ManageCommand, i as CapabilityGrantOk, o as CapabilityScope, x as DeviceId } from "../protocol-B3U828E7.cjs";
2
- import { t as IdentityPort } from "../identity-COdFfaW8.cjs";
1
+ import { F as ManageCommand, i as CapabilityGrantOk, o as CapabilityScope, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { t as IdentityPort } from "../identity-bg6IVGsH.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
5
5
  //#region src/domain/capability-request.d.ts
@@ -1,5 +1,5 @@
1
- import { F as ManageCommand, i as CapabilityGrantOk, o as CapabilityScope, x as DeviceId } from "../protocol-B3U828E7.mjs";
2
- import { t as IdentityPort } from "../identity-B7YMBhMf.mjs";
1
+ import { F as ManageCommand, i as CapabilityGrantOk, o as CapabilityScope, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { t as IdentityPort } from "../identity-5LJ_B8go.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
5
5
  //#region src/domain/capability-request.d.ts
@@ -1,5 +1,5 @@
1
1
  import { capabilityGrantOkSchema, capabilityRequestSchema } from "../generated/protocol.mjs";
2
- import { n as mintCapabilityToken } from "../tokens-D9I1Pn14.mjs";
2
+ import { n as mintCapabilityToken } from "../tokens-VicRWTj1.mjs";
3
3
  //#region src/domain/capability-request.ts
4
4
  /**
5
5
  * The generic, capability-agnostic capability-request / capability-grant-ok primitive (wire-mesh#78, spec/management.cddl). Lifts core/room's own room.join shape -- an ungated ask, held open, a human (or any other domain-supplied decision) accepts or refuses, acceptance mints and returns a token on the same response -- out of that one domain so any capability can reuse it, not just room:member. core/room's own room-client.ts is the reference consumer: it rewires requestToJoin/createRoomRouter's room.join handling onto requestCapability/createCapabilityRequestHandler below, supplying room-specific extension fields (its member list) through this module's own extensions mechanism rather than this module knowing anything about rooms.
@@ -1,4 +1,4 @@
1
- import { x as DeviceId } from "../protocol-B3U828E7.cjs";
1
+ import { x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
2
  //#region src/domain/device-id.d.ts
3
3
  /** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
4
4
  export declare function bytesToHex(bytes: Uint8Array): string;
@@ -1,4 +1,4 @@
1
- import { x as DeviceId } from "../protocol-B3U828E7.mjs";
1
+ import { x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
2
  //#region src/domain/device-id.d.ts
3
3
  /** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
4
4
  export declare function bytesToHex(bytes: Uint8Array): string;
@@ -0,0 +1,47 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_generated_protocol = require("../generated/protocol.cjs");
3
+ const require_token_scope = require("../token-scope-CxHXTT3u.cjs");
4
+ let zod = require("zod");
5
+ //#region src/domain/grant-candidates.ts
6
+ /**
7
+ * Gossip-advertised delegable-grant candidates (wire-mesh#87): lets a bearer of a still-delegable held token advertise its own willingness to field a capability-request for a narrower grant, and lets a requester discover the best candidate it can currently see before falling back to a capability's own structural root (that fallback -- e.g. a room's owner device-id -- is the caller's own concern, entirely outside this module; findGrantCandidate only ever returns a nearer-than-root candidate or undefined). Rides peer-advert's existing open extension tail (spec/transport.cddl, wire-mesh#91) under the domain-qualified key "capability-request/candidates" -- no new CDDL, no new wire mechanism, just a structured value on an already-shipped extension point.
8
+ *
9
+ * Honest limit, not closed here: this is only ever as complete as gossip propagation allows. A request can go unanswered by a nearer delegate not because none exists, but because it hasn't been gossiped yet -- the same "detection with propagation delay" honesty this spec already accepts for kick propagation and revocation timing.
10
+ */
11
+ const GOSSIP_CANDIDATES_KEY = "capability-request/candidates";
12
+ const grantCandidateSchema = zod.z.object({
13
+ capability: zod.z.string(),
14
+ scope: require_generated_protocol.capabilityScopeSchema,
15
+ "delegations-remaining": zod.z.number().int().nonnegative().optional()
16
+ });
17
+ const grantCandidateListSchema = zod.z.array(grantCandidateSchema);
18
+ /**
19
+ * Advertises this session's own willingness to field a capability-request for each of candidates, via sendGossipUpdate's own re-advertisement mechanism. Callers own their own re-advertisement cadence (there is no timer here, matching sendGossipUpdate's own design) -- calling this again with a fresh list replaces what was previously advertised under this key, exactly as sendGossipUpdate's own peer-advert re-send already does for any other extension field.
20
+ */
21
+ async function advertiseGrantCandidates(session, candidates) {
22
+ await session.sendGossipUpdate({ [GOSSIP_CANDIDATES_KEY]: candidates });
23
+ }
24
+ /**
25
+ * Scans directory for the best currently-gossiped delegate that could field a capability-request for capability over scope, returning its device-id -- or undefined when nothing closer than the capability's own structural root has been gossiped. A candidate qualifies when its own advertised capability matches exactly and its own advertised scope narrows into the requested scope (scopeNarrows' existing narrowing relation: the candidate's scope is the same as or a broader ancestor of scope), and its own delegations-remaining is either absent (unbounded) or still greater than zero.
26
+ *
27
+ * Selection policy, deliberately simple and explicitly stated rather than left implicit: the first qualifying candidate in directory's own order wins. Gossip carries no distance, latency, or load signal a requester could meaningfully rank candidates by, so no ordering directory provides is more defensible than any other -- "first seen" is exactly as reasonable a tie-break as "highest delegations-remaining" and simplest to implement and reason about.
28
+ *
29
+ * A malformed or non-conforming candidates value (from a misbehaving or out-of-date peer) is silently skipped, not treated as an error: this is a discovery hint over self-asserted, unsigned gossip, not a security check -- the token minted from any candidate this function returns still goes through mintCapabilityToken's own full narrowing checks regardless.
30
+ */
31
+ function findGrantCandidate(directory, capability, scope) {
32
+ for (const entry of directory) {
33
+ const raw = entry.advert[GOSSIP_CANDIDATES_KEY];
34
+ if (raw === void 0) continue;
35
+ const parsed = grantCandidateListSchema.safeParse(raw);
36
+ if (!parsed.success) continue;
37
+ for (const candidate of parsed.data) {
38
+ if (candidate.capability !== capability) continue;
39
+ const remaining = candidate["delegations-remaining"];
40
+ if (remaining !== void 0 && remaining <= 0) continue;
41
+ if (require_token_scope.scopeNarrows(candidate.scope, scope)) return entry.device;
42
+ }
43
+ }
44
+ }
45
+ //#endregion
46
+ exports.advertiseGrantCandidates = advertiseGrantCandidates;
47
+ exports.findGrantCandidate = findGrantCandidate;
@@ -0,0 +1,26 @@
1
+ import { o as CapabilityScope, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { DirectoryEntry, MeshSession } from "./mesh-session.cjs";
3
+ import { z } from "zod";
4
+ //#region src/domain/grant-candidates.d.ts
5
+ declare const grantCandidateSchema: z.ZodObject<{
6
+ capability: z.ZodString;
7
+ scope: z.ZodLazy<z.ZodObject<{
8
+ kind: z.ZodString;
9
+ path: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>>;
11
+ "delegations-remaining": z.ZodOptional<z.ZodNumber>;
12
+ }, z.core.$strip>;
13
+ export type GrantCandidate = z.infer<typeof grantCandidateSchema>;
14
+ /**
15
+ * Advertises this session's own willingness to field a capability-request for each of candidates, via sendGossipUpdate's own re-advertisement mechanism. Callers own their own re-advertisement cadence (there is no timer here, matching sendGossipUpdate's own design) -- calling this again with a fresh list replaces what was previously advertised under this key, exactly as sendGossipUpdate's own peer-advert re-send already does for any other extension field.
16
+ */
17
+ export declare function advertiseGrantCandidates(session: Readonly<MeshSession>, candidates: readonly GrantCandidate[]): Promise<void>;
18
+ /**
19
+ * Scans directory for the best currently-gossiped delegate that could field a capability-request for capability over scope, returning its device-id -- or undefined when nothing closer than the capability's own structural root has been gossiped. A candidate qualifies when its own advertised capability matches exactly and its own advertised scope narrows into the requested scope (scopeNarrows' existing narrowing relation: the candidate's scope is the same as or a broader ancestor of scope), and its own delegations-remaining is either absent (unbounded) or still greater than zero.
20
+ *
21
+ * Selection policy, deliberately simple and explicitly stated rather than left implicit: the first qualifying candidate in directory's own order wins. Gossip carries no distance, latency, or load signal a requester could meaningfully rank candidates by, so no ordering directory provides is more defensible than any other -- "first seen" is exactly as reasonable a tie-break as "highest delegations-remaining" and simplest to implement and reason about.
22
+ *
23
+ * A malformed or non-conforming candidates value (from a misbehaving or out-of-date peer) is silently skipped, not treated as an error: this is a discovery hint over self-asserted, unsigned gossip, not a security check -- the token minted from any candidate this function returns still goes through mintCapabilityToken's own full narrowing checks regardless.
24
+ */
25
+ export declare function findGrantCandidate(directory: readonly DirectoryEntry[], capability: string, scope: Readonly<CapabilityScope>): DeviceId | undefined;
26
+ //#endregion
@@ -0,0 +1,26 @@
1
+ import { o as CapabilityScope, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { DirectoryEntry, MeshSession } from "./mesh-session.mjs";
3
+ import { z } from "zod";
4
+ //#region src/domain/grant-candidates.d.ts
5
+ declare const grantCandidateSchema: z.ZodObject<{
6
+ capability: z.ZodString;
7
+ scope: z.ZodLazy<z.ZodObject<{
8
+ kind: z.ZodString;
9
+ path: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>>;
11
+ "delegations-remaining": z.ZodOptional<z.ZodNumber>;
12
+ }, z.core.$strip>;
13
+ export type GrantCandidate = z.infer<typeof grantCandidateSchema>;
14
+ /**
15
+ * Advertises this session's own willingness to field a capability-request for each of candidates, via sendGossipUpdate's own re-advertisement mechanism. Callers own their own re-advertisement cadence (there is no timer here, matching sendGossipUpdate's own design) -- calling this again with a fresh list replaces what was previously advertised under this key, exactly as sendGossipUpdate's own peer-advert re-send already does for any other extension field.
16
+ */
17
+ export declare function advertiseGrantCandidates(session: Readonly<MeshSession>, candidates: readonly GrantCandidate[]): Promise<void>;
18
+ /**
19
+ * Scans directory for the best currently-gossiped delegate that could field a capability-request for capability over scope, returning its device-id -- or undefined when nothing closer than the capability's own structural root has been gossiped. A candidate qualifies when its own advertised capability matches exactly and its own advertised scope narrows into the requested scope (scopeNarrows' existing narrowing relation: the candidate's scope is the same as or a broader ancestor of scope), and its own delegations-remaining is either absent (unbounded) or still greater than zero.
20
+ *
21
+ * Selection policy, deliberately simple and explicitly stated rather than left implicit: the first qualifying candidate in directory's own order wins. Gossip carries no distance, latency, or load signal a requester could meaningfully rank candidates by, so no ordering directory provides is more defensible than any other -- "first seen" is exactly as reasonable a tie-break as "highest delegations-remaining" and simplest to implement and reason about.
22
+ *
23
+ * A malformed or non-conforming candidates value (from a misbehaving or out-of-date peer) is silently skipped, not treated as an error: this is a discovery hint over self-asserted, unsigned gossip, not a security check -- the token minted from any candidate this function returns still goes through mintCapabilityToken's own full narrowing checks regardless.
24
+ */
25
+ export declare function findGrantCandidate(directory: readonly DirectoryEntry[], capability: string, scope: Readonly<CapabilityScope>): DeviceId | undefined;
26
+ //#endregion
@@ -0,0 +1,45 @@
1
+ import { capabilityScopeSchema } from "../generated/protocol.mjs";
2
+ import { n as scopeNarrows } from "../token-scope-Z4bmci4M.mjs";
3
+ import { z } from "zod";
4
+ //#region src/domain/grant-candidates.ts
5
+ /**
6
+ * Gossip-advertised delegable-grant candidates (wire-mesh#87): lets a bearer of a still-delegable held token advertise its own willingness to field a capability-request for a narrower grant, and lets a requester discover the best candidate it can currently see before falling back to a capability's own structural root (that fallback -- e.g. a room's owner device-id -- is the caller's own concern, entirely outside this module; findGrantCandidate only ever returns a nearer-than-root candidate or undefined). Rides peer-advert's existing open extension tail (spec/transport.cddl, wire-mesh#91) under the domain-qualified key "capability-request/candidates" -- no new CDDL, no new wire mechanism, just a structured value on an already-shipped extension point.
7
+ *
8
+ * Honest limit, not closed here: this is only ever as complete as gossip propagation allows. A request can go unanswered by a nearer delegate not because none exists, but because it hasn't been gossiped yet -- the same "detection with propagation delay" honesty this spec already accepts for kick propagation and revocation timing.
9
+ */
10
+ const GOSSIP_CANDIDATES_KEY = "capability-request/candidates";
11
+ const grantCandidateSchema = z.object({
12
+ capability: z.string(),
13
+ scope: capabilityScopeSchema,
14
+ "delegations-remaining": z.number().int().nonnegative().optional()
15
+ });
16
+ const grantCandidateListSchema = z.array(grantCandidateSchema);
17
+ /**
18
+ * Advertises this session's own willingness to field a capability-request for each of candidates, via sendGossipUpdate's own re-advertisement mechanism. Callers own their own re-advertisement cadence (there is no timer here, matching sendGossipUpdate's own design) -- calling this again with a fresh list replaces what was previously advertised under this key, exactly as sendGossipUpdate's own peer-advert re-send already does for any other extension field.
19
+ */
20
+ async function advertiseGrantCandidates(session, candidates) {
21
+ await session.sendGossipUpdate({ [GOSSIP_CANDIDATES_KEY]: candidates });
22
+ }
23
+ /**
24
+ * Scans directory for the best currently-gossiped delegate that could field a capability-request for capability over scope, returning its device-id -- or undefined when nothing closer than the capability's own structural root has been gossiped. A candidate qualifies when its own advertised capability matches exactly and its own advertised scope narrows into the requested scope (scopeNarrows' existing narrowing relation: the candidate's scope is the same as or a broader ancestor of scope), and its own delegations-remaining is either absent (unbounded) or still greater than zero.
25
+ *
26
+ * Selection policy, deliberately simple and explicitly stated rather than left implicit: the first qualifying candidate in directory's own order wins. Gossip carries no distance, latency, or load signal a requester could meaningfully rank candidates by, so no ordering directory provides is more defensible than any other -- "first seen" is exactly as reasonable a tie-break as "highest delegations-remaining" and simplest to implement and reason about.
27
+ *
28
+ * A malformed or non-conforming candidates value (from a misbehaving or out-of-date peer) is silently skipped, not treated as an error: this is a discovery hint over self-asserted, unsigned gossip, not a security check -- the token minted from any candidate this function returns still goes through mintCapabilityToken's own full narrowing checks regardless.
29
+ */
30
+ function findGrantCandidate(directory, capability, scope) {
31
+ for (const entry of directory) {
32
+ const raw = entry.advert[GOSSIP_CANDIDATES_KEY];
33
+ if (raw === void 0) continue;
34
+ const parsed = grantCandidateListSchema.safeParse(raw);
35
+ if (!parsed.success) continue;
36
+ for (const candidate of parsed.data) {
37
+ if (candidate.capability !== capability) continue;
38
+ const remaining = candidate["delegations-remaining"];
39
+ if (remaining !== void 0 && remaining <= 0) continue;
40
+ if (scopeNarrows(candidate.scope, scope)) return entry.device;
41
+ }
42
+ }
43
+ }
44
+ //#endregion
45
+ export { advertiseGrantCandidates, findGrantCandidate };
@@ -1,4 +1,4 @@
1
- import { M as HandshakeFrame, et as ProtocolVersion, w as DomainId } from "../protocol-B3U828E7.cjs";
1
+ import { M as HandshakeFrame, et as ProtocolVersion, w as DomainId } from "../protocol-l9RMR3s5.cjs";
2
2
  //#region src/domain/handshake.d.ts
3
3
  /** The highest protocol version this build of core understands. */
4
4
  export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
@@ -1,4 +1,4 @@
1
- import { M as HandshakeFrame, et as ProtocolVersion, w as DomainId } from "../protocol-B3U828E7.mjs";
1
+ import { M as HandshakeFrame, et as ProtocolVersion, w as DomainId } from "../protocol-l9RMR3s5.mjs";
2
2
  //#region src/domain/handshake.d.ts
3
3
  /** The highest protocol version this build of core understands. */
4
4
  export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
@@ -1,7 +1,7 @@
1
- import { D as Frame, F as ManageCommand, K as PeerAdvert, L as ManageError, R as ManageOk, dt as RevocationEntry, et as ProtocolVersion, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.cjs";
2
- import { t as IdentityPort } from "../identity-COdFfaW8.cjs";
1
+ import { D as Frame, F as ManageCommand, K as PeerAdvert, L as ManageError, R as ManageOk, dt as RevocationEntry, et as ProtocolVersion, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { t as IdentityPort } from "../identity-bg6IVGsH.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
- import { r as Transport, t as Connection } from "../transport-BrAqN6I5.cjs";
4
+ import { r as Transport, t as Connection } from "../transport-Baipikk7.cjs";
5
5
  //#region src/domain/mesh-session.d.ts
6
6
  /** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
7
7
  export declare const HANDSHAKE_TIMEOUT_MS = 3000;
@@ -1,7 +1,7 @@
1
- import { D as Frame, F as ManageCommand, K as PeerAdvert, L as ManageError, R as ManageOk, dt as RevocationEntry, et as ProtocolVersion, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.mjs";
2
- import { t as IdentityPort } from "../identity-B7YMBhMf.mjs";
1
+ import { D as Frame, F as ManageCommand, K as PeerAdvert, L as ManageError, R as ManageOk, dt as RevocationEntry, et as ProtocolVersion, o as CapabilityScope, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { t as IdentityPort } from "../identity-5LJ_B8go.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
- import { r as Transport, t as Connection } from "../transport-B_diuPHT.mjs";
4
+ import { r as Transport, t as Connection } from "../transport-DWbvUc3L.mjs";
5
5
  //#region src/domain/mesh-session.d.ts
6
6
  /** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
7
7
  export declare const HANDSHAKE_TIMEOUT_MS = 3000;
@@ -1,4 +1,4 @@
1
- import { t as Connection } from "../transport-BrAqN6I5.cjs";
1
+ import { t as Connection } from "../transport-Baipikk7.cjs";
2
2
  //#region src/domain/relay-hub.d.ts
3
3
  export interface RelayHub {
4
4
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, and forwards relay-data within established pairings. Resolves when the connection's frame stream ends. */
@@ -1,4 +1,4 @@
1
- import { t as Connection } from "../transport-B_diuPHT.mjs";
1
+ import { t as Connection } from "../transport-DWbvUc3L.mjs";
2
2
  //#region src/domain/relay-hub.d.ts
3
3
  export interface RelayHub {
4
4
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, and forwards relay-data within established pairings. Resolves when the connection's frame stream ends. */
@@ -1,19 +1,24 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_tokens = require("../tokens-BxTxBmXt.cjs");
2
+ const require_tokens = require("../tokens-CiNXdKJ8.cjs");
3
3
  const require_domain_device_id = require("./device-id.cjs");
4
4
  //#region src/domain/revocation-view.ts
5
- function revocationKey(tokenId, issuer) {
6
- return `${require_domain_device_id.bytesToHex(tokenId)}:${require_domain_device_id.deviceIdToHex(issuer)}`;
5
+ function revocationKey(tokenId) {
6
+ return require_domain_device_id.bytesToHex(tokenId);
7
7
  }
8
8
  function createRevocationView() {
9
- const revoked = /* @__PURE__ */ new Set();
9
+ const entriesByTokenId = /* @__PURE__ */ new Map();
10
10
  return {
11
- async isRevoked(tokenId, issuer) {
12
- return Promise.resolve(revoked.has(revocationKey(tokenId, issuer)));
11
+ async entriesFor(tokenId) {
12
+ return Promise.resolve(entriesByTokenId.get(revocationKey(tokenId)) ?? []);
13
13
  },
14
14
  async record(entry, options) {
15
15
  const verdict = await require_tokens.verifyRevocationEntry(entry, options);
16
- if (verdict.ok) revoked.add(revocationKey(verdict.claims["token-id"], verdict.claims.issuer));
16
+ if (verdict.ok) {
17
+ const key = revocationKey(verdict.claims["token-id"]);
18
+ const existing = entriesByTokenId.get(key);
19
+ if (existing === void 0) entriesByTokenId.set(key, [verdict.claims]);
20
+ else existing.push(verdict.claims);
21
+ }
17
22
  return verdict;
18
23
  }
19
24
  };
@@ -1,8 +1,8 @@
1
- import { dt as RevocationEntry } from "../protocol-B3U828E7.cjs";
2
- import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-D2aFwPcZ.cjs";
1
+ import { dt as RevocationEntry } from "../protocol-l9RMR3s5.cjs";
2
+ import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-H_mV_JCC.cjs";
3
3
  //#region src/domain/revocation-view.d.ts
4
4
  /**
5
- * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by (token-id, issuer) per management.cddl's contract: an entry counts against a token only when both match, so a third party's entry for someone else's token-id is stored (it is a well-formed, self-certifying entry) but never matches a lookup for the token it does not actually govern.
5
+ * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by token-id alone, per management.cddl's contract: a token-id can legitimately carry multiple recorded entries from different issuers (the token's own issuer, and/or any number of parties holding a delegated manage:revoke authorization over it) -- entriesFor returns every one of them unfiltered, since checking which actually apply (issuer-match, or a verified authorization) is verifyTokenChain's own obligation, not this store's.
6
6
  */
7
7
  export interface RevocationView extends RevocationCheck {
8
8
  /** Verifies one gossiped revocation-entry via verifyRevocationEntry and, if it verifies, records it. An entry that fails verification is dropped, not stored -- the returned verdict lets a caller log or otherwise report the refusal. */
@@ -1,8 +1,8 @@
1
- import { dt as RevocationEntry } from "../protocol-B3U828E7.mjs";
2
- import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-DSwixfDl.mjs";
1
+ import { dt as RevocationEntry } from "../protocol-l9RMR3s5.mjs";
2
+ import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-CBI54oF-.mjs";
3
3
  //#region src/domain/revocation-view.d.ts
4
4
  /**
5
- * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by (token-id, issuer) per management.cddl's contract: an entry counts against a token only when both match, so a third party's entry for someone else's token-id is stored (it is a well-formed, self-certifying entry) but never matches a lookup for the token it does not actually govern.
5
+ * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by token-id alone, per management.cddl's contract: a token-id can legitimately carry multiple recorded entries from different issuers (the token's own issuer, and/or any number of parties holding a delegated manage:revoke authorization over it) -- entriesFor returns every one of them unfiltered, since checking which actually apply (issuer-match, or a verified authorization) is verifyTokenChain's own obligation, not this store's.
6
6
  */
7
7
  export interface RevocationView extends RevocationCheck {
8
8
  /** Verifies one gossiped revocation-entry via verifyRevocationEntry and, if it verifies, records it. An entry that fails verification is dropped, not stored -- the returned verdict lets a caller log or otherwise report the refusal. */
@@ -1,18 +1,23 @@
1
- import { a as verifyRevocationEntry } from "../tokens-D9I1Pn14.mjs";
2
- import { bytesToHex, deviceIdToHex } from "./device-id.mjs";
1
+ import { a as verifyRevocationEntry } from "../tokens-VicRWTj1.mjs";
2
+ import { bytesToHex } from "./device-id.mjs";
3
3
  //#region src/domain/revocation-view.ts
4
- function revocationKey(tokenId, issuer) {
5
- return `${bytesToHex(tokenId)}:${deviceIdToHex(issuer)}`;
4
+ function revocationKey(tokenId) {
5
+ return bytesToHex(tokenId);
6
6
  }
7
7
  function createRevocationView() {
8
- const revoked = /* @__PURE__ */ new Set();
8
+ const entriesByTokenId = /* @__PURE__ */ new Map();
9
9
  return {
10
- async isRevoked(tokenId, issuer) {
11
- return Promise.resolve(revoked.has(revocationKey(tokenId, issuer)));
10
+ async entriesFor(tokenId) {
11
+ return Promise.resolve(entriesByTokenId.get(revocationKey(tokenId)) ?? []);
12
12
  },
13
13
  async record(entry, options) {
14
14
  const verdict = await verifyRevocationEntry(entry, options);
15
- if (verdict.ok) revoked.add(revocationKey(verdict.claims["token-id"], verdict.claims.issuer));
15
+ if (verdict.ok) {
16
+ const key = revocationKey(verdict.claims["token-id"]);
17
+ const existing = entriesByTokenId.get(key);
18
+ if (existing === void 0) entriesByTokenId.set(key, [verdict.claims]);
19
+ else existing.push(verdict.claims);
20
+ }
16
21
  return verdict;
17
22
  }
18
23
  };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_tokens = require("../tokens-BxTxBmXt.cjs");
2
+ const require_tokens = require("../tokens-CiNXdKJ8.cjs");
3
3
  const require_domain_device_id = require("./device-id.cjs");
4
4
  const require_domain_room_path = require("./room-path.cjs");
5
5
  //#region src/domain/room-token-verification.ts
@@ -1,5 +1,5 @@
1
- import { kt as TokenClaims, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.cjs";
2
- import { l as TokenVerdictReason, u as VerifyCapabilityTokenOptions } from "../tokens-D2aFwPcZ.cjs";
1
+ import { kt as TokenClaims, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.cjs";
2
+ import { l as TokenVerdictReason, u as VerifyCapabilityTokenOptions } from "../tokens-H_mV_JCC.cjs";
3
3
  //#region src/domain/room-token-verification.d.ts
4
4
  /** The one capability every core/room verb (room.send/read/leave/members) is gated by, per spec/room.cddl -- room.join/room.invite are deliberately ungated instead and need no token check at all. */
5
5
  export declare const ROOM_MEMBER_CAPABILITY = "room:member";
@@ -1,5 +1,5 @@
1
- import { kt as TokenClaims, s as CapabilityToken, x as DeviceId } from "../protocol-B3U828E7.mjs";
2
- import { l as TokenVerdictReason, u as VerifyCapabilityTokenOptions } from "../tokens-DSwixfDl.mjs";
1
+ import { kt as TokenClaims, s as CapabilityToken, x as DeviceId } from "../protocol-l9RMR3s5.mjs";
2
+ import { l as TokenVerdictReason, u as VerifyCapabilityTokenOptions } from "../tokens-CBI54oF-.mjs";
3
3
  //#region src/domain/room-token-verification.d.ts
4
4
  /** The one capability every core/room verb (room.send/read/leave/members) is gated by, per spec/room.cddl -- room.join/room.invite are deliberately ungated instead and need no token check at all. */
5
5
  export declare const ROOM_MEMBER_CAPABILITY = "room:member";
@@ -1,4 +1,4 @@
1
- import { i as verifyCapabilityToken } from "../tokens-D9I1Pn14.mjs";
1
+ import { i as verifyCapabilityToken } from "../tokens-VicRWTj1.mjs";
2
2
  import { deviceIdToHex } from "./device-id.mjs";
3
3
  import { parseRoomPath } from "./room-path.mjs";
4
4
  //#region src/domain/room-token-verification.ts
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_tokens = require("../tokens-BxTxBmXt.cjs");
2
+ const require_tokens = require("../tokens-CiNXdKJ8.cjs");
3
3
  exports.canGrant = require_tokens.canGrant;
4
4
  exports.mintCapabilityToken = require_tokens.mintCapabilityToken;
5
5
  exports.mintRevocationEntry = require_tokens.mintRevocationEntry;
@@ -1,2 +1,2 @@
1
- import { a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyRevocationEntry, h as verifyCapabilityToken, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-D2aFwPcZ.cjs";
1
+ import { a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyRevocationEntry, h as verifyCapabilityToken, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-H_mV_JCC.cjs";
2
2
  export { MintCapabilityTokenOptions, MintRefusalReason, MintRevocationEntryOptions, MintVerdict, RevocationCheck, RevocationEntryVerdict, RevocationEntryVerdictReason, TokenVerdict, TokenVerdictReason, VerifyCapabilityTokenOptions, VerifyRevocationEntryOptions, canGrant, mintCapabilityToken, mintRevocationEntry, verifyCapabilityToken, verifyRevocationEntry };
@@ -1,2 +1,2 @@
1
- import { a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyRevocationEntry, h as verifyCapabilityToken, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-DSwixfDl.mjs";
1
+ import { a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyRevocationEntry, h as verifyCapabilityToken, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-CBI54oF-.mjs";
2
2
  export { MintCapabilityTokenOptions, MintRefusalReason, MintRevocationEntryOptions, MintVerdict, RevocationCheck, RevocationEntryVerdict, RevocationEntryVerdictReason, TokenVerdict, TokenVerdictReason, VerifyCapabilityTokenOptions, VerifyRevocationEntryOptions, canGrant, mintCapabilityToken, mintRevocationEntry, verifyCapabilityToken, verifyRevocationEntry };
@@ -1,2 +1,2 @@
1
- import { a as verifyRevocationEntry, i as verifyCapabilityToken, n as mintCapabilityToken, r as mintRevocationEntry, t as canGrant } from "../tokens-D9I1Pn14.mjs";
1
+ import { a as verifyRevocationEntry, i as verifyCapabilityToken, n as mintCapabilityToken, r as mintRevocationEntry, t as canGrant } from "../tokens-VicRWTj1.mjs";
2
2
  export { canGrant, mintCapabilityToken, mintRevocationEntry, verifyCapabilityToken, verifyRevocationEntry };
@@ -196,7 +196,8 @@ const revocationClaimsSchema = zod.z.lazy(() => zod.z.object({
196
196
  "token-id": zod.z.instanceof(Uint8Array),
197
197
  "issuer": zod.z.lazy(() => deviceIdSchema),
198
198
  "issuer-key": zod.z.lazy(() => identityKeySchema),
199
- "revoked-at": zod.z.number().int().nonnegative()
199
+ "revoked-at": zod.z.number().int().nonnegative(),
200
+ "authorization": zod.z.instanceof(Uint8Array).optional()
200
201
  }));
201
202
  const revocationEntrySchema = zod.z.lazy(() => zod.z.lazy(() => coseSign1Schema));
202
203
  const revocationAnnounceFrameSchema = zod.z.lazy(() => zod.z.object({
@@ -1,2 +1,2 @@
1
- import { $ as ProcSpawn, $n as roomNoticeSchema, $t as dataRequestFrameSchema, A as HandleClaims, An as procKillSchema, At as WebrtcAnswer, B as ManageResponseFrame, Bn as relayInboundFrameSchema, Bt as capabilityTokenSchema, C as DmRoomPath, Cn as observedAddressFrameSchema, Ct as RoomSend, D as Frame, Dn as pingFrameSchema, Dt as StreamSession, E as ExecSessionInfo, En as peerIdentitySchema, Et as StreamEndFrame, F as ManageCommand, Fn as ptyResizeSchema, Ft as candidatesFrameSchema, G as OwnerNamedRoomPath, Gn as roomInviteSchema, Gt as coreDomainNameSchema, H as NamespacedCapability, Hn as revocationAnnounceFrameSchema, Ht as closeFrameSchema, I as ManageCommandParams, In as ptySpawnSchema, It as capabilityGrantOkSchema, J as PingFrame, Jn as roomLeaveSchema, Jt as coseHeaderLabelSchema, K as PeerAdvert, Kn as roomJoinOkSchema, Kt as coseHeaderAlgSchema, L as ManageError, Ln as ptyWriteSchema, Lt as capabilityGrantSchema, M as HandshakeFrame, Mn as procSpawnSchema, Mt as WebrtcOffer, N as IceCandidateInit, Nn as protocolVersionSchema, Nt as WireCandidate, O as FrameVariant, On as privateUseCapabilitySchema, Ot as SyncPunchFrame, P as IdentityKey, Pn as ptyKillSchema, Pt as candidateKindSchema, Q as ProcSignal, Qn as roomNoticeClaimsSchema, Qt as dataHaveFrameSchema, R as ManageOk, Rn as relayConnectFrameSchema, Rt as capabilityRequestSchema, S as DeviceIdHex, Sn as namespacedDomainIdSchema, St as RoomRead, T as ExecList, Tn as peerAdvertSchema, Tt as StreamDataFrame, U as NamespacedDomainId, Un as revocationClaimsSchema, Ut as coordinatorFrameSchema, V as MessageRef, Vn as relayOfferFrameSchema, Vt as capabilityVerbSchema, W as ObservedAddressFrame, Wn as revocationEntrySchema, Wt as coreCapabilitySchema, X as PrivateUseDomainId, Xn as roomMembersOkSchema, Xt as coseTokenHeadersSchema, Y as PrivateUseCapability, Yn as roomMemberSchema, Yt as coseSign1Schema, Z as ProcKill, Zn as roomMembersSchema, Zt as dataEntriesFrameSchema, _ as CoseTokenHeaders, _n as manageOkSchema, _t as RoomMembers, a as CapabilityRequest, an as execSessionInfoSchema, ar as streamEndFrameSchema, at as RelayConnectFrame, b as DataRequestFrame, bn as messageRefSchema, bt as RoomNoticeClaims, c as CapabilityVerb, cn as gossipFrameSchema, cr as tokenClaimsSchema, ct as RelayOfferFrame, d as CoreCapability, dn as handshakeFrameSchema, dr as webrtcOfferSchema, dt as RevocationEntry, en as deviceIdHexSchema, er as roomPathSchema, et as ProtocolVersion, f as CoreDomainName, fn as iceCandidateInitSchema, fr as wireCandidateSchema, ft as RoomInvite, g as CoseSign1, gn as manageErrorSchema, gt as RoomMember, h as CoseHeaderLabel, hn as manageCommandSchema, ht as RoomLeave, i as CapabilityGrantOk, in as execListSchema, ir as streamDataFrameSchema, it as PtyWrite, j as HandleRecord, jn as procSignalSchema, jt as WebrtcIceCandidate, k as GossipFrame, kn as privateUseDomainIdSchema, kt as TokenClaims, l as CloseFrame, ln as handleClaimsSchema, lr as webrtcAnswerSchema, lt as RevocationAnnounceFrame, m as CoseHeaderKid, mn as manageCommandParamsSchema, mt as RoomJoinOk, n as CandidatesFrame, nn as dmRoomPathSchema, nr as roomSendSchema, nt as PtyResize, o as CapabilityScope, on as frameSchema, or as streamSessionSchema, ot as RelayDataFrame, p as CoseHeaderAlg, pn as identityKeySchema, pt as RoomJoin, q as PeerIdentity, qn as roomJoinSchema, qt as coseHeaderKidSchema, r as CapabilityGrant, rn as domainIdSchema, rr as streamAckFrameSchema, rt as PtySpawn, s as CapabilityToken, sn as frameVariantSchema, sr as syncPunchFrameSchema, st as RelayInboundFrame, t as CandidateKind, tn as deviceIdSchema, tr as roomReadSchema, tt as PtyKill, u as CoordinatorFrame, un as handleRecordSchema, ur as webrtcIceCandidateSchema, ut as RevocationClaims, v as DataEntriesFrame, vn as manageRequestFrameSchema, vt as RoomMembersOk, w as DomainId, wn as ownerNamedRoomPathSchema, wt as StreamAckFrame, x as DeviceId, xn as namespacedCapabilitySchema, xt as RoomPath, y as DataHaveFrame, yn as manageResponseFrameSchema, yt as RoomNotice, z as ManageRequestFrame, zn as relayDataFrameSchema, zt as capabilityScopeSchema } from "../protocol-B3U828E7.cjs";
1
+ import { $ as ProcSpawn, $n as roomNoticeSchema, $t as dataRequestFrameSchema, A as HandleClaims, An as procKillSchema, At as WebrtcAnswer, B as ManageResponseFrame, Bn as relayInboundFrameSchema, Bt as capabilityTokenSchema, C as DmRoomPath, Cn as observedAddressFrameSchema, Ct as RoomSend, D as Frame, Dn as pingFrameSchema, Dt as StreamSession, E as ExecSessionInfo, En as peerIdentitySchema, Et as StreamEndFrame, F as ManageCommand, Fn as ptyResizeSchema, Ft as candidatesFrameSchema, G as OwnerNamedRoomPath, Gn as roomInviteSchema, Gt as coreDomainNameSchema, H as NamespacedCapability, Hn as revocationAnnounceFrameSchema, Ht as closeFrameSchema, I as ManageCommandParams, In as ptySpawnSchema, It as capabilityGrantOkSchema, J as PingFrame, Jn as roomLeaveSchema, Jt as coseHeaderLabelSchema, K as PeerAdvert, Kn as roomJoinOkSchema, Kt as coseHeaderAlgSchema, L as ManageError, Ln as ptyWriteSchema, Lt as capabilityGrantSchema, M as HandshakeFrame, Mn as procSpawnSchema, Mt as WebrtcOffer, N as IceCandidateInit, Nn as protocolVersionSchema, Nt as WireCandidate, O as FrameVariant, On as privateUseCapabilitySchema, Ot as SyncPunchFrame, P as IdentityKey, Pn as ptyKillSchema, Pt as candidateKindSchema, Q as ProcSignal, Qn as roomNoticeClaimsSchema, Qt as dataHaveFrameSchema, R as ManageOk, Rn as relayConnectFrameSchema, Rt as capabilityRequestSchema, S as DeviceIdHex, Sn as namespacedDomainIdSchema, St as RoomRead, T as ExecList, Tn as peerAdvertSchema, Tt as StreamDataFrame, U as NamespacedDomainId, Un as revocationClaimsSchema, Ut as coordinatorFrameSchema, V as MessageRef, Vn as relayOfferFrameSchema, Vt as capabilityVerbSchema, W as ObservedAddressFrame, Wn as revocationEntrySchema, Wt as coreCapabilitySchema, X as PrivateUseDomainId, Xn as roomMembersOkSchema, Xt as coseTokenHeadersSchema, Y as PrivateUseCapability, Yn as roomMemberSchema, Yt as coseSign1Schema, Z as ProcKill, Zn as roomMembersSchema, Zt as dataEntriesFrameSchema, _ as CoseTokenHeaders, _n as manageOkSchema, _t as RoomMembers, a as CapabilityRequest, an as execSessionInfoSchema, ar as streamEndFrameSchema, at as RelayConnectFrame, b as DataRequestFrame, bn as messageRefSchema, bt as RoomNoticeClaims, c as CapabilityVerb, cn as gossipFrameSchema, cr as tokenClaimsSchema, ct as RelayOfferFrame, d as CoreCapability, dn as handshakeFrameSchema, dr as webrtcOfferSchema, dt as RevocationEntry, en as deviceIdHexSchema, er as roomPathSchema, et as ProtocolVersion, f as CoreDomainName, fn as iceCandidateInitSchema, fr as wireCandidateSchema, ft as RoomInvite, g as CoseSign1, gn as manageErrorSchema, gt as RoomMember, h as CoseHeaderLabel, hn as manageCommandSchema, ht as RoomLeave, i as CapabilityGrantOk, in as execListSchema, ir as streamDataFrameSchema, it as PtyWrite, j as HandleRecord, jn as procSignalSchema, jt as WebrtcIceCandidate, k as GossipFrame, kn as privateUseDomainIdSchema, kt as TokenClaims, l as CloseFrame, ln as handleClaimsSchema, lr as webrtcAnswerSchema, lt as RevocationAnnounceFrame, m as CoseHeaderKid, mn as manageCommandParamsSchema, mt as RoomJoinOk, n as CandidatesFrame, nn as dmRoomPathSchema, nr as roomSendSchema, nt as PtyResize, o as CapabilityScope, on as frameSchema, or as streamSessionSchema, ot as RelayDataFrame, p as CoseHeaderAlg, pn as identityKeySchema, pt as RoomJoin, q as PeerIdentity, qn as roomJoinSchema, qt as coseHeaderKidSchema, r as CapabilityGrant, rn as domainIdSchema, rr as streamAckFrameSchema, rt as PtySpawn, s as CapabilityToken, sn as frameVariantSchema, sr as syncPunchFrameSchema, st as RelayInboundFrame, t as CandidateKind, tn as deviceIdSchema, tr as roomReadSchema, tt as PtyKill, u as CoordinatorFrame, un as handleRecordSchema, ur as webrtcIceCandidateSchema, ut as RevocationClaims, v as DataEntriesFrame, vn as manageRequestFrameSchema, vt as RoomMembersOk, w as DomainId, wn as ownerNamedRoomPathSchema, wt as StreamAckFrame, x as DeviceId, xn as namespacedCapabilitySchema, xt as RoomPath, y as DataHaveFrame, yn as manageResponseFrameSchema, yt as RoomNotice, z as ManageRequestFrame, zn as relayDataFrameSchema, zt as capabilityScopeSchema } from "../protocol-l9RMR3s5.cjs";
2
2
  export { CandidateKind, CandidatesFrame, CapabilityGrant, CapabilityGrantOk, CapabilityRequest, CapabilityScope, CapabilityToken, CapabilityVerb, CloseFrame, CoordinatorFrame, CoreCapability, CoreDomainName, CoseHeaderAlg, CoseHeaderKid, CoseHeaderLabel, CoseSign1, CoseTokenHeaders, DataEntriesFrame, DataHaveFrame, DataRequestFrame, DeviceId, DeviceIdHex, DmRoomPath, DomainId, ExecList, ExecSessionInfo, Frame, FrameVariant, GossipFrame, HandleClaims, HandleRecord, HandshakeFrame, IceCandidateInit, IdentityKey, ManageCommand, ManageCommandParams, ManageError, ManageOk, ManageRequestFrame, ManageResponseFrame, MessageRef, NamespacedCapability, NamespacedDomainId, ObservedAddressFrame, OwnerNamedRoomPath, PeerAdvert, PeerIdentity, PingFrame, PrivateUseCapability, PrivateUseDomainId, ProcKill, ProcSignal, ProcSpawn, ProtocolVersion, PtyKill, PtyResize, PtySpawn, PtyWrite, RelayConnectFrame, RelayDataFrame, RelayInboundFrame, RelayOfferFrame, RevocationAnnounceFrame, RevocationClaims, RevocationEntry, RoomInvite, RoomJoin, RoomJoinOk, RoomLeave, RoomMember, RoomMembers, RoomMembersOk, RoomNotice, RoomNoticeClaims, RoomPath, RoomRead, RoomSend, StreamAckFrame, StreamDataFrame, StreamEndFrame, StreamSession, SyncPunchFrame, TokenClaims, WebrtcAnswer, WebrtcIceCandidate, WebrtcOffer, WireCandidate, candidateKindSchema, candidatesFrameSchema, capabilityGrantOkSchema, capabilityGrantSchema, capabilityRequestSchema, capabilityScopeSchema, capabilityTokenSchema, capabilityVerbSchema, closeFrameSchema, coordinatorFrameSchema, coreCapabilitySchema, coreDomainNameSchema, coseHeaderAlgSchema, coseHeaderKidSchema, coseHeaderLabelSchema, coseSign1Schema, coseTokenHeadersSchema, dataEntriesFrameSchema, dataHaveFrameSchema, dataRequestFrameSchema, deviceIdHexSchema, deviceIdSchema, dmRoomPathSchema, domainIdSchema, execListSchema, execSessionInfoSchema, frameSchema, frameVariantSchema, gossipFrameSchema, handleClaimsSchema, handleRecordSchema, handshakeFrameSchema, iceCandidateInitSchema, identityKeySchema, manageCommandParamsSchema, manageCommandSchema, manageErrorSchema, manageOkSchema, manageRequestFrameSchema, manageResponseFrameSchema, messageRefSchema, namespacedCapabilitySchema, namespacedDomainIdSchema, observedAddressFrameSchema, ownerNamedRoomPathSchema, peerAdvertSchema, peerIdentitySchema, pingFrameSchema, privateUseCapabilitySchema, privateUseDomainIdSchema, procKillSchema, procSignalSchema, procSpawnSchema, protocolVersionSchema, ptyKillSchema, ptyResizeSchema, ptySpawnSchema, ptyWriteSchema, relayConnectFrameSchema, relayDataFrameSchema, relayInboundFrameSchema, relayOfferFrameSchema, revocationAnnounceFrameSchema, revocationClaimsSchema, revocationEntrySchema, roomInviteSchema, roomJoinOkSchema, roomJoinSchema, roomLeaveSchema, roomMemberSchema, roomMembersOkSchema, roomMembersSchema, roomNoticeClaimsSchema, roomNoticeSchema, roomPathSchema, roomReadSchema, roomSendSchema, streamAckFrameSchema, streamDataFrameSchema, streamEndFrameSchema, streamSessionSchema, syncPunchFrameSchema, tokenClaimsSchema, webrtcAnswerSchema, webrtcIceCandidateSchema, webrtcOfferSchema, wireCandidateSchema };
@@ -1,2 +1,2 @@
1
- import { $ as ProcSpawn, $n as roomNoticeSchema, $t as dataRequestFrameSchema, A as HandleClaims, An as procKillSchema, At as WebrtcAnswer, B as ManageResponseFrame, Bn as relayInboundFrameSchema, Bt as capabilityTokenSchema, C as DmRoomPath, Cn as observedAddressFrameSchema, Ct as RoomSend, D as Frame, Dn as pingFrameSchema, Dt as StreamSession, E as ExecSessionInfo, En as peerIdentitySchema, Et as StreamEndFrame, F as ManageCommand, Fn as ptyResizeSchema, Ft as candidatesFrameSchema, G as OwnerNamedRoomPath, Gn as roomInviteSchema, Gt as coreDomainNameSchema, H as NamespacedCapability, Hn as revocationAnnounceFrameSchema, Ht as closeFrameSchema, I as ManageCommandParams, In as ptySpawnSchema, It as capabilityGrantOkSchema, J as PingFrame, Jn as roomLeaveSchema, Jt as coseHeaderLabelSchema, K as PeerAdvert, Kn as roomJoinOkSchema, Kt as coseHeaderAlgSchema, L as ManageError, Ln as ptyWriteSchema, Lt as capabilityGrantSchema, M as HandshakeFrame, Mn as procSpawnSchema, Mt as WebrtcOffer, N as IceCandidateInit, Nn as protocolVersionSchema, Nt as WireCandidate, O as FrameVariant, On as privateUseCapabilitySchema, Ot as SyncPunchFrame, P as IdentityKey, Pn as ptyKillSchema, Pt as candidateKindSchema, Q as ProcSignal, Qn as roomNoticeClaimsSchema, Qt as dataHaveFrameSchema, R as ManageOk, Rn as relayConnectFrameSchema, Rt as capabilityRequestSchema, S as DeviceIdHex, Sn as namespacedDomainIdSchema, St as RoomRead, T as ExecList, Tn as peerAdvertSchema, Tt as StreamDataFrame, U as NamespacedDomainId, Un as revocationClaimsSchema, Ut as coordinatorFrameSchema, V as MessageRef, Vn as relayOfferFrameSchema, Vt as capabilityVerbSchema, W as ObservedAddressFrame, Wn as revocationEntrySchema, Wt as coreCapabilitySchema, X as PrivateUseDomainId, Xn as roomMembersOkSchema, Xt as coseTokenHeadersSchema, Y as PrivateUseCapability, Yn as roomMemberSchema, Yt as coseSign1Schema, Z as ProcKill, Zn as roomMembersSchema, Zt as dataEntriesFrameSchema, _ as CoseTokenHeaders, _n as manageOkSchema, _t as RoomMembers, a as CapabilityRequest, an as execSessionInfoSchema, ar as streamEndFrameSchema, at as RelayConnectFrame, b as DataRequestFrame, bn as messageRefSchema, bt as RoomNoticeClaims, c as CapabilityVerb, cn as gossipFrameSchema, cr as tokenClaimsSchema, ct as RelayOfferFrame, d as CoreCapability, dn as handshakeFrameSchema, dr as webrtcOfferSchema, dt as RevocationEntry, en as deviceIdHexSchema, er as roomPathSchema, et as ProtocolVersion, f as CoreDomainName, fn as iceCandidateInitSchema, fr as wireCandidateSchema, ft as RoomInvite, g as CoseSign1, gn as manageErrorSchema, gt as RoomMember, h as CoseHeaderLabel, hn as manageCommandSchema, ht as RoomLeave, i as CapabilityGrantOk, in as execListSchema, ir as streamDataFrameSchema, it as PtyWrite, j as HandleRecord, jn as procSignalSchema, jt as WebrtcIceCandidate, k as GossipFrame, kn as privateUseDomainIdSchema, kt as TokenClaims, l as CloseFrame, ln as handleClaimsSchema, lr as webrtcAnswerSchema, lt as RevocationAnnounceFrame, m as CoseHeaderKid, mn as manageCommandParamsSchema, mt as RoomJoinOk, n as CandidatesFrame, nn as dmRoomPathSchema, nr as roomSendSchema, nt as PtyResize, o as CapabilityScope, on as frameSchema, or as streamSessionSchema, ot as RelayDataFrame, p as CoseHeaderAlg, pn as identityKeySchema, pt as RoomJoin, q as PeerIdentity, qn as roomJoinSchema, qt as coseHeaderKidSchema, r as CapabilityGrant, rn as domainIdSchema, rr as streamAckFrameSchema, rt as PtySpawn, s as CapabilityToken, sn as frameVariantSchema, sr as syncPunchFrameSchema, st as RelayInboundFrame, t as CandidateKind, tn as deviceIdSchema, tr as roomReadSchema, tt as PtyKill, u as CoordinatorFrame, un as handleRecordSchema, ur as webrtcIceCandidateSchema, ut as RevocationClaims, v as DataEntriesFrame, vn as manageRequestFrameSchema, vt as RoomMembersOk, w as DomainId, wn as ownerNamedRoomPathSchema, wt as StreamAckFrame, x as DeviceId, xn as namespacedCapabilitySchema, xt as RoomPath, y as DataHaveFrame, yn as manageResponseFrameSchema, yt as RoomNotice, z as ManageRequestFrame, zn as relayDataFrameSchema, zt as capabilityScopeSchema } from "../protocol-B3U828E7.mjs";
1
+ import { $ as ProcSpawn, $n as roomNoticeSchema, $t as dataRequestFrameSchema, A as HandleClaims, An as procKillSchema, At as WebrtcAnswer, B as ManageResponseFrame, Bn as relayInboundFrameSchema, Bt as capabilityTokenSchema, C as DmRoomPath, Cn as observedAddressFrameSchema, Ct as RoomSend, D as Frame, Dn as pingFrameSchema, Dt as StreamSession, E as ExecSessionInfo, En as peerIdentitySchema, Et as StreamEndFrame, F as ManageCommand, Fn as ptyResizeSchema, Ft as candidatesFrameSchema, G as OwnerNamedRoomPath, Gn as roomInviteSchema, Gt as coreDomainNameSchema, H as NamespacedCapability, Hn as revocationAnnounceFrameSchema, Ht as closeFrameSchema, I as ManageCommandParams, In as ptySpawnSchema, It as capabilityGrantOkSchema, J as PingFrame, Jn as roomLeaveSchema, Jt as coseHeaderLabelSchema, K as PeerAdvert, Kn as roomJoinOkSchema, Kt as coseHeaderAlgSchema, L as ManageError, Ln as ptyWriteSchema, Lt as capabilityGrantSchema, M as HandshakeFrame, Mn as procSpawnSchema, Mt as WebrtcOffer, N as IceCandidateInit, Nn as protocolVersionSchema, Nt as WireCandidate, O as FrameVariant, On as privateUseCapabilitySchema, Ot as SyncPunchFrame, P as IdentityKey, Pn as ptyKillSchema, Pt as candidateKindSchema, Q as ProcSignal, Qn as roomNoticeClaimsSchema, Qt as dataHaveFrameSchema, R as ManageOk, Rn as relayConnectFrameSchema, Rt as capabilityRequestSchema, S as DeviceIdHex, Sn as namespacedDomainIdSchema, St as RoomRead, T as ExecList, Tn as peerAdvertSchema, Tt as StreamDataFrame, U as NamespacedDomainId, Un as revocationClaimsSchema, Ut as coordinatorFrameSchema, V as MessageRef, Vn as relayOfferFrameSchema, Vt as capabilityVerbSchema, W as ObservedAddressFrame, Wn as revocationEntrySchema, Wt as coreCapabilitySchema, X as PrivateUseDomainId, Xn as roomMembersOkSchema, Xt as coseTokenHeadersSchema, Y as PrivateUseCapability, Yn as roomMemberSchema, Yt as coseSign1Schema, Z as ProcKill, Zn as roomMembersSchema, Zt as dataEntriesFrameSchema, _ as CoseTokenHeaders, _n as manageOkSchema, _t as RoomMembers, a as CapabilityRequest, an as execSessionInfoSchema, ar as streamEndFrameSchema, at as RelayConnectFrame, b as DataRequestFrame, bn as messageRefSchema, bt as RoomNoticeClaims, c as CapabilityVerb, cn as gossipFrameSchema, cr as tokenClaimsSchema, ct as RelayOfferFrame, d as CoreCapability, dn as handshakeFrameSchema, dr as webrtcOfferSchema, dt as RevocationEntry, en as deviceIdHexSchema, er as roomPathSchema, et as ProtocolVersion, f as CoreDomainName, fn as iceCandidateInitSchema, fr as wireCandidateSchema, ft as RoomInvite, g as CoseSign1, gn as manageErrorSchema, gt as RoomMember, h as CoseHeaderLabel, hn as manageCommandSchema, ht as RoomLeave, i as CapabilityGrantOk, in as execListSchema, ir as streamDataFrameSchema, it as PtyWrite, j as HandleRecord, jn as procSignalSchema, jt as WebrtcIceCandidate, k as GossipFrame, kn as privateUseDomainIdSchema, kt as TokenClaims, l as CloseFrame, ln as handleClaimsSchema, lr as webrtcAnswerSchema, lt as RevocationAnnounceFrame, m as CoseHeaderKid, mn as manageCommandParamsSchema, mt as RoomJoinOk, n as CandidatesFrame, nn as dmRoomPathSchema, nr as roomSendSchema, nt as PtyResize, o as CapabilityScope, on as frameSchema, or as streamSessionSchema, ot as RelayDataFrame, p as CoseHeaderAlg, pn as identityKeySchema, pt as RoomJoin, q as PeerIdentity, qn as roomJoinSchema, qt as coseHeaderKidSchema, r as CapabilityGrant, rn as domainIdSchema, rr as streamAckFrameSchema, rt as PtySpawn, s as CapabilityToken, sn as frameVariantSchema, sr as syncPunchFrameSchema, st as RelayInboundFrame, t as CandidateKind, tn as deviceIdSchema, tr as roomReadSchema, tt as PtyKill, u as CoordinatorFrame, un as handleRecordSchema, ur as webrtcIceCandidateSchema, ut as RevocationClaims, v as DataEntriesFrame, vn as manageRequestFrameSchema, vt as RoomMembersOk, w as DomainId, wn as ownerNamedRoomPathSchema, wt as StreamAckFrame, x as DeviceId, xn as namespacedCapabilitySchema, xt as RoomPath, y as DataHaveFrame, yn as manageResponseFrameSchema, yt as RoomNotice, z as ManageRequestFrame, zn as relayDataFrameSchema, zt as capabilityScopeSchema } from "../protocol-l9RMR3s5.mjs";
2
2
  export { CandidateKind, CandidatesFrame, CapabilityGrant, CapabilityGrantOk, CapabilityRequest, CapabilityScope, CapabilityToken, CapabilityVerb, CloseFrame, CoordinatorFrame, CoreCapability, CoreDomainName, CoseHeaderAlg, CoseHeaderKid, CoseHeaderLabel, CoseSign1, CoseTokenHeaders, DataEntriesFrame, DataHaveFrame, DataRequestFrame, DeviceId, DeviceIdHex, DmRoomPath, DomainId, ExecList, ExecSessionInfo, Frame, FrameVariant, GossipFrame, HandleClaims, HandleRecord, HandshakeFrame, IceCandidateInit, IdentityKey, ManageCommand, ManageCommandParams, ManageError, ManageOk, ManageRequestFrame, ManageResponseFrame, MessageRef, NamespacedCapability, NamespacedDomainId, ObservedAddressFrame, OwnerNamedRoomPath, PeerAdvert, PeerIdentity, PingFrame, PrivateUseCapability, PrivateUseDomainId, ProcKill, ProcSignal, ProcSpawn, ProtocolVersion, PtyKill, PtyResize, PtySpawn, PtyWrite, RelayConnectFrame, RelayDataFrame, RelayInboundFrame, RelayOfferFrame, RevocationAnnounceFrame, RevocationClaims, RevocationEntry, RoomInvite, RoomJoin, RoomJoinOk, RoomLeave, RoomMember, RoomMembers, RoomMembersOk, RoomNotice, RoomNoticeClaims, RoomPath, RoomRead, RoomSend, StreamAckFrame, StreamDataFrame, StreamEndFrame, StreamSession, SyncPunchFrame, TokenClaims, WebrtcAnswer, WebrtcIceCandidate, WebrtcOffer, WireCandidate, candidateKindSchema, candidatesFrameSchema, capabilityGrantOkSchema, capabilityGrantSchema, capabilityRequestSchema, capabilityScopeSchema, capabilityTokenSchema, capabilityVerbSchema, closeFrameSchema, coordinatorFrameSchema, coreCapabilitySchema, coreDomainNameSchema, coseHeaderAlgSchema, coseHeaderKidSchema, coseHeaderLabelSchema, coseSign1Schema, coseTokenHeadersSchema, dataEntriesFrameSchema, dataHaveFrameSchema, dataRequestFrameSchema, deviceIdHexSchema, deviceIdSchema, dmRoomPathSchema, domainIdSchema, execListSchema, execSessionInfoSchema, frameSchema, frameVariantSchema, gossipFrameSchema, handleClaimsSchema, handleRecordSchema, handshakeFrameSchema, iceCandidateInitSchema, identityKeySchema, manageCommandParamsSchema, manageCommandSchema, manageErrorSchema, manageOkSchema, manageRequestFrameSchema, manageResponseFrameSchema, messageRefSchema, namespacedCapabilitySchema, namespacedDomainIdSchema, observedAddressFrameSchema, ownerNamedRoomPathSchema, peerAdvertSchema, peerIdentitySchema, pingFrameSchema, privateUseCapabilitySchema, privateUseDomainIdSchema, procKillSchema, procSignalSchema, procSpawnSchema, protocolVersionSchema, ptyKillSchema, ptyResizeSchema, ptySpawnSchema, ptyWriteSchema, relayConnectFrameSchema, relayDataFrameSchema, relayInboundFrameSchema, relayOfferFrameSchema, revocationAnnounceFrameSchema, revocationClaimsSchema, revocationEntrySchema, roomInviteSchema, roomJoinOkSchema, roomJoinSchema, roomLeaveSchema, roomMemberSchema, roomMembersOkSchema, roomMembersSchema, roomNoticeClaimsSchema, roomNoticeSchema, roomPathSchema, roomReadSchema, roomSendSchema, streamAckFrameSchema, streamDataFrameSchema, streamEndFrameSchema, streamSessionSchema, syncPunchFrameSchema, tokenClaimsSchema, webrtcAnswerSchema, webrtcIceCandidateSchema, webrtcOfferSchema, wireCandidateSchema };
@@ -195,7 +195,8 @@ const revocationClaimsSchema = z.lazy(() => z.object({
195
195
  "token-id": z.instanceof(Uint8Array),
196
196
  "issuer": z.lazy(() => deviceIdSchema),
197
197
  "issuer-key": z.lazy(() => identityKeySchema),
198
- "revoked-at": z.number().int().nonnegative()
198
+ "revoked-at": z.number().int().nonnegative(),
199
+ "authorization": z.instanceof(Uint8Array).optional()
199
200
  }));
200
201
  const revocationEntrySchema = z.lazy(() => z.lazy(() => coseSign1Schema));
201
202
  const revocationAnnounceFrameSchema = z.lazy(() => z.object({
@@ -1,4 +1,4 @@
1
- import { P as IdentityKey, x as DeviceId } from "./protocol-B3U828E7.mjs";
1
+ import { P as IdentityKey, x as DeviceId } from "./protocol-l9RMR3s5.mjs";
2
2
  //#region src/ports/identity.d.ts
3
3
  /**
4
4
  * Wraps the local node's own identity plus the signing/verification primitives capability-token handling needs -- never hardcoded to one crypto library's own API shape (Node's webcrypto, a WASM implementation, a hardware key, etc. can all satisfy this same contract).
@@ -1,4 +1,4 @@
1
- import { P as IdentityKey, x as DeviceId } from "./protocol-B3U828E7.cjs";
1
+ import { P as IdentityKey, x as DeviceId } from "./protocol-l9RMR3s5.cjs";
2
2
  //#region src/ports/identity.d.ts
3
3
  /**
4
4
  * Wraps the local node's own identity plus the signing/verification primitives capability-token handling needs -- never hardcoded to one crypto library's own API shape (Node's webcrypto, a WASM implementation, a hardware key, etc. can all satisfy this same contract).
@@ -1,2 +1,2 @@
1
- import { t as IdentityPort } from "../identity-COdFfaW8.cjs";
1
+ import { t as IdentityPort } from "../identity-bg6IVGsH.cjs";
2
2
  export { IdentityPort };
@@ -1,2 +1,2 @@
1
- import { t as IdentityPort } from "../identity-B7YMBhMf.mjs";
1
+ import { t as IdentityPort } from "../identity-5LJ_B8go.mjs";
2
2
  export { IdentityPort };
@@ -1,2 +1,2 @@
1
- import { n as Listener, r as Transport, t as Connection } from "../transport-BrAqN6I5.cjs";
1
+ import { n as Listener, r as Transport, t as Connection } from "../transport-Baipikk7.cjs";
2
2
  export { Connection, Listener, Transport };
@@ -1,2 +1,2 @@
1
- import { n as Listener, r as Transport, t as Connection } from "../transport-B_diuPHT.mjs";
1
+ import { n as Listener, r as Transport, t as Connection } from "../transport-DWbvUc3L.mjs";
2
2
  export { Connection, Listener, Transport };
@@ -843,6 +843,7 @@ declare const revocationClaimsSchema: z.ZodLazy<z.ZodObject<{
843
843
  "public-key": z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
844
844
  }, z.core.$strip>>>;
845
845
  "revoked-at": z.ZodNumber;
846
+ authorization: z.ZodOptional<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
846
847
  }, z.core.$strip>>;
847
848
  declare const revocationEntrySchema: z.ZodLazy<z.ZodLazy<z.ZodLazy<z.ZodTuple<[z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodLazy<z.ZodLazy<z.ZodObject<{
848
849
  "1": z.ZodOptional<z.ZodNumber>;
@@ -843,6 +843,7 @@ declare const revocationClaimsSchema: z.ZodLazy<z.ZodObject<{
843
843
  "public-key": z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
844
844
  }, z.core.$strip>>>;
845
845
  "revoked-at": z.ZodNumber;
846
+ authorization: z.ZodOptional<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
846
847
  }, z.core.$strip>>;
847
848
  declare const revocationEntrySchema: z.ZodLazy<z.ZodLazy<z.ZodLazy<z.ZodTuple<[z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodLazy<z.ZodLazy<z.ZodObject<{
848
849
  "1": z.ZodOptional<z.ZodNumber>;
@@ -0,0 +1,43 @@
1
+ //#region src/domain/token-scope.ts
2
+ /**
3
+ * Extracted out of tokens.ts specifically so token-predicates.ts (the generic evaluator's own delegate handlers) and tokens.ts (the chain walk, and its re-export for capability-grant.ts) can both depend on this pure, no-domain-imports module without creating an import cycle between the two -- tokens.ts imports evaluateNarrowing from token-predicates.ts, and token-predicates.ts's own scope-narrows/bearer-is handlers need these exact comparisons, so neither of those two files may import the other.
4
+ */
5
+ function bytesEqual(a, b) {
6
+ if (a.length !== b.length) return false;
7
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
8
+ return true;
9
+ }
10
+ /** True when the path contains a "." or ".." segment. Purely lexical prefix comparison would let "/work/../org" pass under "/work" -- a path that normalises outside the parent -- so any relative segment fails the narrowing comparison wholesale: fail-closed rather than reimplementing path normalisation, consistent with how empty, case-different, and non-boundary-prefixed paths already behave. */
11
+ function hasRelativeSegment(path) {
12
+ return path.split("/").some((segment) => segment === "." || segment === "..");
13
+ }
14
+ /** True when childPath is parentPath or a descendant of it, compared on "/"-segment boundaries: "/work/sub" narrows "/work", but "/workbook" does NOT narrow "/work" despite the string prefix, because "book" continues the same segment. Paths containing "." or ".." segments never narrow anything (see hasRelativeSegment). */
15
+ function pathNarrows(childPath, parentPath) {
16
+ if (hasRelativeSegment(childPath) || hasRelativeSegment(parentPath)) return false;
17
+ if (childPath === parentPath) return true;
18
+ if (!childPath.startsWith(parentPath)) return false;
19
+ if (parentPath.endsWith("/")) return true;
20
+ return childPath.charAt(parentPath.length) === "/";
21
+ }
22
+ /**
23
+ * True when childScope narrows parentScope per tokens.cddl ("each hop can only narrow authority, never widen it"): the kind must be identical (a different kind is a different kind of authority, not a narrower one), and a parent with a path requires the child to carry an equal-or-descendant path -- an absent child path means the kind's whole-scope root, which is wider than any path-narrowed parent. A parent with no path (whole-scope root) lets any child path under the same kind through. Exported for capability-grant.ts's own obligation 4 (an unsolicited push's embedded token must equal-or-root the enclosing request's own scope), which is exactly this same narrowing relation applied outside a delegation chain, and for token-predicates.ts's own `scope-narrows` delegate handler.
24
+ */
25
+ function scopeNarrows(parent, child) {
26
+ if (parent.kind !== child.kind) return false;
27
+ if (parent.path === void 0) return true;
28
+ if (child.path === void 0) return false;
29
+ return pathNarrows(child.path, parent.path);
30
+ }
31
+ //#endregion
32
+ Object.defineProperty(exports, "bytesEqual", {
33
+ enumerable: true,
34
+ get: function() {
35
+ return bytesEqual;
36
+ }
37
+ });
38
+ Object.defineProperty(exports, "scopeNarrows", {
39
+ enumerable: true,
40
+ get: function() {
41
+ return scopeNarrows;
42
+ }
43
+ });
@@ -0,0 +1,32 @@
1
+ //#region src/domain/token-scope.ts
2
+ /**
3
+ * Extracted out of tokens.ts specifically so token-predicates.ts (the generic evaluator's own delegate handlers) and tokens.ts (the chain walk, and its re-export for capability-grant.ts) can both depend on this pure, no-domain-imports module without creating an import cycle between the two -- tokens.ts imports evaluateNarrowing from token-predicates.ts, and token-predicates.ts's own scope-narrows/bearer-is handlers need these exact comparisons, so neither of those two files may import the other.
4
+ */
5
+ function bytesEqual(a, b) {
6
+ if (a.length !== b.length) return false;
7
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
8
+ return true;
9
+ }
10
+ /** True when the path contains a "." or ".." segment. Purely lexical prefix comparison would let "/work/../org" pass under "/work" -- a path that normalises outside the parent -- so any relative segment fails the narrowing comparison wholesale: fail-closed rather than reimplementing path normalisation, consistent with how empty, case-different, and non-boundary-prefixed paths already behave. */
11
+ function hasRelativeSegment(path) {
12
+ return path.split("/").some((segment) => segment === "." || segment === "..");
13
+ }
14
+ /** True when childPath is parentPath or a descendant of it, compared on "/"-segment boundaries: "/work/sub" narrows "/work", but "/workbook" does NOT narrow "/work" despite the string prefix, because "book" continues the same segment. Paths containing "." or ".." segments never narrow anything (see hasRelativeSegment). */
15
+ function pathNarrows(childPath, parentPath) {
16
+ if (hasRelativeSegment(childPath) || hasRelativeSegment(parentPath)) return false;
17
+ if (childPath === parentPath) return true;
18
+ if (!childPath.startsWith(parentPath)) return false;
19
+ if (parentPath.endsWith("/")) return true;
20
+ return childPath.charAt(parentPath.length) === "/";
21
+ }
22
+ /**
23
+ * True when childScope narrows parentScope per tokens.cddl ("each hop can only narrow authority, never widen it"): the kind must be identical (a different kind is a different kind of authority, not a narrower one), and a parent with a path requires the child to carry an equal-or-descendant path -- an absent child path means the kind's whole-scope root, which is wider than any path-narrowed parent. A parent with no path (whole-scope root) lets any child path under the same kind through. Exported for capability-grant.ts's own obligation 4 (an unsolicited push's embedded token must equal-or-root the enclosing request's own scope), which is exactly this same narrowing relation applied outside a delegation chain, and for token-predicates.ts's own `scope-narrows` delegate handler.
24
+ */
25
+ function scopeNarrows(parent, child) {
26
+ if (parent.kind !== child.kind) return false;
27
+ if (parent.path === void 0) return true;
28
+ if (child.path === void 0) return false;
29
+ return pathNarrows(child.path, parent.path);
30
+ }
31
+ //#endregion
32
+ export { scopeNarrows as n, bytesEqual as t };
@@ -1,5 +1,5 @@
1
- import { dt as RevocationEntry, kt as TokenClaims, s as CapabilityToken, ut as RevocationClaims, x as DeviceId } from "./protocol-B3U828E7.mjs";
2
- import { t as IdentityPort } from "./identity-B7YMBhMf.mjs";
1
+ import { dt as RevocationEntry, kt as TokenClaims, s as CapabilityToken, ut as RevocationClaims, x as DeviceId } from "./protocol-l9RMR3s5.mjs";
2
+ import { t as IdentityPort } from "./identity-5LJ_B8go.mjs";
3
3
  import { t as Clock } from "./clock-DiSx-WKM.mjs";
4
4
  import { z } from "zod";
5
5
  import { JsonValue, PredicateNode, Resolution } from "trilean";
@@ -21,10 +21,10 @@ type TokenDelegateHandler<TContext> = (payload: JsonValue, context: TContext) =>
21
21
  //#endregion
22
22
  //#region src/domain/tokens.d.ts
23
23
  /**
24
- * The revocation view a verifier consults. Contract per management.cddl: an entry counts against a token only when BOTH its token-id and its issuer match the token's own -- only a token's own issuer may revoke it, so a third party's entry for someone else's token-id must be ignored. Implementations ingest gossiped revocation-announce frames via verifyRevocationEntry (which enforces each entry's own signature and self-certification) and key the resulting claims by token-id + issuer.
24
+ * The revocation view a verifier consults. Returns every recorded, already-signature-verified revocation-claims for tokenId, across every issuer that has ever submitted one -- unfiltered by the store itself. The actual verifier obligation (an entry counts against a token when its own issuer matches the token's own issuer, OR its optional `authorization` grants delegated revoke authority -- management.cddl) is checked by the caller (verifyTokenChain), not here, since that check needs the target token's own scope plus identity/clock to verify a nested authorization token, none of which a store constructed ahead of time has access to. Implementations ingest gossiped revocation-announce frames via verifyRevocationEntry (which enforces each entry's own signature and self-certification) and key the resulting claims by token-id alone -- a token-id can legitimately carry multiple recorded entries from different issuers.
25
25
  */
26
26
  interface RevocationCheck {
27
- isRevoked: (tokenId: Uint8Array, issuer: DeviceId) => Promise<boolean>;
27
+ entriesFor: (tokenId: Uint8Array) => Promise<readonly RevocationClaims[]>;
28
28
  }
29
29
  type TokenVerdictReason = "malformed" | "bad_signature" | "wrong_issuer" | "bearer_mismatch" | "expired" | "not_yet_valid" | "content_expired" | "revoked" | "delegation_exceeds_parent" | "parent_invalid" |
30
30
  /** claims.conditions is present but its bstr fails CBOR decode, or decodes to something that is not a JSON array of valid trilean PredicateNodes -- fail-closed per CONVENTIONS.md's verifier-obligations glossary, the same treatment "malformed" already gives an undecodable payload. */
@@ -1,38 +1,8 @@
1
1
  const require_generated_protocol = require("./generated/protocol.cjs");
2
+ const require_token_scope = require("./token-scope-CxHXTT3u.cjs");
2
3
  let zod = require("zod");
3
4
  let cbor2 = require("cbor2");
4
5
  let trilean = require("trilean");
5
- //#region src/domain/token-scope.ts
6
- /**
7
- * Extracted out of tokens.ts specifically so token-predicates.ts (the generic evaluator's own delegate handlers) and tokens.ts (the chain walk, and its re-export for capability-grant.ts) can both depend on this pure, no-domain-imports module without creating an import cycle between the two -- tokens.ts imports evaluateNarrowing from token-predicates.ts, and token-predicates.ts's own scope-narrows/bearer-is handlers need these exact comparisons, so neither of those two files may import the other.
8
- */
9
- function bytesEqual(a, b) {
10
- if (a.length !== b.length) return false;
11
- for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
12
- return true;
13
- }
14
- /** True when the path contains a "." or ".." segment. Purely lexical prefix comparison would let "/work/../org" pass under "/work" -- a path that normalises outside the parent -- so any relative segment fails the narrowing comparison wholesale: fail-closed rather than reimplementing path normalisation, consistent with how empty, case-different, and non-boundary-prefixed paths already behave. */
15
- function hasRelativeSegment(path) {
16
- return path.split("/").some((segment) => segment === "." || segment === "..");
17
- }
18
- /** True when childPath is parentPath or a descendant of it, compared on "/"-segment boundaries: "/work/sub" narrows "/work", but "/workbook" does NOT narrow "/work" despite the string prefix, because "book" continues the same segment. Paths containing "." or ".." segments never narrow anything (see hasRelativeSegment). */
19
- function pathNarrows(childPath, parentPath) {
20
- if (hasRelativeSegment(childPath) || hasRelativeSegment(parentPath)) return false;
21
- if (childPath === parentPath) return true;
22
- if (!childPath.startsWith(parentPath)) return false;
23
- if (parentPath.endsWith("/")) return true;
24
- return childPath.charAt(parentPath.length) === "/";
25
- }
26
- /**
27
- * True when childScope narrows parentScope per tokens.cddl ("each hop can only narrow authority, never widen it"): the kind must be identical (a different kind is a different kind of authority, not a narrower one), and a parent with a path requires the child to carry an equal-or-descendant path -- an absent child path means the kind's whole-scope root, which is wider than any path-narrowed parent. A parent with no path (whole-scope root) lets any child path under the same kind through. Exported for capability-grant.ts's own obligation 4 (an unsolicited push's embedded token must equal-or-root the enclosing request's own scope), which is exactly this same narrowing relation applied outside a delegation chain, and for token-predicates.ts's own `scope-narrows` delegate handler.
28
- */
29
- function scopeNarrows(parent, child) {
30
- if (parent.kind !== child.kind) return false;
31
- if (parent.path === void 0) return true;
32
- if (child.path === void 0) return false;
33
- return pathNarrows(child.path, parent.path);
34
- }
35
- //#endregion
36
6
  //#region src/domain/token-predicates.ts
37
7
  /** The wire shape of `token-claims.conditions` once CBOR-decoded: trilean's own PredicateNodeSchema is the single source of truth for what a condition entry may contain, re-validated here rather than trusted from a CDDL-generated shadow schema (see tokens.cddl's own comment on why `conditions` is an opaque bstr, not a native CDDL type) -- a token from an untrusted peer must pass trilean's real schema before any of its conditions are evaluated. Explicitly annotated: trilean's PredicateNodeSchema is a deeply recursive z.lazy() type whose inferred shape is too large for tsdown's declaration-file generator to serialise (TS7056) without this. */
38
8
  const conditionsListSchema = zod.z.array(trilean.PredicateNodeSchema);
@@ -67,7 +37,7 @@ function booleanFound(value) {
67
37
  const narrowingHandlers = {
68
38
  [BEARER_IS]: (_payload, context) => {
69
39
  if (context.parentClaims === void 0) return booleanFound(false);
70
- return booleanFound(bytesEqual(context.parentClaims.bearer, context.childIssuer));
40
+ return booleanFound(require_token_scope.bytesEqual(context.parentClaims.bearer, context.childIssuer));
71
41
  },
72
42
  [EXPIRES_AT]: (_payload, context) => {
73
43
  if (context.parentClaims === void 0) return booleanFound(false);
@@ -75,7 +45,7 @@ const narrowingHandlers = {
75
45
  },
76
46
  [SCOPE_NARROWS]: (_payload, context) => {
77
47
  if (context.parentClaims === void 0) return booleanFound(false);
78
- return booleanFound(scopeNarrows(context.parentClaims.scope, context.candidate.scope));
48
+ return booleanFound(require_token_scope.scopeNarrows(context.parentClaims.scope, context.candidate.scope));
79
49
  },
80
50
  [CAPABILITY_IS]: (_payload, context) => {
81
51
  if (context.parentClaims === void 0) return booleanFound(false);
@@ -211,12 +181,32 @@ async function verifyCapabilityToken(token, options) {
211
181
  ...options.extraPredicateResolvers !== void 0 ? { extraPredicateResolvers: options.extraPredicateResolvers } : {}
212
182
  });
213
183
  if (!verdict.ok) return verdict;
214
- if (options.expectedBearer !== void 0 && !bytesEqual(verdict.claims.bearer, options.expectedBearer)) return {
184
+ if (options.expectedBearer !== void 0 && !require_token_scope.bytesEqual(verdict.claims.bearer, options.expectedBearer)) return {
215
185
  ok: false,
216
186
  reason: "bearer_mismatch"
217
187
  };
218
188
  return verdict;
219
189
  }
190
+ /**
191
+ * Does one recorded revocation-claims entry actually revoke targetClaims, per management.cddl's own additive obligation? Valid when EITHER the entry's own issuer equals the target token's own issuer (the original, unconditional rule -- only a token's own issuer may revoke it), OR the entry carries an `authorization` that independently verifies as an ordinary capability-token -- with `expectedBearer` set to THIS entry's own `issuer`, proving the authorization was actually granted to the party submitting this revocation, not merely referenced from someone else's -- whose own `capability` is `manage:revoke` (spec/registry/core-capabilities.md) and whose own `scope` narrows targetClaims' scope. An authorization that fails any part of this (wrong capability, scope doesn't narrow, fails ordinary verification -- expired, revoked, bad signature, bearer mismatch) makes the entry no more valid than if `authorization` were absent; it never falls back to weakening the issuer-match rule.
192
+ */
193
+ async function revocationEntryGrantsRevoke(entry, targetClaims, options) {
194
+ if (require_token_scope.bytesEqual(entry.issuer, targetClaims.issuer)) return true;
195
+ if (entry.authorization === void 0) return false;
196
+ let decodedAuthorization;
197
+ try {
198
+ decodedAuthorization = (0, cbor2.decode)(entry.authorization, cbor2.cdeDecodeOptions);
199
+ } catch {
200
+ return false;
201
+ }
202
+ const authorizationResult = require_generated_protocol.capabilityTokenSchema.safeParse(decodedAuthorization);
203
+ if (!authorizationResult.success) return false;
204
+ const authorizationVerdict = await verifyCapabilityToken(authorizationResult.data, {
205
+ ...options,
206
+ expectedBearer: entry.issuer
207
+ });
208
+ return authorizationVerdict.ok && authorizationVerdict.claims.capability === "manage:revoke" && require_token_scope.scopeNarrows(authorizationVerdict.claims.scope, targetClaims.scope);
209
+ }
220
210
  async function verifyTokenChain(token, options) {
221
211
  const [protectedHeader, , payload, signature] = token;
222
212
  if (payload === null) return {
@@ -242,7 +232,8 @@ async function verifyTokenChain(token, options) {
242
232
  ok: false,
243
233
  reason: "bad_signature"
244
234
  };
245
- if (!bytesEqual(await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]), claims.issuer)) return {
235
+ const derivedIssuerId = await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]);
236
+ if (!require_token_scope.bytesEqual(derivedIssuerId, claims.issuer)) return {
246
237
  ok: false,
247
238
  reason: "wrong_issuer"
248
239
  };
@@ -260,7 +251,8 @@ async function verifyTokenChain(token, options) {
260
251
  ok: false,
261
252
  reason: "content_expired"
262
253
  };
263
- if (await options.revocation.isRevoked(claims["token-id"], claims.issuer)) return {
254
+ const revocationEntries = await options.revocation.entriesFor(claims["token-id"]);
255
+ for (const entry of revocationEntries) if (await revocationEntryGrantsRevoke(entry, claims, options)) return {
264
256
  ok: false,
265
257
  reason: "revoked"
266
258
  };
@@ -356,7 +348,8 @@ async function verifyRevocationEntry(entry, options) {
356
348
  ok: false,
357
349
  reason: "bad_signature"
358
350
  };
359
- if (!bytesEqual(await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]), claims.issuer)) return {
351
+ const derivedIssuerId = await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]);
352
+ if (!require_token_scope.bytesEqual(derivedIssuerId, claims.issuer)) return {
360
353
  ok: false,
361
354
  reason: "wrong_issuer"
362
355
  };
@@ -479,12 +472,6 @@ Object.defineProperty(exports, "mintRevocationEntry", {
479
472
  return mintRevocationEntry;
480
473
  }
481
474
  });
482
- Object.defineProperty(exports, "scopeNarrows", {
483
- enumerable: true,
484
- get: function() {
485
- return scopeNarrows;
486
- }
487
- });
488
475
  Object.defineProperty(exports, "verifyCapabilityToken", {
489
476
  enumerable: true,
490
477
  get: function() {
@@ -1,5 +1,5 @@
1
- import { dt as RevocationEntry, kt as TokenClaims, s as CapabilityToken, ut as RevocationClaims, x as DeviceId } from "./protocol-B3U828E7.cjs";
2
- import { t as IdentityPort } from "./identity-COdFfaW8.cjs";
1
+ import { dt as RevocationEntry, kt as TokenClaims, s as CapabilityToken, ut as RevocationClaims, x as DeviceId } from "./protocol-l9RMR3s5.cjs";
2
+ import { t as IdentityPort } from "./identity-bg6IVGsH.cjs";
3
3
  import { t as Clock } from "./clock-DiSx-WKM.cjs";
4
4
  import { z } from "zod";
5
5
  import { JsonValue, PredicateNode, Resolution } from "trilean";
@@ -21,10 +21,10 @@ type TokenDelegateHandler<TContext> = (payload: JsonValue, context: TContext) =>
21
21
  //#endregion
22
22
  //#region src/domain/tokens.d.ts
23
23
  /**
24
- * The revocation view a verifier consults. Contract per management.cddl: an entry counts against a token only when BOTH its token-id and its issuer match the token's own -- only a token's own issuer may revoke it, so a third party's entry for someone else's token-id must be ignored. Implementations ingest gossiped revocation-announce frames via verifyRevocationEntry (which enforces each entry's own signature and self-certification) and key the resulting claims by token-id + issuer.
24
+ * The revocation view a verifier consults. Returns every recorded, already-signature-verified revocation-claims for tokenId, across every issuer that has ever submitted one -- unfiltered by the store itself. The actual verifier obligation (an entry counts against a token when its own issuer matches the token's own issuer, OR its optional `authorization` grants delegated revoke authority -- management.cddl) is checked by the caller (verifyTokenChain), not here, since that check needs the target token's own scope plus identity/clock to verify a nested authorization token, none of which a store constructed ahead of time has access to. Implementations ingest gossiped revocation-announce frames via verifyRevocationEntry (which enforces each entry's own signature and self-certification) and key the resulting claims by token-id alone -- a token-id can legitimately carry multiple recorded entries from different issuers.
25
25
  */
26
26
  interface RevocationCheck {
27
- isRevoked: (tokenId: Uint8Array, issuer: DeviceId) => Promise<boolean>;
27
+ entriesFor: (tokenId: Uint8Array) => Promise<readonly RevocationClaims[]>;
28
28
  }
29
29
  type TokenVerdictReason = "malformed" | "bad_signature" | "wrong_issuer" | "bearer_mismatch" | "expired" | "not_yet_valid" | "content_expired" | "revoked" | "delegation_exceeds_parent" | "parent_invalid" |
30
30
  /** claims.conditions is present but its bstr fails CBOR decode, or decodes to something that is not a JSON array of valid trilean PredicateNodes -- fail-closed per CONVENTIONS.md's verifier-obligations glossary, the same treatment "malformed" already gives an undecodable payload. */
@@ -1,38 +1,8 @@
1
1
  import { capabilityTokenSchema, revocationClaimsSchema, tokenClaimsSchema } from "./generated/protocol.mjs";
2
+ import { n as scopeNarrows, t as bytesEqual } from "./token-scope-Z4bmci4M.mjs";
2
3
  import { z } from "zod";
3
4
  import { cdeDecodeOptions, cdeEncodeOptions, decode, encode } from "cbor2";
4
5
  import { PredicateNodeSchema, evaluatePredicate } from "trilean";
5
- //#region src/domain/token-scope.ts
6
- /**
7
- * Extracted out of tokens.ts specifically so token-predicates.ts (the generic evaluator's own delegate handlers) and tokens.ts (the chain walk, and its re-export for capability-grant.ts) can both depend on this pure, no-domain-imports module without creating an import cycle between the two -- tokens.ts imports evaluateNarrowing from token-predicates.ts, and token-predicates.ts's own scope-narrows/bearer-is handlers need these exact comparisons, so neither of those two files may import the other.
8
- */
9
- function bytesEqual(a, b) {
10
- if (a.length !== b.length) return false;
11
- for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
12
- return true;
13
- }
14
- /** True when the path contains a "." or ".." segment. Purely lexical prefix comparison would let "/work/../org" pass under "/work" -- a path that normalises outside the parent -- so any relative segment fails the narrowing comparison wholesale: fail-closed rather than reimplementing path normalisation, consistent with how empty, case-different, and non-boundary-prefixed paths already behave. */
15
- function hasRelativeSegment(path) {
16
- return path.split("/").some((segment) => segment === "." || segment === "..");
17
- }
18
- /** True when childPath is parentPath or a descendant of it, compared on "/"-segment boundaries: "/work/sub" narrows "/work", but "/workbook" does NOT narrow "/work" despite the string prefix, because "book" continues the same segment. Paths containing "." or ".." segments never narrow anything (see hasRelativeSegment). */
19
- function pathNarrows(childPath, parentPath) {
20
- if (hasRelativeSegment(childPath) || hasRelativeSegment(parentPath)) return false;
21
- if (childPath === parentPath) return true;
22
- if (!childPath.startsWith(parentPath)) return false;
23
- if (parentPath.endsWith("/")) return true;
24
- return childPath.charAt(parentPath.length) === "/";
25
- }
26
- /**
27
- * True when childScope narrows parentScope per tokens.cddl ("each hop can only narrow authority, never widen it"): the kind must be identical (a different kind is a different kind of authority, not a narrower one), and a parent with a path requires the child to carry an equal-or-descendant path -- an absent child path means the kind's whole-scope root, which is wider than any path-narrowed parent. A parent with no path (whole-scope root) lets any child path under the same kind through. Exported for capability-grant.ts's own obligation 4 (an unsolicited push's embedded token must equal-or-root the enclosing request's own scope), which is exactly this same narrowing relation applied outside a delegation chain, and for token-predicates.ts's own `scope-narrows` delegate handler.
28
- */
29
- function scopeNarrows(parent, child) {
30
- if (parent.kind !== child.kind) return false;
31
- if (parent.path === void 0) return true;
32
- if (child.path === void 0) return false;
33
- return pathNarrows(child.path, parent.path);
34
- }
35
- //#endregion
36
6
  //#region src/domain/token-predicates.ts
37
7
  /** The wire shape of `token-claims.conditions` once CBOR-decoded: trilean's own PredicateNodeSchema is the single source of truth for what a condition entry may contain, re-validated here rather than trusted from a CDDL-generated shadow schema (see tokens.cddl's own comment on why `conditions` is an opaque bstr, not a native CDDL type) -- a token from an untrusted peer must pass trilean's real schema before any of its conditions are evaluated. Explicitly annotated: trilean's PredicateNodeSchema is a deeply recursive z.lazy() type whose inferred shape is too large for tsdown's declaration-file generator to serialise (TS7056) without this. */
38
8
  const conditionsListSchema = z.array(PredicateNodeSchema);
@@ -217,6 +187,26 @@ async function verifyCapabilityToken(token, options) {
217
187
  };
218
188
  return verdict;
219
189
  }
190
+ /**
191
+ * Does one recorded revocation-claims entry actually revoke targetClaims, per management.cddl's own additive obligation? Valid when EITHER the entry's own issuer equals the target token's own issuer (the original, unconditional rule -- only a token's own issuer may revoke it), OR the entry carries an `authorization` that independently verifies as an ordinary capability-token -- with `expectedBearer` set to THIS entry's own `issuer`, proving the authorization was actually granted to the party submitting this revocation, not merely referenced from someone else's -- whose own `capability` is `manage:revoke` (spec/registry/core-capabilities.md) and whose own `scope` narrows targetClaims' scope. An authorization that fails any part of this (wrong capability, scope doesn't narrow, fails ordinary verification -- expired, revoked, bad signature, bearer mismatch) makes the entry no more valid than if `authorization` were absent; it never falls back to weakening the issuer-match rule.
192
+ */
193
+ async function revocationEntryGrantsRevoke(entry, targetClaims, options) {
194
+ if (bytesEqual(entry.issuer, targetClaims.issuer)) return true;
195
+ if (entry.authorization === void 0) return false;
196
+ let decodedAuthorization;
197
+ try {
198
+ decodedAuthorization = decode(entry.authorization, cdeDecodeOptions);
199
+ } catch {
200
+ return false;
201
+ }
202
+ const authorizationResult = capabilityTokenSchema.safeParse(decodedAuthorization);
203
+ if (!authorizationResult.success) return false;
204
+ const authorizationVerdict = await verifyCapabilityToken(authorizationResult.data, {
205
+ ...options,
206
+ expectedBearer: entry.issuer
207
+ });
208
+ return authorizationVerdict.ok && authorizationVerdict.claims.capability === "manage:revoke" && scopeNarrows(authorizationVerdict.claims.scope, targetClaims.scope);
209
+ }
220
210
  async function verifyTokenChain(token, options) {
221
211
  const [protectedHeader, , payload, signature] = token;
222
212
  if (payload === null) return {
@@ -242,7 +232,8 @@ async function verifyTokenChain(token, options) {
242
232
  ok: false,
243
233
  reason: "bad_signature"
244
234
  };
245
- if (!bytesEqual(await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]), claims.issuer)) return {
235
+ const derivedIssuerId = await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]);
236
+ if (!bytesEqual(derivedIssuerId, claims.issuer)) return {
246
237
  ok: false,
247
238
  reason: "wrong_issuer"
248
239
  };
@@ -260,7 +251,8 @@ async function verifyTokenChain(token, options) {
260
251
  ok: false,
261
252
  reason: "content_expired"
262
253
  };
263
- if (await options.revocation.isRevoked(claims["token-id"], claims.issuer)) return {
254
+ const revocationEntries = await options.revocation.entriesFor(claims["token-id"]);
255
+ for (const entry of revocationEntries) if (await revocationEntryGrantsRevoke(entry, claims, options)) return {
264
256
  ok: false,
265
257
  reason: "revoked"
266
258
  };
@@ -356,7 +348,8 @@ async function verifyRevocationEntry(entry, options) {
356
348
  ok: false,
357
349
  reason: "bad_signature"
358
350
  };
359
- if (!bytesEqual(await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]), claims.issuer)) return {
351
+ const derivedIssuerId = await options.identity.deriveDeviceId(claims["issuer-key"]["public-key"]);
352
+ if (!bytesEqual(derivedIssuerId, claims.issuer)) return {
360
353
  ok: false,
361
354
  reason: "wrong_issuer"
362
355
  };
@@ -461,4 +454,4 @@ async function mintRevocationEntry(options) {
461
454
  ];
462
455
  }
463
456
  //#endregion
464
- export { verifyRevocationEntry as a, verifyCapabilityToken as i, mintCapabilityToken as n, scopeNarrows as o, mintRevocationEntry as r, canGrant as t };
457
+ export { verifyRevocationEntry as a, verifyCapabilityToken as i, mintCapabilityToken as n, mintRevocationEntry as r, canGrant as t };
@@ -1,4 +1,4 @@
1
- import { D as Frame, x as DeviceId } from "./protocol-B3U828E7.mjs";
1
+ import { D as Frame, x as DeviceId } from "./protocol-l9RMR3s5.cjs";
2
2
  //#region src/ports/transport.d.ts
3
3
  /**
4
4
  * An async, serialisable-data contract for exchanging frame values over some connection -- deliberately without baking in any specific transport's own primitives (no raw socket types, no WebSocket-specific options), so a TCP adapter, a WebSocket adapter, or an in-memory adapter for tests can all satisfy it.
@@ -1,4 +1,4 @@
1
- import { D as Frame, x as DeviceId } from "./protocol-B3U828E7.cjs";
1
+ import { D as Frame, x as DeviceId } from "./protocol-l9RMR3s5.mjs";
2
2
  //#region src/ports/transport.d.ts
3
3
  /**
4
4
  * An async, serialisable-data contract for exchanging frame values over some connection -- deliberately without baking in any specific transport's own primitives (no raw socket types, no WebSocket-specific options), so a TCP adapter, a WebSocket adapter, or an in-memory adapter for tests can all satisfy it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wire-mesh-core",
3
- "version": "1.19.0",
3
+ "version": "1.21.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
6
6
  "repository": {
@@ -98,6 +98,10 @@
98
98
  "import": "./dist/domain/device-id.mjs",
99
99
  "require": "./dist/domain/device-id.cjs"
100
100
  },
101
+ "./domain/grant-candidates": {
102
+ "import": "./dist/domain/grant-candidates.mjs",
103
+ "require": "./dist/domain/grant-candidates.cjs"
104
+ },
101
105
  "./domain/handshake": {
102
106
  "import": "./dist/domain/handshake.mjs",
103
107
  "require": "./dist/domain/handshake.cjs"