@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,101 @@
1
+ import type { IZcap } from '@interop/data-integrity-core';
2
+ import type { ZcapClient } from '@interop/ezcap';
3
+ /**
4
+ * The default Space Description name an unlock Space is configured with.
5
+ * Wire-visible (it is the Space's stored name), so it stays stable across
6
+ * apps unless a caller deliberately overrides it.
7
+ */
8
+ export declare const UNLOCK_SPACE_NAME = "Freewallet Keyring";
9
+ /**
10
+ * Ensures the unlock Space and its single `keyring` collection exist
11
+ * (upsert -- idempotent). Runs with the unlock root capability, so `force`
12
+ * lets the collection upsert treat a 404 from the pre-merge describe as
13
+ * genuinely absent rather than unreadable.
14
+ *
15
+ * @param options {object}
16
+ * @param options.storageServerUrl {string}
17
+ * @param options.zcapClient {ZcapClient}
18
+ * @param options.spaceId {string} the unlock Space id
19
+ * @param options.controller {string} the unlock did:key
20
+ * @param [options.name] {string} the Space Description name
21
+ * @returns {Promise<void>}
22
+ */
23
+ export declare function ensureUnlockSpace({ storageServerUrl, zcapClient, spaceId, controller, name }: {
24
+ storageServerUrl: string;
25
+ zcapClient: ZcapClient;
26
+ spaceId: string;
27
+ controller: string;
28
+ name?: string;
29
+ }): Promise<void>;
30
+ /**
31
+ * Reads the keyring record from the unlock Space, or returns `null` when it
32
+ * does not exist yet. A network / unreachable error propagates, so callers can
33
+ * distinguish "no keyring" from "could not check".
34
+ *
35
+ * @param options {object}
36
+ * @param options.storageServerUrl {string}
37
+ * @param options.zcapClient {ZcapClient}
38
+ * @param options.spaceId {string} the unlock Space id
39
+ * @returns {Promise<unknown | null>}
40
+ */
41
+ export declare function getUnlockKeyring({ storageServerUrl, zcapClient, spaceId }: {
42
+ storageServerUrl: string;
43
+ zcapClient: ZcapClient;
44
+ spaceId: string;
45
+ }): Promise<unknown | null>;
46
+ /**
47
+ * Writes (upserts) the keyring record into the unlock Space as a JSON document.
48
+ *
49
+ * @param options {object}
50
+ * @param options.storageServerUrl {string}
51
+ * @param options.zcapClient {ZcapClient}
52
+ * @param options.spaceId {string} the unlock Space id
53
+ * @param options.record {object} the keyring record
54
+ * @returns {Promise<void>}
55
+ */
56
+ export declare function putUnlockKeyring({ storageServerUrl, zcapClient, spaceId, record }: {
57
+ storageServerUrl: string;
58
+ zcapClient: ZcapClient;
59
+ spaceId: string;
60
+ record: object;
61
+ }): Promise<void>;
62
+ /**
63
+ * Deletes the whole unlock Space (what retires an old passphrase on a
64
+ * passphrase change). `space.delete()` is idempotent, so an already-absent
65
+ * Space is a success.
66
+ *
67
+ * @param options {object}
68
+ * @param options.storageServerUrl {string}
69
+ * @param options.zcapClient {ZcapClient}
70
+ * @param options.spaceId {string} the unlock Space id
71
+ * @returns {Promise<void>}
72
+ */
73
+ export declare function deleteUnlockSpace({ storageServerUrl, zcapClient, spaceId }: {
74
+ storageServerUrl: string;
75
+ zcapClient: ZcapClient;
76
+ spaceId: string;
77
+ }): Promise<void>;
78
+ /**
79
+ * Deletes an unlock Space with an explicitly attached management capability,
80
+ * rather than by root invocation. The `zcapClient` here is the DATA identity's
81
+ * (not the unlock identity's); the attached `capability` -- the management zcap
82
+ * the unlock identity delegated to the data identity at bind time -- is what
83
+ * authorizes the DELETE against the unlock Space. This is the tap-free
84
+ * revocation path for a lost unlock method: the data identity can retire it
85
+ * without re-deriving the unlock identity from the (possibly lost) secret. A
86
+ * 404 is treated as success (idempotent -- the Space is already gone).
87
+ *
88
+ * @param options {object}
89
+ * @param options.storageServerUrl {string}
90
+ * @param options.zcapClient {ZcapClient} the data identity's client
91
+ * @param options.spaceId {string} the unlock Space id
92
+ * @param options.capability {IZcap} the delegated management zcap
93
+ * @returns {Promise<void>}
94
+ */
95
+ export declare function deleteUnlockSpaceWithCapability({ storageServerUrl, zcapClient, spaceId, capability }: {
96
+ storageServerUrl: string;
97
+ zcapClient: ZcapClient;
98
+ spaceId: string;
99
+ capability: IZcap;
100
+ }): Promise<void>;
101
+ //# sourceMappingURL=unlockSpace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlockSpace.d.ts","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uBAAuB,CAAA;AAoIrD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACV,IAAwB,EACzB,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQ1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EACP,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,+BAA+B,CAAC,EACpD,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACX,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,KAAK,CAAA;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB"}
@@ -0,0 +1,226 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The unlock Space: a minimal second Space, controlled by an unlock identity
6
+ * and separate from the wallet data Space, holding the one keyring record.
7
+ * These are standalone functions rather than methods on a wallet's remote-store
8
+ * class (that store is bound to the data identity): each builds its own
9
+ * `WasClient` over the unlock agent's `zcapClient`, whose invocation signer is
10
+ * the unlock root key (root invocation, no capability attached -- the same
11
+ * posture the data Space uses).
12
+ *
13
+ * The one resource is a plaintext JSON document (its keyring payload is
14
+ * already ciphertext), so no encryption provider is wired in -- and the
15
+ * read/write handles pass the explicit `{ encryption: 'plaintext' }` override.
16
+ * The override is load-bearing: without it, the client decides plaintext vs
17
+ * encrypted by reading the collection description, and when the unlock Space
18
+ * does not exist yet (every keyring lookup for a fresh unlock secret) that read
19
+ * 404s and the client refuses to guess, throwing an EncryptionError instead of
20
+ * surfacing the miss as a 404-shaped `null`.
21
+ */
22
+ import { WasClient } from '@interop/was-client';
23
+ import { errorStatus } from '@interop/was-client/sync';
24
+ import { KEYRING_COLLECTION, KEYRING_RESOURCE } from '../space/collections.js';
25
+ /**
26
+ * The default Space Description name an unlock Space is configured with.
27
+ * Wire-visible (it is the Space's stored name), so it stays stable across
28
+ * apps unless a caller deliberately overrides it.
29
+ */
30
+ export const UNLOCK_SPACE_NAME = 'Freewallet Keyring';
31
+ /**
32
+ * The bare WAS client for an unlock Space (see the module doc for why it wires
33
+ * in no encryption provider).
34
+ *
35
+ * @param options {object}
36
+ * @param options.storageServerUrl {string}
37
+ * @param options.zcapClient {ZcapClient} built on the unlock agent's signer
38
+ * @returns {WasClient}
39
+ */
40
+ function unlockSpaceClient({ storageServerUrl, zcapClient }) {
41
+ return new WasClient({
42
+ serverUrl: storageServerUrl,
43
+ zcapClient
44
+ });
45
+ }
46
+ /**
47
+ * Ensures a plaintext collection exists in a Space (upsert -- idempotent),
48
+ * running with the invoking client's root capability so `force` lets the upsert
49
+ * treat a 404 from the pre-merge describe as genuinely absent rather than
50
+ * unreadable.
51
+ *
52
+ * @param options {object}
53
+ * @param options.storageServerUrl {string}
54
+ * @param options.zcapClient {ZcapClient}
55
+ * @param options.spaceId {string}
56
+ * @param options.collectionId {string}
57
+ * @param options.name {string}
58
+ * @returns {Promise<void>}
59
+ */
60
+ async function ensurePlaintextCollection({ storageServerUrl, zcapClient, spaceId, collectionId, name }) {
61
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
62
+ await was
63
+ .space(spaceId)
64
+ .collection(collectionId)
65
+ .configure({ name, force: true });
66
+ }
67
+ /**
68
+ * Reads a single plaintext JSON record from a Space collection, or `null` when
69
+ * it does not exist yet (a missing Space, collection, or resource all surface
70
+ * as a 404-shaped `null` from `resource.get()`). A network / unreachable error
71
+ * propagates, so callers can distinguish "no record" from "could not check".
72
+ * The explicit `plaintext` override is load-bearing (see the module doc).
73
+ *
74
+ * @param options {object}
75
+ * @param options.storageServerUrl {string}
76
+ * @param options.zcapClient {ZcapClient}
77
+ * @param options.spaceId {string}
78
+ * @param options.collectionId {string}
79
+ * @param options.resourceId {string}
80
+ * @returns {Promise<unknown | null>}
81
+ */
82
+ async function getPlaintextRecord({ storageServerUrl, zcapClient, spaceId, collectionId, resourceId }) {
83
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
84
+ const result = await was
85
+ .space(spaceId)
86
+ .collection(collectionId, { encryption: 'plaintext' })
87
+ .resource(resourceId)
88
+ .get();
89
+ return result === null ? null : result;
90
+ }
91
+ /**
92
+ * Writes (upserts) a single plaintext JSON record into a Space collection.
93
+ * Serialized to bytes with an explicit `application/json` content-type.
94
+ *
95
+ * @param options {object}
96
+ * @param options.storageServerUrl {string}
97
+ * @param options.zcapClient {ZcapClient}
98
+ * @param options.spaceId {string}
99
+ * @param options.collectionId {string}
100
+ * @param options.resourceId {string}
101
+ * @param options.record {object}
102
+ * @returns {Promise<void>}
103
+ */
104
+ async function putPlaintextRecord({ storageServerUrl, zcapClient, spaceId, collectionId, resourceId, record }) {
105
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
106
+ const body = new TextEncoder().encode(JSON.stringify(record));
107
+ await was
108
+ .space(spaceId)
109
+ .collection(collectionId, { encryption: 'plaintext' })
110
+ .resource(resourceId)
111
+ .put(body, { contentType: 'application/json' });
112
+ }
113
+ /**
114
+ * Ensures the unlock Space and its single `keyring` collection exist
115
+ * (upsert -- idempotent). Runs with the unlock root capability, so `force`
116
+ * lets the collection upsert treat a 404 from the pre-merge describe as
117
+ * genuinely absent rather than unreadable.
118
+ *
119
+ * @param options {object}
120
+ * @param options.storageServerUrl {string}
121
+ * @param options.zcapClient {ZcapClient}
122
+ * @param options.spaceId {string} the unlock Space id
123
+ * @param options.controller {string} the unlock did:key
124
+ * @param [options.name] {string} the Space Description name
125
+ * @returns {Promise<void>}
126
+ */
127
+ export async function ensureUnlockSpace({ storageServerUrl, zcapClient, spaceId, controller, name = UNLOCK_SPACE_NAME }) {
128
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
129
+ await was.space(spaceId).configure({ name, controller });
130
+ await ensurePlaintextCollection({
131
+ storageServerUrl,
132
+ zcapClient,
133
+ spaceId,
134
+ collectionId: KEYRING_COLLECTION.id,
135
+ name: KEYRING_COLLECTION.name
136
+ });
137
+ }
138
+ /**
139
+ * Reads the keyring record from the unlock Space, or returns `null` when it
140
+ * does not exist yet. A network / unreachable error propagates, so callers can
141
+ * distinguish "no keyring" from "could not check".
142
+ *
143
+ * @param options {object}
144
+ * @param options.storageServerUrl {string}
145
+ * @param options.zcapClient {ZcapClient}
146
+ * @param options.spaceId {string} the unlock Space id
147
+ * @returns {Promise<unknown | null>}
148
+ */
149
+ export async function getUnlockKeyring({ storageServerUrl, zcapClient, spaceId }) {
150
+ return getPlaintextRecord({
151
+ storageServerUrl,
152
+ zcapClient,
153
+ spaceId,
154
+ collectionId: KEYRING_COLLECTION.id,
155
+ resourceId: KEYRING_RESOURCE
156
+ });
157
+ }
158
+ /**
159
+ * Writes (upserts) the keyring record into the unlock Space as a JSON document.
160
+ *
161
+ * @param options {object}
162
+ * @param options.storageServerUrl {string}
163
+ * @param options.zcapClient {ZcapClient}
164
+ * @param options.spaceId {string} the unlock Space id
165
+ * @param options.record {object} the keyring record
166
+ * @returns {Promise<void>}
167
+ */
168
+ export async function putUnlockKeyring({ storageServerUrl, zcapClient, spaceId, record }) {
169
+ await putPlaintextRecord({
170
+ storageServerUrl,
171
+ zcapClient,
172
+ spaceId,
173
+ collectionId: KEYRING_COLLECTION.id,
174
+ resourceId: KEYRING_RESOURCE,
175
+ record
176
+ });
177
+ }
178
+ /**
179
+ * Deletes the whole unlock Space (what retires an old passphrase on a
180
+ * passphrase change). `space.delete()` is idempotent, so an already-absent
181
+ * Space is a success.
182
+ *
183
+ * @param options {object}
184
+ * @param options.storageServerUrl {string}
185
+ * @param options.zcapClient {ZcapClient}
186
+ * @param options.spaceId {string} the unlock Space id
187
+ * @returns {Promise<void>}
188
+ */
189
+ export async function deleteUnlockSpace({ storageServerUrl, zcapClient, spaceId }) {
190
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
191
+ await was.space(spaceId).delete();
192
+ }
193
+ /**
194
+ * Deletes an unlock Space with an explicitly attached management capability,
195
+ * rather than by root invocation. The `zcapClient` here is the DATA identity's
196
+ * (not the unlock identity's); the attached `capability` -- the management zcap
197
+ * the unlock identity delegated to the data identity at bind time -- is what
198
+ * authorizes the DELETE against the unlock Space. This is the tap-free
199
+ * revocation path for a lost unlock method: the data identity can retire it
200
+ * without re-deriving the unlock identity from the (possibly lost) secret. A
201
+ * 404 is treated as success (idempotent -- the Space is already gone).
202
+ *
203
+ * @param options {object}
204
+ * @param options.storageServerUrl {string}
205
+ * @param options.zcapClient {ZcapClient} the data identity's client
206
+ * @param options.spaceId {string} the unlock Space id
207
+ * @param options.capability {IZcap} the delegated management zcap
208
+ * @returns {Promise<void>}
209
+ */
210
+ export async function deleteUnlockSpaceWithCapability({ storageServerUrl, zcapClient, spaceId, capability }) {
211
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
212
+ try {
213
+ await was.request({
214
+ capability,
215
+ path: `/space/${spaceId}`,
216
+ method: 'DELETE'
217
+ });
218
+ }
219
+ catch (err) {
220
+ if (errorStatus(err) === 404) {
221
+ return;
222
+ }
223
+ throw err;
224
+ }
225
+ }
226
+ //# sourceMappingURL=unlockSpace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlockSpace.js","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAGtD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,oBAAoB,CAAA;AAErD;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,EACzB,gBAAgB,EAChB,UAAU,EAIX;IACC,OAAO,IAAI,SAAS,CAAC;QACnB,SAAS,EAAE,gBAAgB;QAC3B,UAAU;KACX,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,yBAAyB,CAAC,EACvC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,YAAY,EACZ,IAAI,EAOL;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,GAAG;SACN,KAAK,CAAC,OAAO,CAAC;SACd,UAAU,CAAC,YAAY,CAAC;SACxB,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACrC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,kBAAkB,CAAC,EAChC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,YAAY,EACZ,UAAU,EAOX;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,MAAM,GAAG,MAAM,GAAG;SACrB,KAAK,CAAC,OAAO,CAAC;SACd,UAAU,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;SACrD,QAAQ,CAAC,UAAU,CAAC;SACpB,GAAG,EAAE,CAAA;IACR,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAA;AACxC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,UAAU,kBAAkB,CAAC,EAChC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,YAAY,EACZ,UAAU,EACV,MAAM,EAQP;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7D,MAAM,GAAG;SACN,KAAK,CAAC,OAAO,CAAC;SACd,UAAU,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;SACrD,QAAQ,CAAC,UAAU,CAAC;SACpB,GAAG,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAA;AACnD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACV,IAAI,GAAG,iBAAiB,EAOzB;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;IACxD,MAAM,yBAAyB,CAAC;QAC9B,gBAAgB;QAChB,UAAU;QACV,OAAO;QACP,YAAY,EAAE,kBAAkB,CAAC,EAAE;QACnC,IAAI,EAAE,kBAAkB,CAAC,IAAI;KAC9B,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EAKR;IACC,OAAO,kBAAkB,CAAC;QACxB,gBAAgB;QAChB,UAAU;QACV,OAAO;QACP,YAAY,EAAE,kBAAkB,CAAC,EAAE;QACnC,UAAU,EAAE,gBAAgB;KAC7B,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EAMP;IACC,MAAM,kBAAkB,CAAC;QACvB,gBAAgB;QAChB,UAAU;QACV,OAAO;QACP,YAAY,EAAE,kBAAkB,CAAC,EAAE;QACnC,UAAU,EAAE,gBAAgB;QAC5B,MAAM;KACP,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EAKR;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAA;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,EACpD,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EAMX;IACC,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC,CAAA;IAC/D,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,OAAO,CAAC;YAChB,UAAU;YACV,IAAI,EAAE,UAAU,OAAO,EAAE;YACzB,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC;YAC7B,OAAM;QACR,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `@interop/wallet-core/keys` subpath: the per-user key (PUK) and its
6
+ * wrap-set roster -- recipient zero of every encrypted collection, and the one
7
+ * channel that delivers it to each enrolled wallet client.
8
+ *
9
+ * - `mintPuk` / `pukVaultKeys` -- minting the account's PUK and rebuilding the
10
+ * vault key-agreement key + resolver from stored material.
11
+ * - `ensurePukRoster` / `addPukRosterRecipient` / `readPukRoster` /
12
+ * `pukRosterRecipientResolver` -- the `key-map/puk.json` roster over the
13
+ * was-client marker-store seam, with the three client-side guards a
14
+ * resource-hosted marker needs (`epochsMac`, the latest-seen epoch pin, and
15
+ * a recipient resolver backed by the locally verified did:webvh document).
16
+ * - `pukRosterMarkerStore` -- that marker store, built from a bare signing
17
+ * client for the login-time direct read.
18
+ */
19
+ export { mintPuk, pukVaultKeys } from './puk.js';
20
+ export type { Puk } from './puk.js';
21
+ export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster } from './pukRoster.js';
22
+ export type { PukRosterReadResult, RosterRecipientDocument } from './pukRoster.js';
23
+ export { pukRosterMarkerStore } from './rosterStore.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAChD,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `@interop/wallet-core/keys` subpath: the per-user key (PUK) and its
6
+ * wrap-set roster -- recipient zero of every encrypted collection, and the one
7
+ * channel that delivers it to each enrolled wallet client.
8
+ *
9
+ * - `mintPuk` / `pukVaultKeys` -- minting the account's PUK and rebuilding the
10
+ * vault key-agreement key + resolver from stored material.
11
+ * - `ensurePukRoster` / `addPukRosterRecipient` / `readPukRoster` /
12
+ * `pukRosterRecipientResolver` -- the `key-map/puk.json` roster over the
13
+ * was-client marker-store seam, with the three client-side guards a
14
+ * resource-hosted marker needs (`epochsMac`, the latest-seen epoch pin, and
15
+ * a recipient resolver backed by the locally verified did:webvh document).
16
+ * - `pukRosterMarkerStore` -- that marker store, built from a bare signing
17
+ * client for the login-time direct read.
18
+ */
19
+ export { mintPuk, pukVaultKeys } from './puk.js';
20
+ export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster } from './pukRoster.js';
21
+ export { pukRosterMarkerStore } from './rosterStore.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGhD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAA;AAMvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,42 @@
1
+ import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
2
+ /**
3
+ * The per-user key material: the X25519 key-agreement half as minted by the
4
+ * epoch construction (`id` is the key's own did:key; `secret` its raw 32-byte
5
+ * private key), plus the 32-byte seed of the PUK's Ed25519 signing pair.
6
+ * Random per account; held in memory for the life of a session and persisted
7
+ * only inside a wrapped client-key record. The signing seed is absent on a PUK
8
+ * adopted from a roster rotation -- the roster wraps the key-agreement secret
9
+ * alone, and the signing half has no consumer yet.
10
+ */
11
+ export interface Puk {
12
+ id: string;
13
+ secret: Uint8Array;
14
+ signingSeed?: Uint8Array;
15
+ }
16
+ /**
17
+ * Mints a fresh PUK: the X25519 key-agreement pair via the was-client epoch
18
+ * construction (its did:key is the key id, its raw secret is what wraps), plus
19
+ * a random 32-byte Ed25519 signing seed -- a minted PUK is always a complete
20
+ * identity (only a rotation-adopted one lacks the signing half).
21
+ *
22
+ * @returns {Promise<Required<Puk>>}
23
+ */
24
+ export declare function mintPuk(): Promise<Required<Puk>>;
25
+ /**
26
+ * Reconstructs the PUK's key-agreement key and its single-key resolver from
27
+ * the stored material -- the vault-key pair a session supplies to the storage
28
+ * layer, making the PUK recipient zero of every encrypted collection. The key
29
+ * id is the self-describing `<did:key>#<fingerprint>` form, so grantee-side
30
+ * did:key recipient resolution routes it like any other roster entry.
31
+ *
32
+ * @param options {object}
33
+ * @param options.puk {Puk}
34
+ * @returns {{ keyAgreementKey: IKeyAgreementKey, keyResolver: IKeyResolver }}
35
+ */
36
+ export declare function pukVaultKeys({ puk }: {
37
+ puk: Puk;
38
+ }): {
39
+ keyAgreementKey: IKeyAgreementKey;
40
+ keyResolver: IKeyResolver;
41
+ };
42
+ //# sourceMappingURL=puk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puk.d.ts","sourceRoot":"","sources":["../../src/keys/puk.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AAIrC;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,UAAU,CAAA;IAClB,WAAW,CAAC,EAAE,UAAU,CAAA;CACzB;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAKtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG;IACnD,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;CAC1B,CAQA"}
@@ -0,0 +1,56 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The per-user key (PUK): the user's single roster identity for encrypted
6
+ * collections, standing in as "recipient zero" of every key-epoch roster. It is
7
+ * minted at wallet provisioning -- random, client-side, never server-held, and
8
+ * never derivable from any passphrase or seed -- and delivered to each enrolled
9
+ * client through the wrap-set roster, which each client caches in its own local
10
+ * state under the unlock layer.
11
+ *
12
+ * The key-agreement half is exactly what `@interop/was-client`'s epoch
13
+ * construction mints: a fresh X25519 pair whose did:key is the key's id and
14
+ * whose raw 32-byte secret is what gets wrapped to recipients -- so the roster
15
+ * machinery consumes the PUK unchanged. The Ed25519 signing half is a second
16
+ * independent 32-byte seed, minted now so the PUK is a complete identity, with
17
+ * no consumer yet (the pair derives from the seed on demand once one lands).
18
+ */
19
+ import { X25519KeyAgreementKey2020 } from '@interop/x25519-key-agreement-key';
20
+ import { epochKeyIdFor, mintEpoch } from '@interop/was-client/edv';
21
+ import { singleKeyResolver } from '../identity/keyResolver.js';
22
+ /**
23
+ * Mints a fresh PUK: the X25519 key-agreement pair via the was-client epoch
24
+ * construction (its did:key is the key id, its raw secret is what wraps), plus
25
+ * a random 32-byte Ed25519 signing seed -- a minted PUK is always a complete
26
+ * identity (only a rotation-adopted one lacks the signing half).
27
+ *
28
+ * @returns {Promise<Required<Puk>>}
29
+ */
30
+ export async function mintPuk() {
31
+ const { epochId, secret } = await mintEpoch();
32
+ const signingSeed = new Uint8Array(32);
33
+ crypto.getRandomValues(signingSeed);
34
+ return { id: epochId, secret, signingSeed };
35
+ }
36
+ /**
37
+ * Reconstructs the PUK's key-agreement key and its single-key resolver from
38
+ * the stored material -- the vault-key pair a session supplies to the storage
39
+ * layer, making the PUK recipient zero of every encrypted collection. The key
40
+ * id is the self-describing `<did:key>#<fingerprint>` form, so grantee-side
41
+ * did:key recipient resolution routes it like any other roster entry.
42
+ *
43
+ * @param options {object}
44
+ * @param options.puk {Puk}
45
+ * @returns {{ keyAgreementKey: IKeyAgreementKey, keyResolver: IKeyResolver }}
46
+ */
47
+ export function pukVaultKeys({ puk }) {
48
+ const keyAgreementKey = X25519KeyAgreementKey2020.fromRawSecret({
49
+ secret: puk.secret,
50
+ controller: puk.id,
51
+ id: epochKeyIdFor(puk.id)
52
+ });
53
+ const keyResolver = singleKeyResolver({ keyAgreementKey });
54
+ return { keyAgreementKey, keyResolver };
55
+ }
56
+ //# sourceMappingURL=puk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puk.js","sourceRoot":"","sources":["../../src/keys/puk.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAK7E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAiB9D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,EAAE,CAAA;IAC7C,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;IACnC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AAC7C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,GAAG,EAAgB;IAIhD,MAAM,eAAe,GAAG,yBAAyB,CAAC,aAAa,CAAC;QAC9D,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,UAAU,EAAE,GAAG,CAAC,EAAE;QAClB,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;KAC1B,CAAqB,CAAA;IACtB,MAAM,WAAW,GAAG,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IAC1D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,CAAA;AACzC,CAAC"}