@interop/was-client 0.50.0 → 0.52.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 (83) hide show
  1. package/README.md +59 -7
  2. package/dist/Collection.d.ts +66 -0
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +161 -53
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.js +2 -2
  7. package/dist/Resource.js.map +1 -1
  8. package/dist/Space.d.ts.map +1 -1
  9. package/dist/Space.js +15 -11
  10. package/dist/Space.js.map +1 -1
  11. package/dist/codec.d.ts +54 -12
  12. package/dist/codec.d.ts.map +1 -1
  13. package/dist/edv/EdvCodec.d.ts +9 -8
  14. package/dist/edv/EdvCodec.d.ts.map +1 -1
  15. package/dist/edv/EdvCodec.js +65 -33
  16. package/dist/edv/EdvCodec.js.map +1 -1
  17. package/dist/edv/descriptorStore.d.ts.map +1 -1
  18. package/dist/edv/descriptorStore.js +2 -0
  19. package/dist/edv/descriptorStore.js.map +1 -1
  20. package/dist/edv/docCipher.d.ts.map +1 -1
  21. package/dist/edv/docCipher.js +1 -1
  22. package/dist/edv/docCipher.js.map +1 -1
  23. package/dist/edv/index.d.ts +2 -0
  24. package/dist/edv/index.d.ts.map +1 -1
  25. package/dist/edv/index.js +1 -0
  26. package/dist/edv/index.js.map +1 -1
  27. package/dist/edv/logGovernedDescriptorStore.d.ts +164 -0
  28. package/dist/edv/logGovernedDescriptorStore.d.ts.map +1 -0
  29. package/dist/edv/logGovernedDescriptorStore.js +476 -0
  30. package/dist/edv/logGovernedDescriptorStore.js.map +1 -0
  31. package/dist/edv/recipients.d.ts.map +1 -1
  32. package/dist/edv/recipients.js +25 -82
  33. package/dist/edv/recipients.js.map +1 -1
  34. package/dist/errors.d.ts.map +1 -1
  35. package/dist/errors.js +1 -0
  36. package/dist/errors.js.map +1 -1
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/internal/cas.d.ts +95 -0
  40. package/dist/internal/cas.d.ts.map +1 -0
  41. package/dist/internal/cas.js +116 -0
  42. package/dist/internal/cas.js.map +1 -0
  43. package/dist/internal/codec.d.ts.map +1 -1
  44. package/dist/internal/codec.js +6 -6
  45. package/dist/internal/codec.js.map +1 -1
  46. package/dist/internal/conditional.d.ts +12 -0
  47. package/dist/internal/conditional.d.ts.map +1 -1
  48. package/dist/internal/conditional.js +17 -0
  49. package/dist/internal/conditional.js.map +1 -1
  50. package/dist/internal/content.d.ts +8 -0
  51. package/dist/internal/content.d.ts.map +1 -1
  52. package/dist/internal/content.js +8 -0
  53. package/dist/internal/content.js.map +1 -1
  54. package/dist/internal/meta.d.ts +9 -9
  55. package/dist/internal/meta.d.ts.map +1 -1
  56. package/dist/internal/meta.js +13 -14
  57. package/dist/internal/meta.js.map +1 -1
  58. package/dist/internal/paths.d.ts +6 -0
  59. package/dist/internal/paths.d.ts.map +1 -1
  60. package/dist/internal/paths.js +8 -0
  61. package/dist/internal/paths.js.map +1 -1
  62. package/dist/internal/write.d.ts +1 -1
  63. package/dist/internal/write.d.ts.map +1 -1
  64. package/dist/internal/write.js +4 -2
  65. package/dist/internal/write.js.map +1 -1
  66. package/dist/log/index.d.ts +2 -1
  67. package/dist/log/index.d.ts.map +1 -1
  68. package/dist/log/index.js +2 -1
  69. package/dist/log/index.js.map +1 -1
  70. package/dist/log/logStore.d.ts +38 -25
  71. package/dist/log/logStore.d.ts.map +1 -1
  72. package/dist/log/logStore.js +99 -42
  73. package/dist/log/logStore.js.map +1 -1
  74. package/dist/paths.d.ts +1 -1
  75. package/dist/paths.d.ts.map +1 -1
  76. package/dist/paths.js +1 -1
  77. package/dist/paths.js.map +1 -1
  78. package/dist/sync/provisioning.d.ts.map +1 -1
  79. package/dist/sync/provisioning.js +49 -14
  80. package/dist/sync/provisioning.js.map +1 -1
  81. package/dist/types.d.ts +11 -12
  82. package/dist/types.d.ts.map +1 -1
  83. package/package.json +1 -1
