@interop/wallet-core 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/enrollment/enrollment.d.ts +144 -0
  2. package/dist/enrollment/enrollment.d.ts.map +1 -0
  3. package/dist/enrollment/enrollment.js +296 -0
  4. package/dist/enrollment/enrollment.js.map +1 -0
  5. package/dist/enrollment/index.d.ts +20 -0
  6. package/dist/enrollment/index.d.ts.map +1 -0
  7. package/dist/enrollment/index.js +19 -0
  8. package/dist/enrollment/index.js.map +1 -0
  9. package/dist/identity/index.d.ts +0 -5
  10. package/dist/identity/index.d.ts.map +1 -1
  11. package/dist/identity/index.js +0 -4
  12. package/dist/identity/index.js.map +1 -1
  13. package/dist/index.d.ts +13 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +13 -3
  16. package/dist/index.js.map +1 -1
  17. package/dist/keyring/fetch.d.ts +22 -0
  18. package/dist/keyring/fetch.d.ts.map +1 -0
  19. package/dist/keyring/fetch.js +35 -0
  20. package/dist/keyring/fetch.js.map +1 -0
  21. package/dist/keyring/index.d.ts +30 -0
  22. package/dist/keyring/index.d.ts.map +1 -0
  23. package/dist/keyring/index.js +28 -0
  24. package/dist/keyring/index.js.map +1 -0
  25. package/dist/keyring/kdf.d.ts +102 -0
  26. package/dist/keyring/kdf.d.ts.map +1 -0
  27. package/dist/keyring/kdf.js +148 -0
  28. package/dist/keyring/kdf.js.map +1 -0
  29. package/dist/keyring/record.d.ts +98 -0
  30. package/dist/keyring/record.d.ts.map +1 -0
  31. package/dist/keyring/record.js +119 -0
  32. package/dist/keyring/record.js.map +1 -0
  33. package/dist/keyring/unlockSpace.d.ts +101 -0
  34. package/dist/keyring/unlockSpace.d.ts.map +1 -0
  35. package/dist/keyring/unlockSpace.js +226 -0
  36. package/dist/keyring/unlockSpace.js.map +1 -0
  37. package/dist/keys/index.d.ts +24 -0
  38. package/dist/keys/index.d.ts.map +1 -0
  39. package/dist/keys/index.js +22 -0
  40. package/dist/keys/index.js.map +1 -0
  41. package/dist/keys/puk.d.ts +42 -0
  42. package/dist/keys/puk.d.ts.map +1 -0
  43. package/dist/keys/puk.js +56 -0
  44. package/dist/keys/puk.js.map +1 -0
  45. package/dist/keys/pukRoster.d.ts +210 -0
  46. package/dist/keys/pukRoster.d.ts.map +1 -0
  47. package/dist/keys/pukRoster.js +263 -0
  48. package/dist/keys/pukRoster.js.map +1 -0
  49. package/dist/keys/rosterStore.d.ts +18 -0
  50. package/dist/keys/rosterStore.d.ts.map +1 -0
  51. package/dist/keys/rosterStore.js +38 -0
  52. package/dist/keys/rosterStore.js.map +1 -0
  53. package/dist/space/collections.d.ts +57 -0
  54. package/dist/space/collections.d.ts.map +1 -1
  55. package/dist/space/collections.js +48 -0
  56. package/dist/space/collections.js.map +1 -1
  57. package/dist/space/index.d.ts +4 -0
  58. package/dist/space/index.d.ts.map +1 -1
  59. package/dist/space/index.js +4 -0
  60. package/dist/space/index.js.map +1 -1
  61. package/dist/webvh/didWeb.d.ts +41 -0
  62. package/dist/webvh/didWeb.d.ts.map +1 -0
  63. package/dist/webvh/didWeb.js +24 -0
  64. package/dist/webvh/didWeb.js.map +1 -0
  65. package/dist/webvh/didWebvh.d.ts +251 -0
  66. package/dist/webvh/didWebvh.d.ts.map +1 -0
  67. package/dist/webvh/didWebvh.js +775 -0
  68. package/dist/webvh/didWebvh.js.map +1 -0
  69. package/dist/webvh/index.d.ts +27 -0
  70. package/dist/webvh/index.d.ts.map +1 -0
  71. package/dist/webvh/index.js +24 -0
  72. package/dist/webvh/index.js.map +1 -0
  73. package/dist/webvh/zcap.d.ts +104 -0
  74. package/dist/webvh/zcap.d.ts.map +1 -0
  75. package/dist/webvh/zcap.js +117 -0
  76. package/dist/webvh/zcap.js.map +1 -0
  77. package/package.json +30 -4
  78. package/dist/identity/collectionKeys.d.ts +0 -36
  79. package/dist/identity/collectionKeys.d.ts.map +0 -1
  80. package/dist/identity/collectionKeys.js +0 -92
  81. package/dist/identity/collectionKeys.js.map +0 -1
