@interop/was-client 0.5.0 → 0.7.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 (60) hide show
  1. package/README.md +166 -0
  2. package/dist/Collection.d.ts +28 -3
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +74 -13
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.d.ts +64 -9
  7. package/dist/Resource.d.ts.map +1 -1
  8. package/dist/Resource.js +110 -26
  9. package/dist/Resource.js.map +1 -1
  10. package/dist/Space.d.ts +4 -0
  11. package/dist/Space.d.ts.map +1 -1
  12. package/dist/Space.js +4 -0
  13. package/dist/Space.js.map +1 -1
  14. package/dist/WasClient.d.ts +10 -2
  15. package/dist/WasClient.d.ts.map +1 -1
  16. package/dist/WasClient.js +13 -6
  17. package/dist/WasClient.js.map +1 -1
  18. package/dist/codec.d.ts +127 -0
  19. package/dist/codec.d.ts.map +1 -0
  20. package/dist/codec.js +2 -0
  21. package/dist/codec.js.map +1 -0
  22. package/dist/edv/EdvCodec.d.ts +148 -0
  23. package/dist/edv/EdvCodec.d.ts.map +1 -0
  24. package/dist/edv/EdvCodec.js +284 -0
  25. package/dist/edv/EdvCodec.js.map +1 -0
  26. package/dist/edv/WasTransport.d.ts +178 -0
  27. package/dist/edv/WasTransport.d.ts.map +1 -0
  28. package/dist/edv/WasTransport.js +284 -0
  29. package/dist/edv/WasTransport.js.map +1 -0
  30. package/dist/edv/index.d.ts +21 -0
  31. package/dist/edv/index.d.ts.map +1 -0
  32. package/dist/edv/index.js +21 -0
  33. package/dist/edv/index.js.map +1 -0
  34. package/dist/errors.d.ts +19 -0
  35. package/dist/errors.d.ts.map +1 -1
  36. package/dist/errors.js +29 -1
  37. package/dist/errors.js.map +1 -1
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/internal/codec.d.ts +27 -0
  43. package/dist/internal/codec.d.ts.map +1 -0
  44. package/dist/internal/codec.js +44 -0
  45. package/dist/internal/codec.js.map +1 -0
  46. package/dist/internal/conditional.d.ts +40 -0
  47. package/dist/internal/conditional.d.ts.map +1 -0
  48. package/dist/internal/conditional.js +35 -0
  49. package/dist/internal/conditional.js.map +1 -0
  50. package/dist/internal/content.d.ts +30 -1
  51. package/dist/internal/content.d.ts.map +1 -1
  52. package/dist/internal/content.js +68 -3
  53. package/dist/internal/content.js.map +1 -1
  54. package/dist/internal/request.d.ts +5 -1
  55. package/dist/internal/request.d.ts.map +1 -1
  56. package/dist/internal/request.js +2 -7
  57. package/dist/internal/request.js.map +1 -1
  58. package/dist/types.d.ts +6 -0
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +13 -3
@@ -0,0 +1,148 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The EDV (Encrypted Data Vault) resource codec and its `EncryptionProvider`
6
+ * factory -- the encrypting half of the codec seam. Bound to an
7
+ * encrypted collection, it encrypts a caller's value into an EDV envelope
8
+ * (`{ id, sequence, indexed, jwe }`) on write and decrypts it on read, so
9
+ * `collection.put(id, obj)` / `collection.get(id)` transparently round-trip
10
+ * ciphertext. Keys live in the wallet and are supplied per-collection by the
11
+ * app's `resolveKeys`; they never reach the server, which stores only opaque
12
+ * JWE envelopes.
13
+ *
14
+ * This reuses `EdvClientCore`'s encrypt/decrypt primitives (the same JWE
15
+ * machinery as the standalone `WasTransport`), but here the WAS Resource CRUD --
16
+ * the transport role -- is played by core was-client's `Collection`/`Resource`
17
+ * I/O, so the codec is a pure encode/decode transform and needs no transport of
18
+ * its own.
19
+ *
20
+ * Scope (documents-only):
21
+ *
22
+ * - **Restrict-mode ids.** `add()` mints a 128-bit multibase EDV id; the WAS
23
+ * resource id IS that EDV id. `put(id, ...)` accepts only an EDV-format id --
24
+ * a human-readable id is rejected (it would leak onto the URL). Carry a
25
+ * human-readable label inside the encrypted content instead. (Blind-derived
26
+ * ids are a deferred future item.)
27
+ * - **Small binary as a single JWE.** A `Blob`/`Uint8Array` under the size cap
28
+ * is wrapped and encrypted as one document; an oversized one is rejected
29
+ * (chunked encrypted blobs need the server's `chunked-streams` affordance).
30
+ * - **Enforced sequence (conditional writes).** The codec sets
31
+ * `conditionalWrites`, so the write path pre-reads the current envelope and
32
+ * hands it to `encode`: an update advances `sequence` from its prior value and
33
+ * pins the write to the server's current ETag via `If-Match`, while a fresh
34
+ * insert (`sequence: 0`) is guarded by `If-None-Match: *`. A stale write
35
+ * surfaces as a `PreconditionFailedError` (412) -- the lost-update guard --
36
+ * rather than the old advisory last-writer-wins. Against a backend that does
37
+ * not advertise `conditional-writes` (no ETag) it degrades to advisory.
38
+ * - **No server-visible metadata.** `allowsServerMetadata` is `false`, so
39
+ * `setName`/`setTags` throw on an encrypted collection (the core seam enforces
40
+ * this).
41
+ */
42
+ import { EdvClientCore } from '@interop/edv-client';
43
+ import type { HttpResponse } from '@interop/http-client';
44
+ import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
45
+ import type { EncodedWrite, EncryptionProvider, ResourceCodec } from '../codec.js';
46
+ import type { Json } from '../types.js';
47
+ import { EDV_CONTENT_TYPE } from './WasTransport.js';
48
+ /**
49
+ * A {@link ResourceCodec} that encrypts on write and decrypts on read using an
50
+ * `EdvClientCore`'s JWE primitives. One instance is bound per encrypted
51
+ * collection handle.
52
+ */
53
+ export declare class EdvCodec implements ResourceCodec {
54
+ readonly allowsServerMetadata = false;
55
+ readonly conditionalWrites = true;
56
+ private readonly _edv;
57
+ private readonly _keyAgreementKey;
58
+ private readonly _contentType;
59
+ private readonly _maxBlobBytes;
60
+ /**
61
+ * @param options {object}
62
+ * @param options.edv {EdvClientCore} holds the cipher + key resolver
63
+ * @param options.keyAgreementKey {IKeyAgreementKey} the recipient/decrypt key
64
+ * @param options.contentType {string} stored envelope content type
65
+ * @param options.maxBlobBytes {number} single-document binary cap
66
+ */
67
+ constructor({ edv, keyAgreementKey, contentType, maxBlobBytes }: {
68
+ edv: EdvClientCore;
69
+ keyAgreementKey: IKeyAgreementKey;
70
+ contentType: string;
71
+ maxBlobBytes: number;
72
+ });
73
+ /**
74
+ * @inheritdoc
75
+ */
76
+ encode({ id, data, contentType, current }: {
77
+ id?: string;
78
+ data: Json | Blob | Uint8Array;
79
+ contentType?: string;
80
+ current?: HttpResponse | null;
81
+ }): Promise<EncodedWrite>;
82
+ /**
83
+ * @inheritdoc
84
+ */
85
+ decode(response: {
86
+ data?: unknown;
87
+ json(): Promise<unknown>;
88
+ }): Promise<Json | Blob>;
89
+ /**
90
+ * Resolves a caller value to the EDV document `content`: a JSON object/array
91
+ * passes through; a `Blob`/`Uint8Array` (under the cap) is wrapped as a
92
+ * base64 blob record; a bare primitive is rejected (mirroring the plaintext
93
+ * `prepareBody` contract).
94
+ *
95
+ * @param data {Json | Blob | Uint8Array}
96
+ * @param [contentType] {string}
97
+ * @returns {Promise<object>}
98
+ */
99
+ private _toContent;
100
+ /**
101
+ * Wraps binary bytes as an EDV document content record, enforcing the
102
+ * single-document size cap.
103
+ *
104
+ * @param bytes {Uint8Array}
105
+ * @param contentType {string}
106
+ * @returns {object}
107
+ */
108
+ private _blobContent;
109
+ /**
110
+ * Reconstructs a caller value from decrypted EDV document content: a `Blob`
111
+ * for a wrapped blob record, otherwise the JSON content verbatim.
112
+ *
113
+ * @param content {unknown}
114
+ * @returns {Json | Blob}
115
+ */
116
+ private _fromContent;
117
+ }
118
+ /**
119
+ * Builds an {@link EncryptionProvider} that encrypts the collections the client
120
+ * holds keys for, wiring the per-collection keys (from `resolveKeys`) into an
121
+ * {@link EdvCodec}. Pass the result as `WasClient`'s `encryption` option; core
122
+ * resolves a codec for a collection exactly when `resolveKeys` returns keys for
123
+ * it (the switch is keys alone -- encryption is not a backend feature).
124
+ *
125
+ * @param options {object}
126
+ * @param options.resolveKeys {function} returns the collection's
127
+ * `{ keyAgreementKey, keyResolver }`, or `null` to read/write it as plaintext
128
+ * @param [options.contentType] {string} stored envelope content type;
129
+ * defaults to `application/json`. Pass `EDV_CONTENT_TYPE`
130
+ * (`application/edv+json`) against a server that registers an
131
+ * `application/*+json` parser.
132
+ * @param [options.maxBlobBytes] {number} single-document binary cap (default
133
+ * 1 MiB)
134
+ * @returns {EncryptionProvider}
135
+ */
136
+ export declare function createEdvEncryption({ resolveKeys, contentType, maxBlobBytes }: {
137
+ resolveKeys: (ref: {
138
+ spaceId: string;
139
+ collectionId: string;
140
+ }) => Promise<{
141
+ keyAgreementKey: IKeyAgreementKey;
142
+ keyResolver: IKeyResolver;
143
+ } | null>;
144
+ contentType?: string;
145
+ maxBlobBytes?: number;
146
+ }): EncryptionProvider;
147
+ export { EDV_CONTENT_TYPE };
148
+ //# sourceMappingURL=EdvCodec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EdvCodec.d.ts","sourceRoot":"","sources":["../../src/edv/EdvCodec.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAEV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACd,MAAM,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAsEpD;;;;GAIG;AACH,qBAAa,QAAS,YAAW,aAAa;IAC5C,QAAQ,CAAC,oBAAoB,SAAQ;IACrC,QAAQ,CAAC,iBAAiB,QAAO;IAEjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IAEtC;;;;;;OAMG;gBACS,EACV,GAAG,EACH,eAAe,EACf,WAAW,EACX,YAAY,EACb,EAAE;QACD,GAAG,EAAE,aAAa,CAAA;QAClB,eAAe,EAAE,gBAAgB,CAAA;QACjC,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,EAAE,MAAM,CAAA;KACrB;IAOD;;OAEG;IACG,MAAM,CAAC,EACX,EAAE,EACF,IAAI,EACJ,WAAW,EACX,OAAO,EACR,EAAE;QACD,EAAE,CAAC,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,UAAU,CAAA;QAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;KAC9B,GAAG,OAAO,CAAC,YAAY,CAAC;IA+CzB;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE;QACrB,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;KACzB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAWxB;;;;;;;;;OASG;YACW,UAAU;IAuBxB;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IAYpB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;CAarB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,WAAkC,EAClC,YAAqC,EACtC,EAAE;IACD,WAAW,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QACvE,eAAe,EAAE,gBAAgB,CAAA;QACjC,WAAW,EAAE,YAAY,CAAA;KAC1B,GAAG,IAAI,CAAC,CAAA;IACT,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,kBAAkB,CAmBrB;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
@@ -0,0 +1,284 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The EDV (Encrypted Data Vault) resource codec and its `EncryptionProvider`
6
+ * factory -- the encrypting half of the codec seam. Bound to an
7
+ * encrypted collection, it encrypts a caller's value into an EDV envelope
8
+ * (`{ id, sequence, indexed, jwe }`) on write and decrypts it on read, so
9
+ * `collection.put(id, obj)` / `collection.get(id)` transparently round-trip
10
+ * ciphertext. Keys live in the wallet and are supplied per-collection by the
11
+ * app's `resolveKeys`; they never reach the server, which stores only opaque
12
+ * JWE envelopes.
13
+ *
14
+ * This reuses `EdvClientCore`'s encrypt/decrypt primitives (the same JWE
15
+ * machinery as the standalone `WasTransport`), but here the WAS Resource CRUD --
16
+ * the transport role -- is played by core was-client's `Collection`/`Resource`
17
+ * I/O, so the codec is a pure encode/decode transform and needs no transport of
18
+ * its own.
19
+ *
20
+ * Scope (documents-only):
21
+ *
22
+ * - **Restrict-mode ids.** `add()` mints a 128-bit multibase EDV id; the WAS
23
+ * resource id IS that EDV id. `put(id, ...)` accepts only an EDV-format id --
24
+ * a human-readable id is rejected (it would leak onto the URL). Carry a
25
+ * human-readable label inside the encrypted content instead. (Blind-derived
26
+ * ids are a deferred future item.)
27
+ * - **Small binary as a single JWE.** A `Blob`/`Uint8Array` under the size cap
28
+ * is wrapped and encrypted as one document; an oversized one is rejected
29
+ * (chunked encrypted blobs need the server's `chunked-streams` affordance).
30
+ * - **Enforced sequence (conditional writes).** The codec sets
31
+ * `conditionalWrites`, so the write path pre-reads the current envelope and
32
+ * hands it to `encode`: an update advances `sequence` from its prior value and
33
+ * pins the write to the server's current ETag via `If-Match`, while a fresh
34
+ * insert (`sequence: 0`) is guarded by `If-None-Match: *`. A stale write
35
+ * surfaces as a `PreconditionFailedError` (412) -- the lost-update guard --
36
+ * rather than the old advisory last-writer-wins. Against a backend that does
37
+ * not advertise `conditional-writes` (no ETag) it degrades to advisory.
38
+ * - **No server-visible metadata.** `allowsServerMetadata` is `false`, so
39
+ * `setName`/`setTags` throw on an encrypted collection (the core seam enforces
40
+ * this).
41
+ */
42
+ import { EdvClientCore } from '@interop/edv-client';
43
+ import { ValidationError } from '../errors.js';
44
+ import { readJsonData } from '../internal/content.js';
45
+ import { EDV_CONTENT_TYPE } from './WasTransport.js';
46
+ /**
47
+ * Default ceiling for a single-document (unchunked) encrypted binary write.
48
+ * Past this a `Blob`/`Uint8Array` is rejected until chunked encrypted blobs are
49
+ * supported. 1 MiB before the ~33% base64 inflation.
50
+ */
51
+ const DEFAULT_MAX_BLOB_BYTES = 1024 * 1024;
52
+ /**
53
+ * The default stored content type. Plain JSON keeps the codec portable across
54
+ * any document-capable server (the envelope is still self-identifying by its
55
+ * `jwe` field). Pass `contentType: EDV_CONTENT_TYPE`
56
+ * (`application/edv+json`) against a server that registers an
57
+ * `application/*+json` parser to mark envelopes distinctly in listings.
58
+ */
59
+ const DEFAULT_CONTENT_TYPE = 'application/json';
60
+ /**
61
+ * Marker property tagging an encrypted document whose decrypted content is a
62
+ * binary blob (rather than a JSON value), so `decode` can reconstruct a `Blob`.
63
+ * Namespaced to avoid colliding with caller JSON.
64
+ */
65
+ const BLOB_MARKER = '@interop/was-client:edvBlob';
66
+ /**
67
+ * Heuristic for an EDV document id: multibase base58btc (leading `z`) of a
68
+ * 128-bit value. Used to reject human-readable ids on `put()`. Deliberately a
69
+ * loose, dependency-free check (base58 charset, leading `z`, minimum length) --
70
+ * it rejects ids with human separators (`.`/`-`/`_`/spaces) and is not a full
71
+ * decode-and-length verification.
72
+ */
73
+ const EDV_DOC_ID = /^z[1-9A-HJ-NP-Za-km-z]{21,}$/;
74
+ const ENCODER = new TextEncoder();
75
+ function isBlob(value) {
76
+ return typeof Blob !== 'undefined' && value instanceof Blob;
77
+ }
78
+ /**
79
+ * Encodes bytes to standard base64 using the platform `btoa` (present in modern
80
+ * Node and browsers), via a binary string.
81
+ *
82
+ * @param bytes {Uint8Array}
83
+ * @returns {string}
84
+ */
85
+ function bytesToBase64(bytes) {
86
+ let binary = '';
87
+ for (const byte of bytes) {
88
+ binary += String.fromCharCode(byte);
89
+ }
90
+ return btoa(binary);
91
+ }
92
+ /**
93
+ * Decodes standard base64 to bytes using the platform `atob`.
94
+ *
95
+ * @param base64 {string}
96
+ * @returns {Uint8Array}
97
+ */
98
+ function base64ToBytes(base64) {
99
+ const binary = atob(base64);
100
+ const bytes = new Uint8Array(binary.length);
101
+ for (let index = 0; index < binary.length; index++) {
102
+ bytes[index] = binary.charCodeAt(index);
103
+ }
104
+ return bytes;
105
+ }
106
+ /**
107
+ * A {@link ResourceCodec} that encrypts on write and decrypts on read using an
108
+ * `EdvClientCore`'s JWE primitives. One instance is bound per encrypted
109
+ * collection handle.
110
+ */
111
+ export class EdvCodec {
112
+ allowsServerMetadata = false;
113
+ conditionalWrites = true;
114
+ _edv;
115
+ _keyAgreementKey;
116
+ _contentType;
117
+ _maxBlobBytes;
118
+ /**
119
+ * @param options {object}
120
+ * @param options.edv {EdvClientCore} holds the cipher + key resolver
121
+ * @param options.keyAgreementKey {IKeyAgreementKey} the recipient/decrypt key
122
+ * @param options.contentType {string} stored envelope content type
123
+ * @param options.maxBlobBytes {number} single-document binary cap
124
+ */
125
+ constructor({ edv, keyAgreementKey, contentType, maxBlobBytes }) {
126
+ this._edv = edv;
127
+ this._keyAgreementKey = keyAgreementKey;
128
+ this._contentType = contentType;
129
+ this._maxBlobBytes = maxBlobBytes;
130
+ }
131
+ /**
132
+ * @inheritdoc
133
+ */
134
+ async encode({ id, data, contentType, current }) {
135
+ if (id !== undefined && !EDV_DOC_ID.test(id)) {
136
+ throw new ValidationError(`Cannot write a human-readable id "${id}" to an encrypted collection ` +
137
+ '-- it would leak onto the URL. Use add() to mint an EDV document ' +
138
+ 'id, or carry the human-readable label inside the encrypted content.');
139
+ }
140
+ const docId = id ?? (await this._edv.generateId());
141
+ const content = await this._toContent(data, contentType);
142
+ // When the write path pre-read a current envelope, advance `sequence` from
143
+ // its prior value (`_encrypt({ update: true })` increments it) and pin the
144
+ // write to the server's current ETag with `If-Match`. With no prior envelope
145
+ // this is a fresh insert (`sequence: 0`) guarded by `If-None-Match: *`
146
+ // (create-if-absent), so a concurrent first writer cannot be clobbered.
147
+ const priorDoc = current
148
+ ? (await readJsonData(current))
149
+ : null;
150
+ const recipients = this._edv._createDefaultRecipients(this._keyAgreementKey);
151
+ const encrypted = await this._edv._encrypt({
152
+ doc: {
153
+ id: docId,
154
+ content,
155
+ ...(priorDoc && { sequence: priorDoc.sequence })
156
+ },
157
+ recipients,
158
+ keyResolver: this._edv.keyResolver,
159
+ hmac: undefined,
160
+ update: priorDoc !== null
161
+ });
162
+ return {
163
+ id: docId,
164
+ body: ENCODER.encode(JSON.stringify(encrypted)),
165
+ contentType: this._contentType,
166
+ // Pin an update to the server's current ETag; guard a fresh insert with
167
+ // create-if-absent. (An ETag is absent only against a backend without the
168
+ // conditional-writes feature, where this degrades to an advisory write.)
169
+ ...(priorDoc
170
+ ? { ifMatch: current.headers.get('etag') ?? undefined }
171
+ : { ifNoneMatch: true })
172
+ };
173
+ }
174
+ /**
175
+ * @inheritdoc
176
+ */
177
+ async decode(response) {
178
+ const encryptedDoc = (await readJsonData(response));
179
+ const decrypted = await this._edv._decrypt({
180
+ encryptedDoc,
181
+ keyAgreementKey: this._keyAgreementKey
182
+ });
183
+ return this._fromContent(decrypted.content);
184
+ }
185
+ /**
186
+ * Resolves a caller value to the EDV document `content`: a JSON object/array
187
+ * passes through; a `Blob`/`Uint8Array` (under the cap) is wrapped as a
188
+ * base64 blob record; a bare primitive is rejected (mirroring the plaintext
189
+ * `prepareBody` contract).
190
+ *
191
+ * @param data {Json | Blob | Uint8Array}
192
+ * @param [contentType] {string}
193
+ * @returns {Promise<object>}
194
+ */
195
+ async _toContent(data, contentType) {
196
+ if (isBlob(data)) {
197
+ const bytes = new Uint8Array(await data.arrayBuffer());
198
+ return this._blobContent(bytes, contentType || data.type || 'application/octet-stream');
199
+ }
200
+ if (data instanceof Uint8Array) {
201
+ return this._blobContent(data, contentType || 'application/octet-stream');
202
+ }
203
+ if (data !== null && typeof data === 'object') {
204
+ return data;
205
+ }
206
+ throw new ValidationError('Encrypted resource data must be a plain object/array (JSON) or a ' +
207
+ 'Blob/Uint8Array (binary).');
208
+ }
209
+ /**
210
+ * Wraps binary bytes as an EDV document content record, enforcing the
211
+ * single-document size cap.
212
+ *
213
+ * @param bytes {Uint8Array}
214
+ * @param contentType {string}
215
+ * @returns {object}
216
+ */
217
+ _blobContent(bytes, contentType) {
218
+ if (bytes.length > this._maxBlobBytes) {
219
+ throw new ValidationError(`Encrypted binary write of ${bytes.length} bytes exceeds the ` +
220
+ `single-document limit of ${this._maxBlobBytes} bytes. Chunked ` +
221
+ "encrypted blobs need the server's chunked-streams affordance " +
222
+ '(not yet available).');
223
+ }
224
+ return { [BLOB_MARKER]: true, contentType, base64: bytesToBase64(bytes) };
225
+ }
226
+ /**
227
+ * Reconstructs a caller value from decrypted EDV document content: a `Blob`
228
+ * for a wrapped blob record, otherwise the JSON content verbatim.
229
+ *
230
+ * @param content {unknown}
231
+ * @returns {Json | Blob}
232
+ */
233
+ _fromContent(content) {
234
+ if (content !== null &&
235
+ typeof content === 'object' &&
236
+ content[BLOB_MARKER] === true) {
237
+ const record = content;
238
+ return new Blob([base64ToBytes(record.base64)], {
239
+ type: record.contentType
240
+ });
241
+ }
242
+ return content;
243
+ }
244
+ }
245
+ /**
246
+ * Builds an {@link EncryptionProvider} that encrypts the collections the client
247
+ * holds keys for, wiring the per-collection keys (from `resolveKeys`) into an
248
+ * {@link EdvCodec}. Pass the result as `WasClient`'s `encryption` option; core
249
+ * resolves a codec for a collection exactly when `resolveKeys` returns keys for
250
+ * it (the switch is keys alone -- encryption is not a backend feature).
251
+ *
252
+ * @param options {object}
253
+ * @param options.resolveKeys {function} returns the collection's
254
+ * `{ keyAgreementKey, keyResolver }`, or `null` to read/write it as plaintext
255
+ * @param [options.contentType] {string} stored envelope content type;
256
+ * defaults to `application/json`. Pass `EDV_CONTENT_TYPE`
257
+ * (`application/edv+json`) against a server that registers an
258
+ * `application/*+json` parser.
259
+ * @param [options.maxBlobBytes] {number} single-document binary cap (default
260
+ * 1 MiB)
261
+ * @returns {EncryptionProvider}
262
+ */
263
+ export function createEdvEncryption({ resolveKeys, contentType = DEFAULT_CONTENT_TYPE, maxBlobBytes = DEFAULT_MAX_BLOB_BYTES }) {
264
+ return {
265
+ async resolveCodec({ spaceId, collectionId }) {
266
+ const keys = await resolveKeys({ spaceId, collectionId });
267
+ if (!keys) {
268
+ return null;
269
+ }
270
+ const edv = new EdvClientCore({
271
+ keyAgreementKey: keys.keyAgreementKey,
272
+ keyResolver: keys.keyResolver
273
+ });
274
+ return new EdvCodec({
275
+ edv,
276
+ keyAgreementKey: keys.keyAgreementKey,
277
+ contentType,
278
+ maxBlobBytes
279
+ });
280
+ }
281
+ };
282
+ }
283
+ export { EDV_CONTENT_TYPE };
284
+ //# sourceMappingURL=EdvCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EdvCodec.js","sourceRoot":"","sources":["../../src/edv/EdvCodec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * An `@interop/edv-client` `Transport` that maps Encrypted Data Vault (EDV)
6
+ * document operations onto ordinary WAS Resource CRUD -- the "EDV-over-WAS"
7
+ * layout profile (Layer 1). It is paired with `EdvClientCore`, which does all
8
+ * encryption, decryption, and index blinding client-side; this transport only
9
+ * moves opaque JWE documents to and from a WAS server, reusing the client's
10
+ * zcap-signed request layer (`WasClient.request()`). Keys never reach the
11
+ * server.
12
+ *
13
+ * Profile decisions encoded here:
14
+ *
15
+ * - **Vault per Collection.** The WAS Collection is the EDV vault; each
16
+ * encrypted document is one WAS Resource.
17
+ * - **Restrict-mode ids.** The WAS resource id IS the EDV document id (the
18
+ * 128-bit multibase value `EdvClientCore.generateId()` produces), which is
19
+ * URL-safe and never a reserved segment.
20
+ * - **Encrypted content type.** Documents are stored as `application/json` by
21
+ * default, so the profile works against an unmodified WAS server. The
22
+ * preferred marker is `application/edv+json` (exported as `EDV_CONTENT_TYPE`),
23
+ * which distinguishes EDV envelopes from plaintext application JSON in
24
+ * listings and metadata -- but the server must register an `application/*+json`
25
+ * content-type parser to accept it (the reference was-teaching-server does; a
26
+ * server that does not will reject it with 415). Pass `contentType:
27
+ * EDV_CONTENT_TYPE` to opt into it where the server supports it.
28
+ *
29
+ * Scope: documents only (`insert` / `update` / `get`). Blinded `find` / `count`
30
+ * / `updateIndex` and chunked streams (`storeChunk` / `getChunk`) require
31
+ * server-side EDV affordances (blinded `/query`, the `/{id}/chunks/{n}`
32
+ * sub-segment, conditional writes) that a plaintext WAS server does not yet
33
+ * provide, so they throw here. Because there are no conditional writes, the EDV
34
+ * `sequence` is advisory (last-writer-wins on `update`).
35
+ */
36
+ import { Transport } from '@interop/edv-client';
37
+ import type { IEncryptedDocument } from '@interop/data-integrity-core';
38
+ import type { WasClient } from '../WasClient.js';
39
+ /**
40
+ * The preferred content type marking a stored EDV-encrypted document (a JSON
41
+ * envelope whose `jwe` property carries the ciphertext). Requires the server to
42
+ * register an `application/*+json` content-type parser; otherwise use the
43
+ * default `application/json` (see `WasTransport`'s `contentType` option).
44
+ */
45
+ export declare const EDV_CONTENT_TYPE = "application/edv+json";
46
+ /**
47
+ * The subset of `WasClient` this transport depends on: the signed-request
48
+ * escape hatch. Declared structurally so tests can supply a lightweight stub.
49
+ */
50
+ type WasRequester = Pick<WasClient, 'request'>;
51
+ export declare class WasTransport extends Transport {
52
+ readonly spaceId: string;
53
+ readonly collectionId: string;
54
+ readonly contentType: string;
55
+ private readonly _was;
56
+ /**
57
+ * @param options {object}
58
+ * @param options.was {WasClient} a WAS client holding the signer
59
+ * @param options.spaceId {string} the vault's Space id
60
+ * @param options.collectionId {string} the vault Collection id
61
+ * @param [options.contentType] {string} content type for stored envelopes;
62
+ * defaults to `application/json` (accepted by an unmodified server). Pass
63
+ * `EDV_CONTENT_TYPE` against a server that registers an `application/*+json`
64
+ * parser.
65
+ */
66
+ constructor({ was, spaceId, collectionId, contentType }: {
67
+ was: WasRequester;
68
+ spaceId: string;
69
+ collectionId: string;
70
+ contentType?: string;
71
+ });
72
+ /**
73
+ * The WAS resource path for a document id, delegating to was-client's
74
+ * internal `resourcePath` builder so the percent-encoding and trailing-slash
75
+ * rules stay defined in one place (no trailing slash -- get/put/delete by
76
+ * id).
77
+ *
78
+ * @param id {string} the EDV document id (= WAS resource id)
79
+ * @returns {string}
80
+ */
81
+ private _resourcePath;
82
+ /**
83
+ * Writes an encrypted document to its WAS resource path as
84
+ * `application/edv+json` (the envelope serialized to bytes so the stored
85
+ * content type is exact).
86
+ *
87
+ * @param id {string}
88
+ * @param encrypted {IEncryptedDocument}
89
+ * @returns {Promise<HttpResponse>}
90
+ */
91
+ private _put;
92
+ /**
93
+ * @inheritdoc
94
+ *
95
+ * Inserts a new encrypted document. WAS `PUT` is an upsert, so to preserve
96
+ * EDV insert semantics (`DuplicateError` if the id already exists) this first
97
+ * checks for an existing resource. The check + write is not atomic -- with no
98
+ * server-side conditional writes yet, this is an advisory, single-writer
99
+ * guard.
100
+ *
101
+ * @param options {object}
102
+ * @param options.encrypted {IEncryptedDocument} the document to insert
103
+ * @returns {Promise<void>}
104
+ */
105
+ insert({ encrypted }?: {
106
+ encrypted?: IEncryptedDocument;
107
+ }): Promise<void>;
108
+ /**
109
+ * @inheritdoc
110
+ *
111
+ * Updates (upserts) an encrypted document. The EDV `sequence` is advisory
112
+ * here -- without server-side conditional writes, a stale write is not
113
+ * rejected (last-writer-wins).
114
+ *
115
+ * @param options {object}
116
+ * @param options.encrypted {IEncryptedDocument} the document to update
117
+ * @returns {Promise<void>}
118
+ */
119
+ update({ encrypted }?: {
120
+ encrypted?: IEncryptedDocument;
121
+ }): Promise<void>;
122
+ /**
123
+ * @inheritdoc
124
+ *
125
+ * Reads an encrypted document by id. Throws a `NotFoundError` (the name
126
+ * `EdvClientCore` expects) when the resource is missing or not visible.
127
+ *
128
+ * @param options {object}
129
+ * @param options.id {string} the document id to read
130
+ * @returns {Promise<IEncryptedDocument>}
131
+ */
132
+ get({ id }?: {
133
+ id?: string;
134
+ }): Promise<IEncryptedDocument>;
135
+ /**
136
+ * Resolves to `true` if a resource exists at the document's path. A 404
137
+ * resolves to `false`; any other error propagates.
138
+ *
139
+ * @param id {string}
140
+ * @returns {Promise<boolean>}
141
+ */
142
+ private _exists;
143
+ /**
144
+ * @inheritdoc
145
+ *
146
+ * Blinded-index query is not part of the documents-only EDV-over-WAS profile;
147
+ * it needs the server's `/query` affordance.
148
+ */
149
+ find(): Promise<never>;
150
+ /**
151
+ * @inheritdoc
152
+ *
153
+ * Index updates need the server's `/{id}/index` affordance.
154
+ */
155
+ updateIndex(): Promise<never>;
156
+ /**
157
+ * @inheritdoc
158
+ *
159
+ * Chunked streams need the reserved `/{id}/chunks/{n}` sub-segment.
160
+ */
161
+ storeChunk(): Promise<never>;
162
+ /**
163
+ * @inheritdoc
164
+ *
165
+ * Chunked streams need the reserved `/{id}/chunks/{n}` sub-segment.
166
+ */
167
+ getChunk(): Promise<never>;
168
+ /**
169
+ * Throws a uniform "not supported in this profile" error for EDV operations
170
+ * that depend on server-side affordances absent from a plaintext WAS server.
171
+ *
172
+ * @param operation {string}
173
+ * @returns {never}
174
+ */
175
+ private _unsupported;
176
+ }
177
+ export {};
178
+ //# sourceMappingURL=WasTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WasTransport.d.ts","sourceRoot":"","sources":["../../src/edv/WasTransport.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAKhD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,yBAAyB,CAAA;AAQtD;;;GAGG;AACH,KAAK,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;AAoC9C,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IAEnC;;;;;;;;;OASG;gBACS,EACV,GAAG,EACH,OAAO,EACP,YAAY,EACZ,WAAkC,EACnC,EAAE;QACD,GAAG,EAAE,YAAY,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB;IAQD;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAIrB;;;;;;;;OAQG;YACW,IAAI;IAalB;;;;;;;;;;;;OAYG;IACY,MAAM,CAAC,EACpB,SAAS,EACV,GAAE;QAAE,SAAS,CAAC,EAAE,kBAAkB,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1D;;;;;;;;;;OAUG;IACY,MAAM,CAAC,EACpB,SAAS,EACV,GAAE;QAAE,SAAS,CAAC,EAAE,kBAAkB,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB1D;;;;;;;;;OASG;IACY,GAAG,CAAC,EACjB,EAAE,EACH,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAuBrD;;;;;;OAMG;YACW,OAAO;IAYrB;;;;;OAKG;IACY,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;IAIrC;;;;OAIG;IACY,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC;IAI5C;;;;OAIG;IACY,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;IAI3C;;;;OAIG;IACY,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC;IAIzC;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;CAQrB"}