@@ -0,0 +1,476 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The log-governed case of the descriptor-store seam. Two stores:
6
+ *
7
+ * - `logGovernedDescriptorStore` is the generic one, over any
8
+ * `ResourceLogStore` (a Resource-hosted key roster, a Collection's history
9
+ * log): reads resolve to the log's VERIFIED head state -- chain, proofs,
10
+ * external authorization against a caller-supplied controller view, and the
11
+ * chain-head pin all checked by `@interop/vh-resource-log` before any
12
+ * descriptor is handed out -- and writes become signed appends (verified-head
13
+ * build, the library's pre-write pass, compare-and-swap, read-back and pin).
14
+ * It also carries the sealing sweep, the idempotent backstop append that
15
+ * advances a log's head past the controller's latest membership change.
16
+ * - `logGovernedCollectionDescriptorStore` is the pointer-following one, over a
17
+ * Collection whose served `encryption` member is a point-state projection of
18
+ * its governing history log, named by the projection's `history` member. It
19
+ * dispatches on that member, and for a governed Collection reads through the
20
+ * generic store and then holds the served projection to the verified head:
21
+ * a projection that does not JCS-equal the head's state after stripping
22
+ * `history` is refused.
23
+ *
24
+ * The generic read boundary (`readGovernedEpochConfiguration`) and the
25
+ * `WasEpochConfiguration` state shape are shared with the wallet's user key
26
+ * roster, which wraps the generic store. What stays outside this module is
27
+ * DID-method resolution: the controller port and the pin store are injected by
28
+ * the caller.
29
+ */
30
+ import { canonicalize } from 'json-canonicalize';
31
+ import { RESOURCE_LOG_METHOD } from '@interop/storage-core';
32
+ import { buildResourceLogEntry, confirmAppend, createResourceLog, isResourceLogConflictError, readResourceLog, ResourceLogClosedError, ResourceLogIntegrityError, sealResourceLog, verifyResourceLog, verifyResourceLogAppend } from '@interop/vh-resource-log';
33
+ import { PreconditionFailedError, ValidationError } from '../errors.js';
34
+ import { unreadableDescriptionError } from '../internal/describe.js';
35
+ import { resourceLogStore } from '../log/logStore.js';
36
+ /**
37
+ * The state-document schema identifier an encryption descriptor carries in a
38
+ * governed log entry, per the Encrypted Collections profile.
39
+ */
40
+ export const EPOCH_CONFIGURATION_STATE_TYPE = 'WasEpochConfiguration';
41
+ /**
42
+ * The log-entry `state` for a descriptor: the point-state projection's
43
+ * `history` member stripped (it belongs to the projection only; the verifier
44
+ * refuses an entry whose state carries it) and the schema identifier stamped.
45
+ *
46
+ * @param descriptor {CollectionEncryption}
47
+ * @returns {CollectionEncryption & { type: string }}
48
+ */
49
+ export function toEpochConfigurationState(descriptor) {
50
+ const { history: _history, ...rest } = descriptor;
51
+ return { ...rest, type: EPOCH_CONFIGURATION_STATE_TYPE };
52
+ }
53
+ /**
54
+ * The one governed epoch-configuration read: the fail-closed boundary that
55
+ * decides whether a served log state may be treated as an encryption
56
+ * descriptor. Resolves the controller view, reads and fully verifies the log
57
+ * (chain, proofs, external authorization, and the chain-head pin, via
58
+ * `readResourceLog`), and refuses a verified head whose state is not a
59
+ * `WasEpochConfiguration` rather than handing it out as a descriptor.
60
+ * Resolves `null` for an absent log (the pre-genesis state) only while no pin
61
+ * is held for it; under a held pin an absent log is refused as a `rollback`,
62
+ * the library's rule. Every trusted descriptor read goes through this helper,
63
+ * so a hardening applied here reaches all of them.
64
+ *
65
+ * @param options {object}
66
+ * @param options.store {ResourceLogStore} the log's transport seam
67
+ * @param options.resolveController {function}
68
+ * `() => Promise<ResourceLogController>` -- the caller's currently verified
69
+ * controller view, resolved per operation
70
+ * @param options.pinStore {ResourceLogPinStore} this client's chain-head
71
+ * pin for this log
72
+ * @param options.logId {string} the pin-slot key for this log, from
73
+ * `resourceLogPinId`
74
+ * @returns {Promise<{ verified: VerifiedResourceLog; descriptor: CollectionEncryption; controller: ResourceLogController; etag?: string } | null>}
75
+ * the verified log, its head state as the descriptor, the controller view
76
+ * it was verified under, and the log's validator
77
+ */
78
+ export async function readGovernedEpochConfiguration({ store, resolveController, pinStore, logId }) {
79
+ const controller = await resolveController();
80
+ const current = await readResourceLog({
81
+ store,
82
+ controller,
83
+ expectedMethod: RESOURCE_LOG_METHOD,
84
+ pinStore,
85
+ logId
86
+ });
87
+ if (current === null) {
88
+ return null;
89
+ }
90
+ const state = current.verified.state;
91
+ if (state.type !== EPOCH_CONFIGURATION_STATE_TYPE) {
92
+ throw new ResourceLogIntegrityError(`The governed descriptor log carries state of type ` +
93
+ `"${state.type}", not "${EPOCH_CONFIGURATION_STATE_TYPE}".`);
94
+ }
95
+ return {
96
+ verified: current.verified,
97
+ descriptor: state,
98
+ controller,
99
+ etag: current.etag
100
+ };
101
+ }
102
+ /**
103
+ * Translates the log-store port's CAS conflict (the library's
104
+ * `ResourceLogConflictError`, matched by `name` -- it is minted in the store
105
+ * adapter's package, which may resolve its own library copy) into the
106
+ * `PreconditionFailedError` the `EncryptionDescriptorStore` port documents
107
+ * and the edv recipient loops rebase on. Any other error -- an untranslated
108
+ * `PreconditionFailedError` included -- returns unchanged.
109
+ *
110
+ * @param err {unknown}
111
+ * @returns {unknown} the error to rethrow
112
+ */
113
+ function asDescriptorStoreConflict(err) {
114
+ if (isResourceLogConflictError(err)) {
115
+ return new PreconditionFailedError(err.message, {
116
+ status: 412,
117
+ cause: err
118
+ });
119
+ }
120
+ return err;
121
+ }
122
+ /**
123
+ * Builds the generic log-governed `EncryptionDescriptorStore` over a resource
124
+ * log's transport seam. Because the seam is the same one the edv recipient
125
+ * primitives (`initRecipients` / `addRecipient` / `removeRecipient`, with
126
+ * their compare-and-swap retry loops) already drive, they run over a log
127
+ * without knowing it: a lost race on the log is translated back to the
128
+ * `PreconditionFailedError` those loops rebase on.
129
+ *
130
+ * The controller view is resolved per operation rather than held, so a
131
+ * caller that just edited its controller document hands every subsequent
132
+ * write the view it now verifies. A replace builds its entry on the head the most
133
+ * recent read on this instance verified, pinned to that read's `etag`, so a
134
+ * stale head loses the compare-and-swap instead of forking; the library's
135
+ * pre-write pass verifies the candidate as a reader would before it lands,
136
+ * so a refused entry never poisons the served log for other readers.
137
+ *
138
+ * @param options {object}
139
+ * @param options.log {ResourceLogStore} the log's transport seam
140
+ * @param options.resolveController {function}
141
+ * `() => Promise<ResourceLogController>` -- the caller's currently verified
142
+ * controller view, resolved per operation
143
+ * @param options.pinStore {ResourceLogPinStore} this client's chain-head pin
144
+ * for this log
145
+ * @param options.logId {string} the pin-slot key for this log, from
146
+ * `resourceLogPinId`
147
+ * @param [options.signer] {ResourceLogSigner} this client's enrolled
148
+ * signing key, for the appends this store writes; absent, the store is
149
+ * read-only
150
+ * @returns {LogGovernedDescriptorStore}
151
+ */
152
+ export function logGovernedDescriptorStore({ log, resolveController, pinStore, logId, signer }) {
153
+ // The verified log observed by the most recent read or confirmed append on
154
+ // this store instance, and the controller view it was verified under: the
155
+ // library's pre-write pass reads the head's controller version as an index
156
+ // into THAT view's version list, so a replace may only run it against a
157
+ // view this one is a prefix of.
158
+ let lastVerified = null;
159
+ let lastVerifiedView = null;
160
+ function requireSigner(operation) {
161
+ if (signer === undefined) {
162
+ throw new ValidationError(`Cannot ${operation} the governed descriptor: this store was built ` +
163
+ 'without a signer, so it is read-only.');
164
+ }
165
+ return signer;
166
+ }
167
+ async function settle({ entry, controller }) {
168
+ const readBack = await confirmAppend({ store: log, entry });
169
+ const confirmed = await verifyResourceLog({
170
+ entries: readBack.entries,
171
+ controller,
172
+ expectedMethod: RESOURCE_LOG_METHOD,
173
+ pin: await pinStore.read({ logId })
174
+ });
175
+ await pinStore.write({ logId, pin: confirmed.pin });
176
+ lastVerified = confirmed;
177
+ lastVerifiedView = controller;
178
+ }
179
+ const store = {
180
+ async read() {
181
+ const current = await readGovernedEpochConfiguration({
182
+ store: log,
183
+ resolveController,
184
+ pinStore,
185
+ logId
186
+ });
187
+ if (current === null) {
188
+ lastVerified = null;
189
+ lastVerifiedView = null;
190
+ return null;
191
+ }
192
+ lastVerified = current.verified;
193
+ lastVerifiedView = current.controller;
194
+ return {
195
+ descriptor: current.descriptor,
196
+ verified: current.verified,
197
+ etag: current.etag
198
+ };
199
+ },
200
+ async replace(descriptor, { ifMatch }) {
201
+ const logSigner = requireSigner('replace');
202
+ if (ifMatch === undefined) {
203
+ throw new ValidationError('Cannot replace the governed descriptor: the backend returned no ' +
204
+ 'validator, and the profile forbids an unconditional write.');
205
+ }
206
+ /**
207
+ * An append builds on the head this instance last verified. A replace
208
+ * that no read on this instance precedes (a caller seeding the
209
+ * compare-and-swap from a read another instance made) acquires that
210
+ * head now. The caller's validator still guards the append, so a seed
211
+ * behind the served log loses the compare-and-swap as it would anywhere.
212
+ */
213
+ if (lastVerified === null) {
214
+ await store.read();
215
+ }
216
+ if (lastVerified === null) {
217
+ throw new ValidationError('Cannot replace the governed descriptor: the log is absent.');
218
+ }
219
+ if (lastVerified.terminal) {
220
+ throw new ResourceLogClosedError({ nextLog: lastVerified.terminal });
221
+ }
222
+ const controller = await resolveController();
223
+ /**
224
+ * The pre-write pass's precondition, enforced rather than assumed: the
225
+ * view that verified `lastVerified` must be a prefix of this one (the
226
+ * controller log is append-only, so carrying its head version is
227
+ * enough). A resolver that regressed is reported as the port's conflict
228
+ * class, so the edv machinery re-reads under the current view and
229
+ * rebases instead of the pass refusing on a bound that indexes another
230
+ * list.
231
+ */
232
+ const verifiedHead = lastVerifiedView?.versionIds[lastVerifiedView.versionIds.length - 1];
233
+ if (verifiedHead !== undefined &&
234
+ !controller.versionIds.includes(verifiedHead)) {
235
+ throw new PreconditionFailedError('Cannot replace the governed descriptor: the controller view ' +
236
+ `resolved for this write does not carry version "${verifiedHead}", ` +
237
+ 'which the preceding read verified against; re-read and retry.', { status: 412 });
238
+ }
239
+ const entry = await buildResourceLogEntry({
240
+ head: lastVerified.head,
241
+ state: toEpochConfigurationState(descriptor),
242
+ controller,
243
+ signer: logSigner
244
+ });
245
+ await verifyResourceLogAppend({ entry, controller, head: lastVerified });
246
+ try {
247
+ await log.append(entry, { ifMatch });
248
+ }
249
+ catch (err) {
250
+ throw asDescriptorStoreConflict(err);
251
+ }
252
+ await settle({ entry, controller });
253
+ },
254
+ async seal() {
255
+ const logSigner = requireSigner('seal');
256
+ const controller = await resolveController();
257
+ /**
258
+ * Reuse the log view the most recent read or confirmed append on this
259
+ * store instance verified: a rotation that just appended carries a
260
+ * version past the removal, so the sweep resolves noop with no
261
+ * re-fetch, and a stale view is safe (sealResourceLog's append path
262
+ * re-reads before writing).
263
+ */
264
+ const { sealed, verified } = await sealResourceLog({
265
+ store: log,
266
+ controller,
267
+ expectedMethod: RESOURCE_LOG_METHOD,
268
+ pinStore,
269
+ logId,
270
+ signer: logSigner,
271
+ ...(lastVerified === null ? {} : { verified: lastVerified })
272
+ });
273
+ // The sweep hands back the caller's own view untouched when it had
274
+ // nothing to write; only a log it read or appended was verified under
275
+ // this call's controller view.
276
+ if (verified !== null && verified !== lastVerified) {
277
+ lastVerified = verified;
278
+ lastVerifiedView = controller;
279
+ }
280
+ return sealed ? 'sealed' : 'noop';
281
+ }
282
+ };
283
+ if (signer !== undefined) {
284
+ const logSigner = signer;
285
+ store.create = async (descriptor) => {
286
+ /**
287
+ * The library's guarded create: under a held pin it adopts the pinned
288
+ * slot's served log (refusing an absent one as a rollback) and builds
289
+ * nothing; otherwise it verifies the built genesis pre-write, creates it
290
+ * guarded, and confirms by read-back and pin. Either way of losing the
291
+ * race (a refused genesis against a log that already exists, or a lost
292
+ * guarded create) adopts the winner's log, and is reported as the
293
+ * port's conflict class so the edv machinery re-reads and adopts the
294
+ * winner's descriptor.
295
+ */
296
+ const controller = await resolveController();
297
+ const { verified, created } = await createResourceLog({
298
+ store: log,
299
+ controller,
300
+ method: RESOURCE_LOG_METHOD,
301
+ pinStore,
302
+ logId,
303
+ signer: logSigner,
304
+ state: toEpochConfigurationState(descriptor)
305
+ });
306
+ lastVerified = verified;
307
+ lastVerifiedView = controller;
308
+ if (!created) {
309
+ throw new PreconditionFailedError('The resource log create lost its guarded-create race: a log is ' +
310
+ 'already served; re-read and adopt it.', { status: 412 });
311
+ }
312
+ };
313
+ }
314
+ return store;
315
+ }
316
+ /**
317
+ * Builds the `EncryptionDescriptorStore` over a Collection that may be
318
+ * log-governed. `read()` fetches the Collection Description and dispatches on
319
+ * its `encryption` member: absent, the store resolves `null` (a fresh
320
+ * Collection that `create` makes log-governed with a genesis entry); present
321
+ * without `history`, it is the plain point-state descriptor and the store
322
+ * behaves exactly like `collectionDescriptorStore`; present with `history`,
323
+ * the store refuses a `history.method` other than the profile's format
324
+ * identifier before any fetch, refuses a `history.resource` that is not this
325
+ * Collection's own log URL, opens the log through `resourceLogStore`, reads
326
+ * it through the generic {@link logGovernedDescriptorStore}, and holds the
327
+ * projection to the verified head's state after stripping `history`. The
328
+ * Description and the log are two reads, so a projection that equals an
329
+ * EARLIER entry's state is a concurrent append landing between them and is
330
+ * reported as `PreconditionFailedError` (412), which the recipient loops
331
+ * rebase on; a projection matching no entry at all is refused as
332
+ * `ResourceLogIntegrityError`. The descriptor handed out is the verified head
333
+ * state with the served `history` pointer kept on it.
334
+ *
335
+ * Writes on a governed Collection are the generic store's signed appends and
336
+ * need `signer`; without one the store is read-only for governed collections
337
+ * (`replace` and `seal` refuse, `create` is absent). A lost race surfaces as
338
+ * `PreconditionFailedError` (412), the port's documented class. `seal()` is
339
+ * the generic store's sealing sweep over the Collection's log.
340
+ *
341
+ * @param options {object}
342
+ * @param options.collection {Collection}
343
+ * @param options.resolveController {function}
344
+ * `() => Promise<ResourceLogController>` -- the caller's currently verified
345
+ * controller view, resolved per operation
346
+ * @param options.pinStore {ResourceLogPinStore} this client's chain-head pin
347
+ * for this log
348
+ * @param options.logId {string} the pin-slot key for this log, from
349
+ * `resourceLogPinId`
350
+ * @param [options.signer] {ResourceLogSigner} this client's enrolled
351
+ * signing key, for the appends this store writes
352
+ * @returns {LogGovernedDescriptorStore}
353
+ */
354
+ export function logGovernedCollectionDescriptorStore({ collection, resolveController, pinStore, logId, signer }) {
355
+ const governed = logGovernedDescriptorStore({
356
+ log: resourceLogStore({ collection }),
357
+ resolveController,
358
+ pinStore,
359
+ logId,
360
+ signer
361
+ });
362
+ /**
363
+ * The description observed by the most recent read: its sibling fields are
364
+ * forwarded by a point-state replace (the server's replace semantics would
365
+ * otherwise drop them), and its `encryption` member decides which write path
366
+ * a replace takes. Safe to carry even if stale: every write is pinned to the
367
+ * same read's validator, so a concurrent change fails the CAS instead. A
368
+ * create clears it, since the Collection it described is now log-governed.
369
+ */
370
+ let described;
371
+ async function readGoverned(projection) {
372
+ const { history, ...pointState } = projection;
373
+ if (history.method !== RESOURCE_LOG_METHOD) {
374
+ throw new ResourceLogIntegrityError(`The descriptor's history names the format "${history.method}", ` +
375
+ `not "${RESOURCE_LOG_METHOD}".`);
376
+ }
377
+ if (!sameUrl(history.resource, collection.historyLogUrl)) {
378
+ throw new ResourceLogIntegrityError(`The descriptor's history names the log "${history.resource}", ` +
379
+ `not this Collection's own log "${collection.historyLogUrl}".`);
380
+ }
381
+ const current = await governed.read();
382
+ if (current === null) {
383
+ throw new ResourceLogIntegrityError('The descriptor names a governing log, but the Collection serves none.');
384
+ }
385
+ // The generic store's descriptor IS the verified head's state.
386
+ const served = canonicalize(pointState);
387
+ if (served !== canonicalize(current.descriptor)) {
388
+ /**
389
+ * The Description was read before the log. A projection that equals an
390
+ * earlier entry's state is the head the server derived it from before a
391
+ * concurrent append moved the log on: a lost race, not a forgery, so
392
+ * the port's conflict class lets the caller re-read and rebase.
393
+ */
394
+ const entries = current.verified?.entries ?? [];
395
+ const stale = entries
396
+ .slice(0, -1)
397
+ .some(entry => canonicalize(entry.state) === served);
398
+ if (stale) {
399
+ throw new PreconditionFailedError('The served descriptor is behind the verified head of its ' +
400
+ 'governing log (a concurrent append landed); re-read and retry.', { status: 412 });
401
+ }
402
+ throw new ResourceLogIntegrityError('The served descriptor does not match the verified head of its ' +
403
+ 'governing log.');
404
+ }
405
+ return {
406
+ descriptor: { ...current.descriptor, history },
407
+ etag: current.etag
408
+ };
409
+ }
410
+ const store = {
411
+ async read() {
412
+ const current = await collection.describeWithEtag();
413
+ if (current === null) {
414
+ throw unreadableDescriptionError({
415
+ operation: 'manage recipients',
416
+ advice: 'Use a capability that can read the Collection Description.'
417
+ });
418
+ }
419
+ described = current.description;
420
+ const descriptor = current.description.encryption;
421
+ if (!descriptor) {
422
+ return null;
423
+ }
424
+ if (descriptor.scheme !== 'edv') {
425
+ throw new ValidationError('Cannot manage recipients: this collection is not declared ' +
426
+ "encrypted with the 'edv' scheme.");
427
+ }
428
+ if (descriptor.history === undefined) {
429
+ return { descriptor, etag: current.etag };
430
+ }
431
+ return readGoverned(descriptor);
432
+ },
433
+ async replace(descriptor, { ifMatch }) {
434
+ if (described === undefined) {
435
+ await store.read();
436
+ }
437
+ if (described?.encryption?.history !== undefined) {
438
+ await governed.replace(descriptor, { ifMatch });
439
+ return;
440
+ }
441
+ await collection.replaceDescription({
442
+ name: described?.name,
443
+ backend: described?.backend,
444
+ generator: described?.generator,
445
+ generatorOrigin: described?.generatorOrigin,
446
+ encryption: descriptor
447
+ }, { ifMatch });
448
+ },
449
+ seal: () => governed.seal()
450
+ };
451
+ if (governed.create !== undefined) {
452
+ const create = governed.create;
453
+ store.create = async (descriptor) => {
454
+ await create(descriptor);
455
+ described = undefined;
456
+ };
457
+ }
458
+ return store;
459
+ }
460
+ /**
461
+ * Whether two absolute URLs name the same resource, compared normalized (so
462
+ * a differently cased host or a default port does not read as a mismatch).
463
+ *
464
+ * @param left {string}
465
+ * @param right {string}
466
+ * @returns {boolean}
467
+ */
468
+ function sameUrl(left, right) {
469
+ try {
470
+ return new URL(left).href === new URL(right).href;
471
+ }
472
+ catch {
473
+ return false;
474
+ }
475
+ }
476
+ //# sourceMappingURL=logGovernedDescriptorStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logGovernedDescriptorStore.js","sourceRoot":"","sources":["../../src/edv/logGovernedDescriptorStore.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../src/edv/recipients.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAQxC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,KAAK,EACV,oBAAoB,EAIpB,cAAc,EACf,MAAM,aAAa,CAAA;AASpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAG1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAuW1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,KAAK,EACL,UAAU,EACV,YAAoB,EACrB,EAAE;IACD,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,UAAU,EAAE,kBAAkB,EAAE,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CA8CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,KAAK,EACL,UAAU,EACV,KAAK,EAAE,cAAc,EACtB,EAAE;IACD,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,UAAU,EAAE,kBAAkB,EAAE,CAAA;IAChC,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAA;CAChD,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuChC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,YAAY,CAAC,EACjC,UAAU,EACV,KAAK,EACL,SAAS,EACT,KAAK,EACN,EAAE;IACD,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,KAAK,EAAE;QAAE,eAAe,EAAE,gBAAgB,CAAA;KAAE,CAAA;CAC7C,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAmChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,wBAAsB,eAAe,CAAC,EACpC,UAAU,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,MAAM,EACN,IAAI,EACJ,mBAAgD,EACjD,EAAE;IACD,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC9B,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAA;IAC1C,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;CAC1E,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAoBhC;AA+KD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,KAAK,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,MAAM,EACN,IAAI,EACJ,mBAAgD,EACjD,EAAE;IACD,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,SAAS,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,CAAA;IACpD,KAAK,EAAE;QAAE,eAAe,EAAE,gBAAgB,CAAA;KAAE,CAAA;IAC5C,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAA;IAC1C,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;CAC1E,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA8BhC"}
1
+ {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../src/edv/recipients.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,10 @@
1
1
  import { EDV_SCHEME_VERSION } from './constants.js';
2
- import { EncryptionError, PreconditionFailedError, ValidationError } from '../errors.js';
2
+ import { EncryptionError, ValidationError } from '../errors.js';
3
+ import { compareAndSwap } from '../internal/cas.js';
3
4
  import { collectionDescriptorStore } from './descriptorStore.js';
4
5
  import { didKeyResolver, mintEpoch, unwrapEpochSecret, wrapEpochSecret, wrapEpochSecretTo } from './epochCrypto.js';
5
6
  import { pickEpoch } from './epochRoster.js';
6
7
  import { mintHmacKey } from './hmacKey.js';
7
- /**
8
- * How many times a recipient CAS write retries a stale (`412`) description
9
- * before surfacing {@link PreconditionFailedError}.
10
- */
11
- const MAX_CAS_ATTEMPTS = 3;
12
8
  /**
13
9
  * Escrows one or more readers into a single wrap roster (one epoch's
14
10
  * `recipients`, or the blinded-index key's): the caller unwraps its OWN entry
@@ -857,38 +853,13 @@ function descriptorStoreFor({ collection, store }) {
857
853
  throw new ValidationError('A recipient operation needs its descriptor host: pass `collection` or ' +
858
854
  '`store`.');
859
855
  }
860
- /**
861
- * Whether `err` is the compare-and-swap conflict a descriptor store raises
862
- * (`PreconditionFailedError`, 412). Matched by `name` as well as `instanceof`:
863
- * a store implemented by a consumer (wallet-core's log-governed store) mints
864
- * the conflict from its own `@interop/was-client` import, and in a tree that
865
- * resolves was-client twice that class is a different object from ours, so an
866
- * `instanceof`-only check would turn every lost race into a hard failure
867
- * instead of a rebase.
868
- *
869
- * @param err {unknown}
870
- * @returns {boolean}
871
- */
872
- function isPreconditionFailed(err) {
873
- return (err instanceof PreconditionFailedError ||
874
- (err instanceof Error && err.name === 'PreconditionFailedError'));
875
- }
876
856
  /**
877
857
  * Reads the store's descriptor, applies `mutate`, and writes the result back
878
- * with a compare-and-swap (`If-Match`). Retries on a stale (`412`) validator,
879
- * re-reading the fresh descriptor each time, up to {@link MAX_CAS_ATTEMPTS};
880
- * surfaces {@link PreconditionFailedError} if it keeps losing the race. A
881
- * `mutate` that resolves `null` signals "no change needed" (the descriptor
882
- * already reflects the desired state, e.g. an idempotent retry): nothing is
883
- * written and the current descriptor is returned as-is.
884
- *
885
- * When the store reports no descriptor yet (`read()` resolves `null`, e.g. the
886
- * resource adapter before the first `initRecipients`), the optional `seed` is
887
- * mutated instead and the result written with the store's create-if-absent
888
- * guard (`If-None-Match: *`). Only `initRecipients` passes a seed; without
889
- * one an absent descriptor is refused. Losing the create race (a concurrent
890
- * writer created the first descriptor) re-enters the loop and re-reads, like a
891
- * stale CAS.
858
+ * with a compare-and-swap: the shared {@link compareAndSwap} loop over an
859
+ * `EncryptionDescriptorStore`, with the recipient-specific handling of a store
860
+ * that holds no descriptor yet. Only `initRecipients` passes a `seed` (mutated
861
+ * in place of the absent descriptor and written create-if-absent); without one
862
+ * an absent descriptor is refused.
892
863
  *
893
864
  * @param options {object}
894
865
  * @param options.store {EncryptionDescriptorStore}
@@ -899,56 +870,28 @@ function isPreconditionFailed(err) {
899
870
  * @returns {Promise<CollectionEncryption>} the written (or current) descriptor
900
871
  */
901
872
  async function casUpdateDescriptor({ store, mutate, seed }) {
902
- let lastError;
903
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
904
- const current = await store.read();
905
- if (current === null) {
873
+ return compareAndSwap({
874
+ store: {
875
+ async read() {
876
+ const current = await store.read();
877
+ return current === null
878
+ ? null
879
+ : { value: current.descriptor, etag: current.etag };
880
+ },
881
+ replace: (descriptor, options) => store.replace(descriptor, options),
882
+ ...(store.create !== undefined && {
883
+ create: (descriptor) => store.create(descriptor)
884
+ })
885
+ },
886
+ mutate,
887
+ operation: 'Recipient change',
888
+ onAbsent: () => {
906
889
  if (seed === undefined) {
907
890
  throw new ValidationError('Cannot manage recipients: this descriptor store holds no encryption ' +
908
891
  'descriptor yet. Call initRecipients first.');
909
892
  }
910
- if (store.create === undefined) {
911
- throw new ValidationError('Cannot initialize recipients: this descriptor store holds no descriptor ' +
912
- 'and does not support creating one.');
913
- }
914
- const created = await mutate(seed);
915
- if (created === null) {
916
- return seed;
917
- }
918
- try {
919
- await store.create(created);
920
- return created;
921
- }
922
- catch (err) {
923
- if (isPreconditionFailed(err)) {
924
- // A concurrent writer created the first descriptor: re-read and
925
- // re-apply.
926
- lastError = err;
927
- continue;
928
- }
929
- throw err;
930
- }
931
- }
932
- const next = await mutate(current.descriptor);
933
- if (next === null) {
934
- // The descriptor already reflects the desired state: nothing to write.
935
- return current.descriptor;
936
- }
937
- try {
938
- await store.replace(next, { ifMatch: current.etag });
939
- return next;
940
- }
941
- catch (err) {
942
- if (isPreconditionFailed(err)) {
943
- // A concurrent recipient change landed first: re-read and re-apply.
944
- lastError = err;
945
- continue;
946
- }
947
- throw err;
893
+ return seed;
948
894
  }
949
- }
950
- throw new PreconditionFailedError(`Recipient change lost the compare-and-swap race after ${MAX_CAS_ATTEMPTS} ` +
951
- 'attempts (another writer kept updating the stored descriptor). ' +
952
- 'Retry the operation.', { cause: lastError });
895
+ });
953
896
  }
954
897
  //# sourceMappingURL=recipients.js.map