@@ -0,0 +1,210 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The PUK wrap set: the `key-map/puk.json` roster resource. Its body is a
6
+ * `CollectionEncryption` marker verbatim, whose current epoch IS the current
7
+ * per-user key -- the epoch id is the PUK's did:key and the wrapped secret is
8
+ * the PUK's raw 32-byte key, wrapped to each enrolled client's key-agreement
9
+ * key. The roster is the delivery channel for PUK rotation: each client keeps
10
+ * the PUK in its own local state under the unlock layer, and the roster's
11
+ * epoch stamp marks a cached copy stale.
12
+ *
13
+ * Everything mutates through was-client's marker-store seam (the
14
+ * plain-resource adapter): read-with-etag, compare-and-swap writes, and a
15
+ * guarded create for the initially-absent roster. No marker logic is
16
+ * reimplemented here.
17
+ *
18
+ * A resource-hosted marker gets NONE of the server-side epoch invariants a
19
+ * Collection Description enforces (append-only epochs, monotone
20
+ * `currentEpoch`), so three client-side compensations are load-bearing alone
21
+ * against a tampering host:
22
+ *
23
+ * - **`epochsMac`** -- the epoch configuration is authenticated under the
24
+ * current epoch's secret, which the server never holds; a fabricated
25
+ * configuration fails the MAC (`PukRosterIntegrityError`).
26
+ * - **The epoch pin** -- the latest-seen roster epoch is pinned locally by the
27
+ * consuming app (beside the account-pointer pin); a served
28
+ * roster that rolls back behind the pin is refused
29
+ * (`PukRosterContinuityError`) rather than followed. Stale-roster replay
30
+ * thereby lands in the same accepted continuity class as a substituted
31
+ * account pointer.
32
+ * - **The roster delivers, never sources** -- the recipient-key source of
33
+ * record is the locally verified did:webvh document (one `keyAgreement`
34
+ * verification method per enrolled client). When an epoch rotates, each
35
+ * remaining recipient's key is resolved from that document
36
+ * (`pukRosterRecipientResolver`); a roster entry with no matching document
37
+ * verification method is dropped and never receives a wrap, so a
38
+ * server-injected entry sits ignored. Wraps are minted only by enrolled
39
+ * clients, against log-verified keys.
40
+ */
41
+ import type { IKeyAgreementKey } from '@interop/data-integrity-core';
42
+ import type { CollectionEncryption } from '@interop/was-client';
43
+ import { type MarkerStore, type RecipientPublicKey } from '@interop/was-client/edv';
44
+ import type { Puk } from './puk.js';
45
+ /**
46
+ * Thrown when a served roster fails its client-side authentication: a
47
+ * missing/unsupported/invalid `epochsMac`, or a marker whose `currentEpoch`
48
+ * names no epoch in its own list. The server (or whoever can write to it) has
49
+ * produced a configuration no enrolled client authenticated.
50
+ */
51
+ export declare class PukRosterIntegrityError extends Error {
52
+ constructor(message: string);
53
+ }
54
+ /**
55
+ * Thrown when a served roster conflicts with the locally pinned latest-seen
56
+ * epoch -- the epochs list no longer contains the pinned epoch, or
57
+ * `currentEpoch` precedes it in the (append-only) list. A rollback/replay of
58
+ * an older consistent configuration, which a valid `epochsMac` alone cannot
59
+ * catch; refused rather than followed.
60
+ */
61
+ export declare class PukRosterContinuityError extends Error {
62
+ pinnedEpochId: string;
63
+ constructor({ pinnedEpochId }: {
64
+ pinnedEpochId: string;
65
+ });
66
+ }
67
+ /**
68
+ * Thrown when this client holds no usable wrap in the roster's current epoch
69
+ * (no recipient entry for its key-agreement key, or the entry fails to
70
+ * unwrap). The client cannot obtain the current PUK -- it may have been
71
+ * rotated off the roster.
72
+ */
73
+ export declare class PukRosterUnwrapError extends Error {
74
+ constructor(message: string);
75
+ }
76
+ /**
77
+ * The subset of a resolved DID document the recipient resolver consumes: the
78
+ * `keyAgreement` relation (VM references or embedded VMs) and the
79
+ * `verificationMethod` list references resolve against.
80
+ */
81
+ export interface RosterRecipientDocument {
82
+ keyAgreement?: Array<string | {
83
+ id?: string;
84
+ publicKeyMultibase?: string;
85
+ }>;
86
+ verificationMethod?: Array<{
87
+ id?: string;
88
+ publicKeyMultibase?: string;
89
+ }>;
90
+ }
91
+ /**
92
+ * Builds the recipient resolver for roster rotations, backed by a locally
93
+ * verified did:webvh document -- the enforcement point for "the roster
94
+ * delivers, never sources". Given a remaining recipient's `kid`, it answers
95
+ * with that recipient's public key ONLY when the document carries a matching
96
+ * `keyAgreement` verification method (matched on the public-key multibase, so
97
+ * a did:key-form kid matches its `<did:webvh>#<multibase>` VM); otherwise it
98
+ * resolves `null` -- the was-client skip contract -- so the entry is dropped
99
+ * from the fresh epoch and never receives a wrap.
100
+ *
101
+ * @param options {object}
102
+ * @param options.document {RosterRecipientDocument} the locally verified
103
+ * did:webvh document (never a server-supplied roster field)
104
+ * @returns {function} a `resolveRecipientKey` for `removeRecipient`
105
+ */
106
+ export declare function pukRosterRecipientResolver({ document }: {
107
+ document: RosterRecipientDocument;
108
+ }): (kid: string) => Promise<RecipientPublicKey | null>;
109
+ /**
110
+ * Ensures the roster exists, create-if-absent: an absent roster is
111
+ * initialized with the account's existing PUK installed as the first epoch,
112
+ * wrapped to this client's key-agreement key; an existing roster is returned
113
+ * as-is (authentication is the read path's job, and provisioning must never
114
+ * clobber an established roster). Idempotent -- losing the guarded-create
115
+ * race to a concurrent first init converges on the winner's roster.
116
+ *
117
+ * @param options {object}
118
+ * @param options.store {MarkerStore} the roster's marker store
119
+ * @param options.puk {Puk} the account's per-user key
120
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
121
+ * (identity) key-agreement key -- the roster recipient
122
+ * @returns {Promise<CollectionEncryption>} the roster marker
123
+ */
124
+ export declare function ensurePukRoster({ store, puk, clientKeyAgreementKey }: {
125
+ store: MarkerStore;
126
+ puk: Puk;
127
+ clientKeyAgreementKey: IKeyAgreementKey;
128
+ }): Promise<CollectionEncryption>;
129
+ /**
130
+ * Wraps the PUK to a client being enrolled -- the roster half of the
131
+ * enrollment ceremony, and deliberately its FIRST write (decryption material
132
+ * before authorization, the push order): the wrap lands before the did:webvh
133
+ * log entries, so no enrolled client is ever authorized but blind, and a tear
134
+ * right after this write leaves only an orphan wrap -- invisible to
135
+ * authorization, harmless, resumed by re-running the ceremony.
136
+ *
137
+ * Escrow semantics ride on was-client's `addRecipient`: the new client
138
+ * receives EVERY epoch's key, current and prior, so it decrypts
139
+ * pre-enrollment history. The recipient key arrives over the point-to-point
140
+ * enrollment channel and is verified there by the enrolling client (the
141
+ * document VM it writes next comes from the same exchange) -- never sourced
142
+ * from the roster. Idempotent: a wrap already standing in the current epoch
143
+ * is returned as-is.
144
+ *
145
+ * @param options {object}
146
+ * @param options.store {MarkerStore} the roster's marker store
147
+ * @param options.recipient {RecipientPublicKey} the enrollee's public
148
+ * key-agreement key; `id` is the kid its own roster reads will look for
149
+ * @param options.ownerKeyAgreementKey {IKeyAgreementKey} the enrolling
150
+ * client's own (identity) key-agreement key, unwrapping each epoch for
151
+ * re-wrapping
152
+ * @returns {Promise<CollectionEncryption>} the refreshed roster marker
153
+ */
154
+ export declare function addPukRosterRecipient({ store, recipient, ownerKeyAgreementKey }: {
155
+ store: MarkerStore;
156
+ recipient: RecipientPublicKey;
157
+ ownerKeyAgreementKey: IKeyAgreementKey;
158
+ }): Promise<CollectionEncryption>;
159
+ /**
160
+ * What a roster read resolves to: the authenticated marker, the current PUK
161
+ * (the cached one confirmed current, or a fresh one unwrapped from a rotated
162
+ * epoch -- `rotated` says which), and the epoch id the caller must pin as the
163
+ * new latest-seen.
164
+ */
165
+ export interface PukRosterReadResult {
166
+ marker: CollectionEncryption;
167
+ puk: Puk;
168
+ rotated: boolean;
169
+ latestEpochId: string;
170
+ }
171
+ /**
172
+ * Reads and authenticates the roster -- the direct read at login and on epoch
173
+ * mismatch. Resolves `null` when the roster does not exist yet (an account
174
+ * provisioned before the roster, or provisioning still in flight); otherwise:
175
+ *
176
+ * 1. **Continuity**: the served epochs must contain the pinned latest-seen
177
+ * epoch, and `currentEpoch` must not precede it in the append-only list
178
+ * (`PukRosterContinuityError` -- the rollback/replay refusal).
179
+ * 2. **Possession**: `currentEpoch === puk.id` confirms the cached PUK
180
+ * current; otherwise the current epoch was rotated by another client and
181
+ * this client's wrap is unwrapped with its own key-agreement key
182
+ * (`PukRosterUnwrapError` when it holds none).
183
+ * 3. **Authentication**: the marker's `epochsMac` is verified under the
184
+ * current epoch's secret (`PukRosterIntegrityError` on any mismatch -- a
185
+ * fabricated configuration).
186
+ *
187
+ * A rotated read returns the fresh PUK; its Ed25519 signing seed does not
188
+ * travel through the roster (the roster wraps the key-agreement secret
189
+ * alone), so the returned PUK carries none.
190
+ *
191
+ * A caller with no cached PUK at all -- a freshly enrolled client making its
192
+ * first post-enrollment read -- omits `puk` and always takes the unwrap path;
193
+ * the result's `rotated` is then true (the PUK was adopted from the roster).
194
+ *
195
+ * @param options {object}
196
+ * @param options.store {MarkerStore} the roster's marker store
197
+ * @param [options.puk] {Puk} this client's cached PUK, when it holds one
198
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
199
+ * (identity) key-agreement key, unwrapping a rotated epoch
200
+ * @param [options.pinnedEpochId] {string} the locally pinned latest-seen
201
+ * roster epoch, when this client has seen the roster before
202
+ * @returns {Promise<PukRosterReadResult | null>}
203
+ */
204
+ export declare function readPukRoster({ store, puk, clientKeyAgreementKey, pinnedEpochId }: {
205
+ store: MarkerStore;
206
+ puk?: Puk;
207
+ clientKeyAgreementKey: IKeyAgreementKey;
208
+ pinnedEpochId?: string | null;
209
+ }): Promise<PukRosterReadResult | null>;
210
+ //# sourceMappingURL=pukRoster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pukRoster.d.ts","sourceRoot":"","sources":["../../src/keys/pukRoster.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,aAAa,EAAE,MAAM,CAAA;gBACT,EAAE,aAAa,EAAE,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;CAQzD;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3E,kBAAkB,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACzE;AAgBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,uBAAuB,CAAA;CAClC,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAsCtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CAAC,EACpC,KAAK,EACL,GAAG,EACH,qBAAqB,EACtB,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,GAAG,EAAE,GAAG,CAAA;IACR,qBAAqB,EAAE,gBAAgB,CAAA;CACxC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAUhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,KAAK,EACL,SAAS,EACT,oBAAoB,EACrB,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,SAAS,EAAE,kBAAkB,CAAA;IAC7B,oBAAoB,EAAE,gBAAgB,CAAA;CACvC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0BhC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,GAAG,EAAE,GAAG,CAAA;IACR,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,aAAa,CAAC,EAClC,KAAK,EACL,GAAG,EACH,qBAAqB,EACrB,aAAa,EACd,EAAE;IACD,KAAK,EAAE,WAAW,CAAA;IAClB,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAwEtC"}
@@ -0,0 +1,263 @@
1
+ import { addRecipient, initRecipients, ownerRecipient, unwrapEpochSecret, verifyEpochsMac } from '@interop/was-client/edv';
2
+ /**
3
+ * Thrown when a served roster fails its client-side authentication: a
4
+ * missing/unsupported/invalid `epochsMac`, or a marker whose `currentEpoch`
5
+ * names no epoch in its own list. The server (or whoever can write to it) has
6
+ * produced a configuration no enrolled client authenticated.
7
+ */
8
+ export class PukRosterIntegrityError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = 'PukRosterIntegrityError';
12
+ }
13
+ }
14
+ /**
15
+ * Thrown when a served roster conflicts with the locally pinned latest-seen
16
+ * epoch -- the epochs list no longer contains the pinned epoch, or
17
+ * `currentEpoch` precedes it in the (append-only) list. A rollback/replay of
18
+ * an older consistent configuration, which a valid `epochsMac` alone cannot
19
+ * catch; refused rather than followed.
20
+ */
21
+ export class PukRosterContinuityError extends Error {
22
+ pinnedEpochId;
23
+ constructor({ pinnedEpochId }) {
24
+ super('The PUK roster no longer carries the epoch this client has pinned -- ' +
25
+ 'a rolled-back or replayed roster.');
26
+ this.name = 'PukRosterContinuityError';
27
+ this.pinnedEpochId = pinnedEpochId;
28
+ }
29
+ }
30
+ /**
31
+ * Thrown when this client holds no usable wrap in the roster's current epoch
32
+ * (no recipient entry for its key-agreement key, or the entry fails to
33
+ * unwrap). The client cannot obtain the current PUK -- it may have been
34
+ * rotated off the roster.
35
+ */
36
+ export class PukRosterUnwrapError extends Error {
37
+ constructor(message) {
38
+ super(message);
39
+ this.name = 'PukRosterUnwrapError';
40
+ }
41
+ }
42
+ /**
43
+ * The fragment after the last `#` of a key/VM id -- for the ids this roster
44
+ * handles (did:key KAK ids, `<did>#<multibase>` VM ids) that fragment is the
45
+ * key's public multibase, which is what makes kid-to-VM matching key-material
46
+ * equality rather than string equality across id formats.
47
+ *
48
+ * @param id {string}
49
+ * @returns {string | undefined}
50
+ */
51
+ function multibaseFragmentOf(id) {
52
+ const hash = id.lastIndexOf('#');
53
+ return hash === -1 ? undefined : id.slice(hash + 1);
54
+ }
55
+ /**
56
+ * Builds the recipient resolver for roster rotations, backed by a locally
57
+ * verified did:webvh document -- the enforcement point for "the roster
58
+ * delivers, never sources". Given a remaining recipient's `kid`, it answers
59
+ * with that recipient's public key ONLY when the document carries a matching
60
+ * `keyAgreement` verification method (matched on the public-key multibase, so
61
+ * a did:key-form kid matches its `<did:webvh>#<multibase>` VM); otherwise it
62
+ * resolves `null` -- the was-client skip contract -- so the entry is dropped
63
+ * from the fresh epoch and never receives a wrap.
64
+ *
65
+ * @param options {object}
66
+ * @param options.document {RosterRecipientDocument} the locally verified
67
+ * did:webvh document (never a server-supplied roster field)
68
+ * @returns {function} a `resolveRecipientKey` for `removeRecipient`
69
+ */
70
+ export function pukRosterRecipientResolver({ document }) {
71
+ // Materialize the document's keyAgreement VMs once: embedded VMs verbatim,
72
+ // string references resolved against `verificationMethod`.
73
+ const byId = new Map();
74
+ for (const method of document.verificationMethod ?? []) {
75
+ if (typeof method?.id === 'string') {
76
+ byId.set(method.id, method);
77
+ }
78
+ }
79
+ const keyAgreementMethods = [];
80
+ for (const entry of document.keyAgreement ?? []) {
81
+ const method = typeof entry === 'string' ? byId.get(entry) : entry;
82
+ if (method && typeof method.publicKeyMultibase === 'string') {
83
+ keyAgreementMethods.push(method);
84
+ }
85
+ }
86
+ return async function resolveRecipientKey(kid) {
87
+ const fragment = multibaseFragmentOf(kid);
88
+ if (!fragment) {
89
+ return null;
90
+ }
91
+ const match = keyAgreementMethods.find(method => method.publicKeyMultibase === fragment ||
92
+ (typeof method.id === 'string' &&
93
+ multibaseFragmentOf(method.id) === fragment));
94
+ if (!match) {
95
+ // No document verification method backs this roster entry: drop it.
96
+ return null;
97
+ }
98
+ return { id: kid, publicKeyMultibase: match.publicKeyMultibase };
99
+ };
100
+ }
101
+ /**
102
+ * Ensures the roster exists, create-if-absent: an absent roster is
103
+ * initialized with the account's existing PUK installed as the first epoch,
104
+ * wrapped to this client's key-agreement key; an existing roster is returned
105
+ * as-is (authentication is the read path's job, and provisioning must never
106
+ * clobber an established roster). Idempotent -- losing the guarded-create
107
+ * race to a concurrent first init converges on the winner's roster.
108
+ *
109
+ * @param options {object}
110
+ * @param options.store {MarkerStore} the roster's marker store
111
+ * @param options.puk {Puk} the account's per-user key
112
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
113
+ * (identity) key-agreement key -- the roster recipient
114
+ * @returns {Promise<CollectionEncryption>} the roster marker
115
+ */
116
+ export async function ensurePukRoster({ store, puk, clientKeyAgreementKey }) {
117
+ const current = await store.read();
118
+ if (current !== null) {
119
+ return current.marker;
120
+ }
121
+ return initRecipients({
122
+ store,
123
+ recipients: [ownerRecipient({ keyAgreementKey: clientKeyAgreementKey })],
124
+ epoch: { epochId: puk.id, secret: puk.secret }
125
+ });
126
+ }
127
+ /**
128
+ * Wraps the PUK to a client being enrolled -- the roster half of the
129
+ * enrollment ceremony, and deliberately its FIRST write (decryption material
130
+ * before authorization, the push order): the wrap lands before the did:webvh
131
+ * log entries, so no enrolled client is ever authorized but blind, and a tear
132
+ * right after this write leaves only an orphan wrap -- invisible to
133
+ * authorization, harmless, resumed by re-running the ceremony.
134
+ *
135
+ * Escrow semantics ride on was-client's `addRecipient`: the new client
136
+ * receives EVERY epoch's key, current and prior, so it decrypts
137
+ * pre-enrollment history. The recipient key arrives over the point-to-point
138
+ * enrollment channel and is verified there by the enrolling client (the
139
+ * document VM it writes next comes from the same exchange) -- never sourced
140
+ * from the roster. Idempotent: a wrap already standing in the current epoch
141
+ * is returned as-is.
142
+ *
143
+ * @param options {object}
144
+ * @param options.store {MarkerStore} the roster's marker store
145
+ * @param options.recipient {RecipientPublicKey} the enrollee's public
146
+ * key-agreement key; `id` is the kid its own roster reads will look for
147
+ * @param options.ownerKeyAgreementKey {IKeyAgreementKey} the enrolling
148
+ * client's own (identity) key-agreement key, unwrapping each epoch for
149
+ * re-wrapping
150
+ * @returns {Promise<CollectionEncryption>} the refreshed roster marker
151
+ */
152
+ export async function addPukRosterRecipient({ store, recipient, ownerKeyAgreementKey }) {
153
+ const current = await store.read();
154
+ if (current === null) {
155
+ throw new Error('The PUK roster does not exist yet; the account must finish ' +
156
+ 'provisioning before a client can be enrolled.');
157
+ }
158
+ const marker = current.marker;
159
+ const currentEpoch = (marker.epochs ?? []).find(epoch => epoch.id === marker.currentEpoch);
160
+ const wrapped = currentEpoch?.recipients.some(entry => entry.header.kid === recipient.id);
161
+ if (wrapped) {
162
+ // A completed (or torn-after-the-wrap) earlier run: addRecipient writes
163
+ // every epoch's wrap in one marker write, so the current epoch standing
164
+ // means the escrow set is complete.
165
+ return marker;
166
+ }
167
+ return addRecipient({
168
+ store,
169
+ recipient,
170
+ owner: { keyAgreementKey: ownerKeyAgreementKey }
171
+ });
172
+ }
173
+ /**
174
+ * Reads and authenticates the roster -- the direct read at login and on epoch
175
+ * mismatch. Resolves `null` when the roster does not exist yet (an account
176
+ * provisioned before the roster, or provisioning still in flight); otherwise:
177
+ *
178
+ * 1. **Continuity**: the served epochs must contain the pinned latest-seen
179
+ * epoch, and `currentEpoch` must not precede it in the append-only list
180
+ * (`PukRosterContinuityError` -- the rollback/replay refusal).
181
+ * 2. **Possession**: `currentEpoch === puk.id` confirms the cached PUK
182
+ * current; otherwise the current epoch was rotated by another client and
183
+ * this client's wrap is unwrapped with its own key-agreement key
184
+ * (`PukRosterUnwrapError` when it holds none).
185
+ * 3. **Authentication**: the marker's `epochsMac` is verified under the
186
+ * current epoch's secret (`PukRosterIntegrityError` on any mismatch -- a
187
+ * fabricated configuration).
188
+ *
189
+ * A rotated read returns the fresh PUK; its Ed25519 signing seed does not
190
+ * travel through the roster (the roster wraps the key-agreement secret
191
+ * alone), so the returned PUK carries none.
192
+ *
193
+ * A caller with no cached PUK at all -- a freshly enrolled client making its
194
+ * first post-enrollment read -- omits `puk` and always takes the unwrap path;
195
+ * the result's `rotated` is then true (the PUK was adopted from the roster).
196
+ *
197
+ * @param options {object}
198
+ * @param options.store {MarkerStore} the roster's marker store
199
+ * @param [options.puk] {Puk} this client's cached PUK, when it holds one
200
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
201
+ * (identity) key-agreement key, unwrapping a rotated epoch
202
+ * @param [options.pinnedEpochId] {string} the locally pinned latest-seen
203
+ * roster epoch, when this client has seen the roster before
204
+ * @returns {Promise<PukRosterReadResult | null>}
205
+ */
206
+ export async function readPukRoster({ store, puk, clientKeyAgreementKey, pinnedEpochId }) {
207
+ const current = await store.read();
208
+ if (current === null) {
209
+ return null;
210
+ }
211
+ const marker = current.marker;
212
+ const epochIds = (marker.epochs ?? []).map(epoch => epoch.id);
213
+ const currentIndex = marker.currentEpoch
214
+ ? epochIds.indexOf(marker.currentEpoch)
215
+ : -1;
216
+ if (currentIndex === -1) {
217
+ throw new PukRosterIntegrityError('The PUK roster names no current epoch in its own epoch list.');
218
+ }
219
+ if (pinnedEpochId) {
220
+ const pinnedIndex = epochIds.indexOf(pinnedEpochId);
221
+ if (pinnedIndex === -1 || currentIndex < pinnedIndex) {
222
+ throw new PukRosterContinuityError({ pinnedEpochId });
223
+ }
224
+ }
225
+ // The epochsMac construction's own version/alg are the caller's to check.
226
+ const epochsMac = marker.epochsMac;
227
+ if (!epochsMac || epochsMac.v !== 1 || epochsMac.alg !== 'HS256') {
228
+ throw new PukRosterIntegrityError('The PUK roster carries no supported epoch-configuration MAC.');
229
+ }
230
+ let currentPuk;
231
+ let rotated;
232
+ if (puk && marker.currentEpoch === puk.id) {
233
+ currentPuk = puk;
234
+ rotated = false;
235
+ }
236
+ else {
237
+ // Rotated by another client: unwrap this client's entry in the current
238
+ // epoch with its own key-agreement key (rotation delivery).
239
+ const entry = marker.epochs[currentIndex].recipients.find(recipient => recipient.header.kid === clientKeyAgreementKey.id);
240
+ if (!entry) {
241
+ throw new PukRosterUnwrapError('The PUK roster current epoch carries no wrap for this client.');
242
+ }
243
+ const secret = await unwrapEpochSecret({
244
+ entry,
245
+ keyAgreementKey: clientKeyAgreementKey
246
+ });
247
+ if (!secret) {
248
+ throw new PukRosterUnwrapError("This client's PUK roster entry failed to unwrap.");
249
+ }
250
+ currentPuk = { id: marker.currentEpoch, secret };
251
+ rotated = true;
252
+ }
253
+ if (!(await verifyEpochsMac({ marker, epochSecret: currentPuk.secret }))) {
254
+ throw new PukRosterIntegrityError('The PUK roster epoch configuration failed authentication.');
255
+ }
256
+ return {
257
+ marker,
258
+ puk: currentPuk,
259
+ rotated,
260
+ latestEpochId: marker.currentEpoch
261
+ };
262
+ }
263
+ //# sourceMappingURL=pukRoster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pukRoster.js","sourceRoot":"","sources":["../../src/keys/pukRoster.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ZcapClient } from '@interop/ezcap';
2
+ import { type MarkerStore } from '@interop/was-client/edv';
3
+ /**
4
+ * Builds the compare-and-swap marker store over `key-map/puk.json` in a data
5
+ * Space.
6
+ *
7
+ * @param options {object}
8
+ * @param options.storageServerUrl {string}
9
+ * @param options.zcapClient {ZcapClient} the session's root signing client
10
+ * @param options.spaceId {string} the data Space id
11
+ * @returns {MarkerStore}
12
+ */
13
+ export declare function pukRosterMarkerStore({ storageServerUrl, zcapClient, spaceId }: {
14
+ storageServerUrl: string;
15
+ zcapClient: ZcapClient;
16
+ spaceId: string;
17
+ }): MarkerStore;
18
+ //# sourceMappingURL=rosterStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rosterStore.d.ts","sourceRoot":"","sources":["../../src/keys/rosterStore.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAM/E;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,WAAW,CAQd"}
@@ -0,0 +1,38 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The marker store over a Space's PUK wrap-set roster (`key-map/puk.json`).
6
+ * Standalone rather than a method on a wallet's remote-store class, because
7
+ * the login-time direct read checks the roster BEFORE any storage client (or
8
+ * cipher) is built: it takes the bare signing client instead of a store
9
+ * instance.
10
+ *
11
+ * The `plaintext` collection override is load-bearing. Without it the client
12
+ * decides plaintext vs encrypted by describing the collection first, and a 404
13
+ * from an absent Space or collection then surfaces as an encryption error
14
+ * rather than as an absent roster.
15
+ */
16
+ import { WasClient } from '@interop/was-client';
17
+ import { resourceMarkerStore } from '@interop/was-client/edv';
18
+ import { KEY_MAP_COLLECTION, PUK_ROSTER_RESOURCE } from '../space/collections.js';
19
+ /**
20
+ * Builds the compare-and-swap marker store over `key-map/puk.json` in a data
21
+ * Space.
22
+ *
23
+ * @param options {object}
24
+ * @param options.storageServerUrl {string}
25
+ * @param options.zcapClient {ZcapClient} the session's root signing client
26
+ * @param options.spaceId {string} the data Space id
27
+ * @returns {MarkerStore}
28
+ */
29
+ export function pukRosterMarkerStore({ storageServerUrl, zcapClient, spaceId }) {
30
+ const was = new WasClient({ serverUrl: storageServerUrl, zcapClient });
31
+ return resourceMarkerStore({
32
+ resource: was
33
+ .space(spaceId)
34
+ .collection(KEY_MAP_COLLECTION.id, { encryption: 'plaintext' })
35
+ .resource(PUK_ROSTER_RESOURCE)
36
+ });
37
+ }
38
+ //# sourceMappingURL=rosterStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rosterStore.js","sourceRoot":"","sources":["../../src/keys/rosterStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,EAAE,mBAAmB,EAAoB,MAAM,yBAAyB,CAAA;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,yBAAyB,CAAA;AAEhC;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,UAAU,EACV,OAAO,EAKR;IACC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IACtE,OAAO,mBAAmB,CAAC;QACzB,QAAQ,EAAE,GAAG;aACV,KAAK,CAAC,OAAO,CAAC;aACd,UAAU,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;aAC9D,QAAQ,CAAC,mBAAmB,CAAC;KACjC,CAAC,CAAA;AACJ,CAAC"}
@@ -62,4 +62,61 @@ export declare const PUBLIC_CREDENTIALS_COLLECTION_SPEC: SpaceCollectionSpec;
62
62
  export declare const WALLET_ACTIVITY_COLLECTION_SPEC: SpaceCollectionSpec;
63
63
  /** The wallet Space's own (non-contacts) collection specs, in provision order. */
64
64
  export declare const WALLET_SPACE_COLLECTION_SPECS: SpaceCollectionSpec[];
65
+ /**
66
+ * The system collections and resource names that carry an account's identity
67
+ * and key material. They sit deliberately OUTSIDE the synced collection specs
68
+ * above: none of them gets a local replica or background replication, and each
69
+ * is read and written directly.
70
+ *
71
+ * - `id` -- world-readable (a collection-level public-read policy): the
72
+ * published DID document (`did.json`) and the did:webvh history log
73
+ * (`did.jsonl`). The path segments name the collection that holds the
74
+ * document, so the did:web id is `did:web:<host>:space:<spaceId>:id` and
75
+ * resolves to `https://<host>/space/<spaceId>/id/did.json`.
76
+ * - `key-map` -- private and capability-gated: the key-id map (`keys.json`)
77
+ * and the PUK wrap-set roster (`puk.json`). Kept separate from `id` exactly
78
+ * so `id` can be made world-readable without ever exposing key material.
79
+ * - `keyring` -- the unlock Space's single collection, holding the one
80
+ * keyring record (`keyring.json`). It lives in the minimal unlock Space
81
+ * controlled by an unlock identity, never in the wallet data Space.
82
+ */
83
+ export declare const ID_COLLECTION: {
84
+ id: string;
85
+ name: string;
86
+ };
87
+ export declare const KEY_MAP_COLLECTION: {
88
+ id: string;
89
+ name: string;
90
+ };
91
+ export declare const KEYRING_COLLECTION: {
92
+ id: string;
93
+ name: string;
94
+ };
95
+ /** The world-readable DID document, served as `application/did+json`. */
96
+ export declare const DID_DOCUMENT_RESOURCE = "did.json";
97
+ /**
98
+ * The world-readable did:webvh history log, a raw JSON-Lines string served as
99
+ * `text/jsonl`: one log entry per line, each a full DID-document snapshot in a
100
+ * hash chain. Sibling of `did.json` in the same `id` collection;
101
+ * `did:webvh:<scid>:<host>:space:<spaceId>:id` resolves to
102
+ * `https://<host>/space/<spaceId>/id/did.jsonl`.
103
+ */
104
+ export declare const DID_LOG_RESOURCE = "did.jsonl";
105
+ /**
106
+ * The (non-public) key-id map: verification method to KMS key id. Lives in the
107
+ * `key-map` collection. The recovery anchor -- written before `did.json` so a
108
+ * torn provisioning resumes from it.
109
+ */
110
+ export declare const DID_KEYS_RESOURCE = "keys.json";
111
+ /**
112
+ * The per-user-key (PUK) wrap-set roster, sibling of `keys.json` in the same
113
+ * private `key-map` collection: a `CollectionEncryption` marker stored
114
+ * verbatim as the resource body, whose current epoch IS the current PUK (the
115
+ * epoch id is the PUK's did:key; the wrapped secret is the PUK's raw key,
116
+ * wrapped to each enrolled client's key-agreement key). Read directly with a
117
+ * compare-and-swap etag -- never replicated.
118
+ */
119
+ export declare const PUK_ROSTER_RESOURCE = "puk.json";
120
+ /** The keyring record: the encrypted account pointer, in the unlock Space. */
121
+ export declare const KEYRING_RESOURCE = "keyring.json";
65
122
  //# sourceMappingURL=collections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/space/collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AACnE,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,uBAAuB,CAAA;AACjE,0DAA0D;AAC1D,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,QAAQ,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,KAAK,GAAG,WAAW,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,mCAAmC,EAAE,mBAMjD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,mBAMhD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAM7C,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,EAAE,mBAAmB,EAI9D,CAAA"}
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/space/collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AACnE,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,uBAAuB,CAAA;AACjE,0DAA0D;AAC1D,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,QAAQ,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,KAAK,GAAG,WAAW,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,mCAAmC,EAAE,mBAMjD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,mBAMhD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAM7C,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,EAAE,mBAAmB,EAI9D,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa;;;CAAiC,CAAA;AAC3D,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AACpE,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AAEpE,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,aAAa,CAAA;AAC/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAA;AAC3C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,cAAc,CAAA;AAC5C;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAC7C,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,iBAAiB,CAAA"}