@interop/was-client 0.60.0 → 0.61.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.
- package/README.md +66 -45
- package/dist/Collection.d.ts +135 -94
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +612 -194
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +1 -1
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +0 -3
- package/dist/Resource.js.map +1 -1
- package/dist/Space.d.ts +17 -16
- package/dist/Space.d.ts.map +1 -1
- package/dist/Space.js +41 -24
- package/dist/Space.js.map +1 -1
- package/dist/codec.d.ts +3 -3
- package/dist/edv/EdvCodec.js +1 -1
- package/dist/edv/descriptorStore.d.ts +16 -14
- package/dist/edv/descriptorStore.d.ts.map +1 -1
- package/dist/edv/descriptorStore.js +17 -14
- package/dist/edv/descriptorStore.js.map +1 -1
- package/dist/edv/index.d.ts +1 -1
- package/dist/edv/index.js +1 -1
- package/dist/edv/logGovernedDescriptorStore.d.ts +2 -2
- package/dist/edv/logGovernedDescriptorStore.d.ts.map +1 -1
- package/dist/edv/logGovernedDescriptorStore.js +10 -9
- package/dist/edv/logGovernedDescriptorStore.js.map +1 -1
- package/dist/edv/recipients.d.ts +1 -1
- package/dist/edv/recipients.js +2 -2
- package/dist/edv/recipients.js.map +1 -1
- package/dist/edv/refresh.d.ts +1 -1
- package/dist/edv/refresh.js +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +3 -3
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/codec.d.ts +22 -1
- package/dist/internal/codec.d.ts.map +1 -1
- package/dist/internal/codec.js +117 -46
- package/dist/internal/codec.js.map +1 -1
- package/dist/internal/describe.d.ts +98 -24
- package/dist/internal/describe.d.ts.map +1 -1
- package/dist/internal/describe.js +125 -18
- package/dist/internal/describe.js.map +1 -1
- package/dist/internal/meta.d.ts +32 -17
- package/dist/internal/meta.d.ts.map +1 -1
- package/dist/internal/meta.js +64 -35
- package/dist/internal/meta.js.map +1 -1
- package/dist/internal/paths.d.ts +33 -17
- package/dist/internal/paths.d.ts.map +1 -1
- package/dist/internal/paths.js +92 -40
- package/dist/internal/paths.js.map +1 -1
- package/dist/internal/reserved.d.ts +14 -0
- package/dist/internal/reserved.d.ts.map +1 -1
- package/dist/internal/reserved.js +23 -4
- package/dist/internal/reserved.js.map +1 -1
- package/dist/paths.d.ts +8 -5
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +8 -5
- package/dist/paths.js.map +1 -1
- package/dist/sync/provisioning.d.ts +5 -5
- package/dist/sync/provisioning.d.ts.map +1 -1
- package/dist/sync/provisioning.js +2 -2
- package/dist/sync/provisioning.js.map +1 -1
- package/dist/types.d.ts +16 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/internal/codec.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { prepareBody, parseResource } from './content.js';
|
|
2
|
-
import {
|
|
2
|
+
import { asCollectionMetadata, readCollectionMetadata, storedEncryption, unreadableDescriptionError } from './describe.js';
|
|
3
3
|
import { readIndexSchema } from './indexSchema.js';
|
|
4
|
-
import { readMeta } from './meta.js';
|
|
5
4
|
import { Memo } from './memo.js';
|
|
6
|
-
import { collectionMeta } from './paths.js';
|
|
7
5
|
import { EncryptionError, NotImplementedError } from '../errors.js';
|
|
8
6
|
/**
|
|
9
7
|
* A per-handle codec cache. Memoizes the in-flight resolution so concurrent
|
|
@@ -138,32 +136,40 @@ export async function resolveCodec(context, { spaceId, collectionId, override, c
|
|
|
138
136
|
// descriptor's epoch roster and refuses an override without one
|
|
139
137
|
// fail-closed, so dropping the descriptor here would break every read and
|
|
140
138
|
// write.
|
|
141
|
-
|
|
139
|
+
const { codec } = await buildEncryptingCodec(context, {
|
|
142
140
|
spaceId,
|
|
143
141
|
collectionId,
|
|
144
142
|
scheme: override.scheme,
|
|
145
143
|
keys: override.keys,
|
|
146
|
-
capability,
|
|
147
144
|
encryption: override
|
|
148
145
|
});
|
|
146
|
+
// The override skipped the Collection Metadata read, so a searchable
|
|
147
|
+
// collection's persisted index schema is fetched here.
|
|
148
|
+
const meta = await loadIndexSchema(context, {
|
|
149
|
+
spaceId,
|
|
150
|
+
collectionId,
|
|
151
|
+
capability,
|
|
152
|
+
codec
|
|
153
|
+
});
|
|
154
|
+
return meta !== undefined ? { codec, meta } : { codec };
|
|
149
155
|
}
|
|
150
156
|
// 2. A plaintext-only client (no keystore) never encrypts; no round-trip.
|
|
151
157
|
if (!context.encryption) {
|
|
152
158
|
return { codec: identityCodec };
|
|
153
159
|
}
|
|
154
160
|
// 3. Otherwise the Collection's declared `encryption` descriptor decides -- but
|
|
155
|
-
// only if we could actually read the
|
|
156
|
-
// (a resource-scoped capability cannot GET
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
const
|
|
161
|
+
// only if we could actually read the Collection Metadata object. An
|
|
162
|
+
// unreadable object (a resource-scoped capability cannot GET it, and WAS
|
|
163
|
+
// masks that as a 404) is ambiguous: it is indistinguishable from "absent",
|
|
164
|
+
// so an encryption-capable client fails closed rather than silently
|
|
165
|
+
// downgrading to plaintext and writing the caller's secret as server-visible
|
|
166
|
+
// plaintext into a possibly-encrypted collection.
|
|
167
|
+
const read = await readCollectionMetadata(context, {
|
|
162
168
|
spaceId,
|
|
163
169
|
collectionId,
|
|
164
170
|
capability
|
|
165
171
|
});
|
|
166
|
-
if (
|
|
172
|
+
if (read === null) {
|
|
167
173
|
throw unreadableDescriptionError({
|
|
168
174
|
operation: `determine whether collection ${spaceId}/${collectionId} is ` +
|
|
169
175
|
'encrypted',
|
|
@@ -174,16 +180,91 @@ export async function resolveCodec(context, { spaceId, collectionId, override, c
|
|
|
174
180
|
ErrorClass: EncryptionError
|
|
175
181
|
});
|
|
176
182
|
}
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
const declared = storedEncryption(read.metadata);
|
|
184
|
+
const { codec } = declared
|
|
185
|
+
? await buildEncryptingCodec(context, {
|
|
186
|
+
spaceId,
|
|
187
|
+
collectionId,
|
|
188
|
+
scheme: declared.scheme,
|
|
189
|
+
encryption: declared
|
|
190
|
+
})
|
|
191
|
+
: { codec: identityCodec };
|
|
192
|
+
// The read that decided policy IS the Collection Metadata object, so it is
|
|
193
|
+
// also the index schema and the `meta()` answer: decode its `custom` with the
|
|
194
|
+
// codec just built and hand the snapshot on, rather than reading the same
|
|
195
|
+
// document again. A `custom` this reader cannot open is not the resolution's
|
|
196
|
+
// business -- only `meta()` and the search paths need it -- so the decode
|
|
197
|
+
// failure leaves the schema empty and the snapshot absent instead of failing
|
|
198
|
+
// every operation on the handle.
|
|
199
|
+
const meta = await snapshotFrom({ read, codec });
|
|
200
|
+
return meta !== undefined ? { codec, meta } : { codec };
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Builds the codec a descriptor names, for a write that states the descriptor
|
|
204
|
+
* itself rather than discovering it from stored state: the identity codec when
|
|
205
|
+
* there is no descriptor, and the keystore's codec when there is. Resolves
|
|
206
|
+
* `null` when this client cannot build that codec (no keystore, no keys, or an
|
|
207
|
+
* unhandled scheme) -- a caller that must not guess treats `null` as its own
|
|
208
|
+
* refusal, since nothing here is stored state to fail closed on.
|
|
209
|
+
*
|
|
210
|
+
* @param context {ClientContext}
|
|
211
|
+
* @param options {object}
|
|
212
|
+
* @param options.spaceId {string}
|
|
213
|
+
* @param options.collectionId {string}
|
|
214
|
+
* @param [options.descriptor] {CollectionEncryption} the descriptor the write
|
|
215
|
+
* declares; absent means plaintext
|
|
216
|
+
* @returns {Promise<ResourceCodec | null>}
|
|
217
|
+
*/
|
|
218
|
+
export async function codecForDescriptor(context, { spaceId, collectionId, descriptor }) {
|
|
219
|
+
if (descriptor === undefined) {
|
|
220
|
+
return identityCodec;
|
|
221
|
+
}
|
|
222
|
+
if (!context.encryption) {
|
|
223
|
+
return null;
|
|
179
224
|
}
|
|
180
|
-
|
|
225
|
+
const codec = await context.encryption.codecFor({
|
|
181
226
|
spaceId,
|
|
182
227
|
collectionId,
|
|
183
|
-
scheme:
|
|
184
|
-
encryption:
|
|
185
|
-
capability
|
|
228
|
+
scheme: descriptor.scheme,
|
|
229
|
+
encryption: descriptor
|
|
186
230
|
});
|
|
231
|
+
return codec ?? null;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Turns the Collection Metadata object a resolution read into the snapshot the
|
|
235
|
+
* resolution carries: `custom` decoded through the codec just built (an opaque
|
|
236
|
+
* envelope on an encrypted collection), and the codec's persisted index schema
|
|
237
|
+
* installed from it along the way.
|
|
238
|
+
*
|
|
239
|
+
* A `custom` the decode refuses -- a reader removed from the collection whose
|
|
240
|
+
* epoch key no longer unwraps it, an envelope bound to another slot, a
|
|
241
|
+
* plaintext object where an envelope belongs -- resolves `undefined` rather
|
|
242
|
+
* than throwing. The schema then stays empty (a search on an undeclared
|
|
243
|
+
* attribute still fails loudly at `find()`), and the operations that do not
|
|
244
|
+
* need `custom` keep working; a `meta()` reads and decodes for itself and is
|
|
245
|
+
* the call that surfaces the refusal.
|
|
246
|
+
*
|
|
247
|
+
* @param options {object}
|
|
248
|
+
* @param options.read {object} the stored object and its validator
|
|
249
|
+
* @param options.codec {ResourceCodec}
|
|
250
|
+
* @returns {Promise<(CollectionMetadata & { etag?: string }) | undefined>}
|
|
251
|
+
*/
|
|
252
|
+
async function snapshotFrom({ read, codec }) {
|
|
253
|
+
let custom;
|
|
254
|
+
try {
|
|
255
|
+
// The stated slot drives the encrypting codec's binding check: in the
|
|
256
|
+
// Collection slot it refuses a resource-bound envelope served there.
|
|
257
|
+
custom = await codec.decodeMeta({ custom: read.metadata.custom }, { kind: 'collection' });
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
codec.indexing?.applySchema(readIndexSchema(custom));
|
|
263
|
+
return {
|
|
264
|
+
...asCollectionMetadata(read.metadata),
|
|
265
|
+
custom,
|
|
266
|
+
...(read.etag !== undefined && { etag: read.etag })
|
|
267
|
+
};
|
|
187
268
|
}
|
|
188
269
|
/**
|
|
189
270
|
* Builds the encrypting codec for a collection known to be encrypted, failing
|
|
@@ -196,12 +277,12 @@ export async function resolveCodec(context, { spaceId, collectionId, override, c
|
|
|
196
277
|
* @param options.spaceId {string}
|
|
197
278
|
* @param options.collectionId {string}
|
|
198
279
|
* @param options.scheme {string}
|
|
280
|
+
* @param [options.encryption] {CollectionEncryption} the descriptor, passed
|
|
281
|
+
* whole to the provider
|
|
199
282
|
* @param [options.keys] {unknown} override-supplied key material
|
|
200
|
-
* @param [options.capability] {IZcap} the handle's bound capability, used for
|
|
201
|
-
* the index-schema read
|
|
202
283
|
* @returns {Promise<CodecResolution>}
|
|
203
284
|
*/
|
|
204
|
-
async function buildEncryptingCodec(context, { spaceId, collectionId, scheme, encryption, keys
|
|
285
|
+
async function buildEncryptingCodec(context, { spaceId, collectionId, scheme, encryption, keys }) {
|
|
205
286
|
const where = `${spaceId}/${collectionId}`;
|
|
206
287
|
if (!context.encryption) {
|
|
207
288
|
throw new EncryptionError(`Collection ${where} is encrypted (scheme "${scheme}") but this client ` +
|
|
@@ -220,20 +301,14 @@ async function buildEncryptingCodec(context, { spaceId, collectionId, scheme, en
|
|
|
220
301
|
'holds no keys for it (or does not handle the scheme). Supply keys via ' +
|
|
221
302
|
'your keystore (resolveKeys) or a per-handle encryption override.');
|
|
222
303
|
}
|
|
223
|
-
|
|
224
|
-
spaceId,
|
|
225
|
-
collectionId,
|
|
226
|
-
capability,
|
|
227
|
-
codec
|
|
228
|
-
});
|
|
229
|
-
return meta !== undefined ? { codec, meta } : { codec };
|
|
304
|
+
return { codec };
|
|
230
305
|
}
|
|
231
306
|
/**
|
|
232
|
-
* Loads the collection's persisted index schema onto a
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* is every codec on a collection whose descriptor
|
|
236
|
-
*
|
|
307
|
+
* Loads the collection's persisted index schema onto a codec built from a
|
|
308
|
+
* per-handle encryption override -- the one path that skipped the Collection
|
|
309
|
+
* Metadata read, so the schema is not already in hand. A no-op for a codec with
|
|
310
|
+
* no search capability, which is every codec on a collection whose descriptor
|
|
311
|
+
* declares no blinding key.
|
|
237
312
|
*
|
|
238
313
|
* The schema is discovered rather than declared per app: it is the reason
|
|
239
314
|
* declarations are persisted at all, so a reader that did not create the
|
|
@@ -247,7 +322,7 @@ async function buildEncryptingCodec(context, { spaceId, collectionId, scheme, en
|
|
|
247
322
|
* failing the resolution: neither says the collection is broken, and every
|
|
248
323
|
* search on an undeclared attribute still fails loudly at `find()`.
|
|
249
324
|
*
|
|
250
|
-
* The decoded metadata is returned so the caller that paid for
|
|
325
|
+
* The decoded metadata is returned so the caller that paid for the read can
|
|
251
326
|
* hand it to a `meta()` that would otherwise repeat it -- it is exactly what
|
|
252
327
|
* `Collection.meta()` produces, decrypted `custom` and `etag` included.
|
|
253
328
|
*
|
|
@@ -262,17 +337,14 @@ async function buildEncryptingCodec(context, { spaceId, collectionId, scheme, en
|
|
|
262
337
|
* no read happened at all
|
|
263
338
|
*/
|
|
264
339
|
async function loadIndexSchema(context, { spaceId, collectionId, capability, codec }) {
|
|
265
|
-
|
|
266
|
-
if (!indexing) {
|
|
340
|
+
if (!codec.indexing) {
|
|
267
341
|
return undefined;
|
|
268
342
|
}
|
|
269
|
-
let
|
|
343
|
+
let read;
|
|
270
344
|
try {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
subject: `collection "${collectionId}"`,
|
|
275
|
-
slot: { kind: 'collection' },
|
|
345
|
+
read = await readCollectionMetadata(context, {
|
|
346
|
+
spaceId,
|
|
347
|
+
collectionId,
|
|
276
348
|
capability
|
|
277
349
|
});
|
|
278
350
|
}
|
|
@@ -282,10 +354,9 @@ async function loadIndexSchema(context, { spaceId, collectionId, capability, cod
|
|
|
282
354
|
}
|
|
283
355
|
throw err;
|
|
284
356
|
}
|
|
285
|
-
if (
|
|
357
|
+
if (read === null) {
|
|
286
358
|
return null;
|
|
287
359
|
}
|
|
288
|
-
|
|
289
|
-
return meta;
|
|
360
|
+
return snapshotFrom({ read, codec });
|
|
290
361
|
}
|
|
291
362
|
//# sourceMappingURL=codec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/internal/codec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/internal/codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,19 +2,44 @@
|
|
|
2
2
|
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Reads a Collection
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Reads a Collection Metadata object with a single GET of the Collection's
|
|
6
|
+
* `meta` sub-resource, in the wire form the server serves it: `custom` is
|
|
7
|
+
* whatever is stored there (an opaque envelope on an encrypted Collection),
|
|
8
|
+
* left undecoded, because the codec that would decode it is itself resolved
|
|
9
|
+
* from this object's `encryption` member. Shared by `Collection`'s read and
|
|
10
|
+
* write paths and by the codec resolver's descriptor discovery, so the request
|
|
11
|
+
* shape (path, capability, null-unwrap, validator) lives in one place.
|
|
12
|
+
*
|
|
13
|
+
* Also owns the masked-404 fail-closed policy: WAS returns 404 for both
|
|
14
|
+
* not-found and unauthorized, so a `null` read is ambiguous and an operation
|
|
15
|
+
* that must know the current state fails closed via
|
|
11
16
|
* `unreadableDescriptionError` rather than guessing. `collectionWritableFields`
|
|
12
|
-
* lives here too: it is the one inclusion rule for the writable
|
|
13
|
-
*
|
|
17
|
+
* lives here too: it is the one inclusion rule for the writable configuration
|
|
18
|
+
* members a caller supplies, beside `carriedForward`, the rule for the stored
|
|
19
|
+
* members a full-replacement write re-sends unchanged.
|
|
14
20
|
*/
|
|
15
21
|
import type { ClientContext } from './request.js';
|
|
16
22
|
import type { WasError } from '../errors.js';
|
|
17
|
-
import type {
|
|
23
|
+
import type { CollectionEncryption, CollectionMetadata, CollectionWritableFields, IZcap } from '../types.js';
|
|
24
|
+
/**
|
|
25
|
+
* A Collection Metadata object exactly as the server served it. Typed as an
|
|
26
|
+
* open record rather than as `CollectionMetadata`, because `custom` here is the
|
|
27
|
+
* stored value (an opaque encryption envelope on an encrypted Collection) and
|
|
28
|
+
* because a write forwards members this client does not model verbatim rather
|
|
29
|
+
* than dropping them (see {@link carriedForward}).
|
|
30
|
+
*/
|
|
31
|
+
export type StoredCollectionMetadata = Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Reads a stored Collection Metadata object as the `CollectionMetadata` wire
|
|
34
|
+
* type. The stored form is typed as an open record -- `custom` is the stored
|
|
35
|
+
* value and a write forwards members this client does not model -- while the
|
|
36
|
+
* server guarantees the object's shape, so the assertion lives here once
|
|
37
|
+
* instead of at each reader.
|
|
38
|
+
*
|
|
39
|
+
* @param stored {StoredCollectionMetadata}
|
|
40
|
+
* @returns {CollectionMetadata}
|
|
41
|
+
*/
|
|
42
|
+
export declare function asCollectionMetadata(stored: StoredCollectionMetadata): CollectionMetadata;
|
|
18
43
|
/**
|
|
19
44
|
* Whether a served encryption descriptor is the server-derived projection of
|
|
20
45
|
* a Collection governed by its history log (it carries the `history` pointer)
|
|
@@ -31,38 +56,87 @@ export declare function isGovernedDescriptor(descriptor: CollectionEncryption):
|
|
|
31
56
|
};
|
|
32
57
|
};
|
|
33
58
|
/**
|
|
34
|
-
* Picks the writable Collection
|
|
35
|
-
* inclusion rule (`!== undefined`) behind every
|
|
36
|
-
* `configure` / `replaceDescription` request bodies and their echoed
|
|
37
|
-
*
|
|
38
|
-
*
|
|
59
|
+
* Picks the writable Collection configuration members that are set. The one
|
|
60
|
+
* inclusion rule (`!== undefined`) behind every Collection Metadata write body
|
|
61
|
+
* -- the `configure` / `replaceDescription` request bodies and their echoed
|
|
62
|
+
* returns, and `Space.createCollection`'s create body -- so the paths cannot
|
|
63
|
+
* drift and a new writable member is added in one place.
|
|
39
64
|
*
|
|
40
65
|
* @param fields {CollectionWritableFields}
|
|
41
66
|
* @returns {CollectionWritableFields}
|
|
42
67
|
*/
|
|
43
68
|
export declare function collectionWritableFields(fields: CollectionWritableFields): CollectionWritableFields;
|
|
44
69
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
70
|
+
* The Collection's configuration members: what a configuration write
|
|
71
|
+
* (`configure`, `replaceDescription`) states in full and an annotation write
|
|
72
|
+
* carries forward.
|
|
73
|
+
*/
|
|
74
|
+
export declare const CONFIGURATION_MEMBERS: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* The Collection's annotation members: the user-writable `custom` and the key
|
|
77
|
+
* epoch its envelope was sealed under. What an annotation write (`setMeta` and
|
|
78
|
+
* its sugar) states and a configuration write carries forward.
|
|
79
|
+
*/
|
|
80
|
+
export declare const ANNOTATION_MEMBERS: readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Reads a stored `encryption` descriptor at its wire type. The one place the
|
|
83
|
+
* open stored record is narrowed to `CollectionEncryption`, shared by the
|
|
84
|
+
* compose paths and the codec resolver so the assertion is not repeated.
|
|
85
|
+
*
|
|
86
|
+
* @param stored {StoredCollectionMetadata}
|
|
87
|
+
* @returns {CollectionEncryption | undefined}
|
|
88
|
+
*/
|
|
89
|
+
export declare function storedEncryption(stored: StoredCollectionMetadata): CollectionEncryption | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Picks the stored members a full-replacement write carries forward: every
|
|
92
|
+
* member except the ones the server manages and the ones this write states
|
|
93
|
+
* itself. A denylist rather than an allowlist, so a member this client does
|
|
94
|
+
* not model -- `plaintext`, or one a newer server serves -- survives a write
|
|
95
|
+
* it is not about instead of being silently cleared.
|
|
96
|
+
*
|
|
97
|
+
* A governed `encryption` descriptor is deliberately dropped: on a
|
|
98
|
+
* log-governed Collection the served descriptor is the server's projection of
|
|
99
|
+
* the history log's head, and a write that carries it is refused
|
|
100
|
+
* (`encryption-history-log-governed`). Omitting the member leaves the derived
|
|
101
|
+
* descriptor in place.
|
|
102
|
+
*
|
|
103
|
+
* @param stored {StoredCollectionMetadata}
|
|
104
|
+
* @param options {object}
|
|
105
|
+
* @param options.replacing {readonly string[]} the members this write states
|
|
106
|
+
* itself (`CONFIGURATION_MEMBERS` on a configuration write,
|
|
107
|
+
* `ANNOTATION_MEMBERS` on an annotation write)
|
|
108
|
+
* @returns {StoredCollectionMetadata}
|
|
109
|
+
*/
|
|
110
|
+
export declare function carriedForward(stored: StoredCollectionMetadata, { replacing }: {
|
|
111
|
+
replacing: readonly string[];
|
|
112
|
+
}): StoredCollectionMetadata;
|
|
113
|
+
/**
|
|
114
|
+
* Reads the Collection Metadata object with its `metaVersion` validator, in the
|
|
115
|
+
* stored wire form. Returns `null` if the collection is missing or not visible
|
|
116
|
+
* to you (WAS returns 404 for both not-found and unauthorized); `etag` is
|
|
117
|
+
* absent against a backend that does not version the object.
|
|
47
118
|
*
|
|
48
119
|
* @param context {ClientContext}
|
|
49
120
|
* @param options {object}
|
|
50
121
|
* @param options.spaceId {string}
|
|
51
122
|
* @param options.collectionId {string}
|
|
52
123
|
* @param [options.capability] {IZcap} capability attached to the request
|
|
53
|
-
* @returns {Promise<
|
|
124
|
+
* @returns {Promise<{ metadata: StoredCollectionMetadata; etag?: string } | null>}
|
|
54
125
|
*/
|
|
55
|
-
export declare function
|
|
126
|
+
export declare function readCollectionMetadata(context: ClientContext, options: {
|
|
56
127
|
spaceId: string;
|
|
57
128
|
collectionId: string;
|
|
58
129
|
capability?: IZcap;
|
|
59
|
-
}): Promise<
|
|
130
|
+
}): Promise<{
|
|
131
|
+
metadata: StoredCollectionMetadata;
|
|
132
|
+
etag?: string;
|
|
133
|
+
} | null>;
|
|
60
134
|
/**
|
|
61
|
-
* Builds the fail-closed error for an operation that needs a
|
|
62
|
-
* could not read. The one owner of the masked-404 policy
|
|
63
|
-
* returns 404 for both not-found and unauthorized, so a null
|
|
64
|
-
* ambiguous -- fail closed"); callers supply the operation, its
|
|
65
|
-
* and the recovery advice.
|
|
135
|
+
* Builds the fail-closed error for an operation that needs a Collection
|
|
136
|
+
* Metadata object it could not read. The one owner of the masked-404 policy
|
|
137
|
+
* statement ("WAS returns 404 for both not-found and unauthorized, so a null
|
|
138
|
+
* read is ambiguous -- fail closed"); callers supply the operation, its
|
|
139
|
+
* consequence, and the recovery advice.
|
|
66
140
|
*
|
|
67
141
|
* @param options {object}
|
|
68
142
|
* @param options.operation {string} what was refused, continuing "Cannot ..."
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/internal/describe.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/internal/describe.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAIjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,EACN,MAAM,aAAa,CAAA;AAEpB;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE9D;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAEpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,GAC/B,UAAU,IAAI,oBAAoB,GAAG;IACtC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9C,CAEA;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,wBAAwB,CAU1B;AAsBD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAAwB,CAAA;AAExE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,wBAAwB,GAC/B,oBAAoB,GAAG,SAAS,CAElC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,wBAAwB,EAChC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC9C,wBAAwB,CAgB1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACrE,OAAO,CAAC;IAAE,QAAQ,EAAE,wBAAwB,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAYvE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,SAAS,EACT,WAAW,EACX,MAAM,EACN,UAA4B,EAC7B,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAA;CAC/C,GAAG,QAAQ,CAQX"}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readDataWithEtag } from './request.js';
|
|
2
|
+
import { collectionMeta } from './paths.js';
|
|
3
3
|
import { ValidationError } from '../errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reads a stored Collection Metadata object as the `CollectionMetadata` wire
|
|
6
|
+
* type. The stored form is typed as an open record -- `custom` is the stored
|
|
7
|
+
* value and a write forwards members this client does not model -- while the
|
|
8
|
+
* server guarantees the object's shape, so the assertion lives here once
|
|
9
|
+
* instead of at each reader.
|
|
10
|
+
*
|
|
11
|
+
* @param stored {StoredCollectionMetadata}
|
|
12
|
+
* @returns {CollectionMetadata}
|
|
13
|
+
*/
|
|
14
|
+
export function asCollectionMetadata(stored) {
|
|
15
|
+
return stored;
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Whether a served encryption descriptor is the server-derived projection of
|
|
6
19
|
* a Collection governed by its history log (it carries the `history` pointer)
|
|
@@ -14,11 +27,11 @@ export function isGovernedDescriptor(descriptor) {
|
|
|
14
27
|
return descriptor.history !== undefined;
|
|
15
28
|
}
|
|
16
29
|
/**
|
|
17
|
-
* Picks the writable Collection
|
|
18
|
-
* inclusion rule (`!== undefined`) behind every
|
|
19
|
-
* `configure` / `replaceDescription` request bodies and their echoed
|
|
20
|
-
*
|
|
21
|
-
*
|
|
30
|
+
* Picks the writable Collection configuration members that are set. The one
|
|
31
|
+
* inclusion rule (`!== undefined`) behind every Collection Metadata write body
|
|
32
|
+
* -- the `configure` / `replaceDescription` request bodies and their echoed
|
|
33
|
+
* returns, and `Space.createCollection`'s create body -- so the paths cannot
|
|
34
|
+
* drift and a new writable member is added in one place.
|
|
22
35
|
*
|
|
23
36
|
* @param fields {CollectionWritableFields}
|
|
24
37
|
* @returns {CollectionWritableFields}
|
|
@@ -35,28 +48,122 @@ export function collectionWritableFields(fields) {
|
|
|
35
48
|
};
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
51
|
+
* The members of a Collection Metadata object the server owns: it ignores them
|
|
52
|
+
* in a request body and re-derives them on every write, so a write never
|
|
53
|
+
* echoes them back. `id` is stated by the write path itself, `type` is the
|
|
54
|
+
* server's classification, and the rest are server-observed (the spec's
|
|
55
|
+
* "server-managed members are read-only" rule).
|
|
56
|
+
*/
|
|
57
|
+
const SERVER_MANAGED_MEMBERS = [
|
|
58
|
+
'id',
|
|
59
|
+
'type',
|
|
60
|
+
// Not a stored member at all: the client-side projection of the validator
|
|
61
|
+
// that `describe()` returns beside the object, which must not travel back.
|
|
62
|
+
'etag',
|
|
63
|
+
'url',
|
|
64
|
+
'linkset',
|
|
65
|
+
'createdAt',
|
|
66
|
+
'updatedAt',
|
|
67
|
+
'createdBy'
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* The Collection's configuration members: what a configuration write
|
|
71
|
+
* (`configure`, `replaceDescription`) states in full and an annotation write
|
|
72
|
+
* carries forward.
|
|
73
|
+
*/
|
|
74
|
+
export const CONFIGURATION_MEMBERS = [
|
|
75
|
+
'name',
|
|
76
|
+
'backend',
|
|
77
|
+
'encryption',
|
|
78
|
+
'generator',
|
|
79
|
+
'generatorOrigin'
|
|
80
|
+
];
|
|
81
|
+
/**
|
|
82
|
+
* The Collection's annotation members: the user-writable `custom` and the key
|
|
83
|
+
* epoch its envelope was sealed under. What an annotation write (`setMeta` and
|
|
84
|
+
* its sugar) states and a configuration write carries forward.
|
|
85
|
+
*/
|
|
86
|
+
export const ANNOTATION_MEMBERS = ['custom', 'epoch'];
|
|
87
|
+
/**
|
|
88
|
+
* Reads a stored `encryption` descriptor at its wire type. The one place the
|
|
89
|
+
* open stored record is narrowed to `CollectionEncryption`, shared by the
|
|
90
|
+
* compose paths and the codec resolver so the assertion is not repeated.
|
|
91
|
+
*
|
|
92
|
+
* @param stored {StoredCollectionMetadata}
|
|
93
|
+
* @returns {CollectionEncryption | undefined}
|
|
94
|
+
*/
|
|
95
|
+
export function storedEncryption(stored) {
|
|
96
|
+
return stored.encryption;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Picks the stored members a full-replacement write carries forward: every
|
|
100
|
+
* member except the ones the server manages and the ones this write states
|
|
101
|
+
* itself. A denylist rather than an allowlist, so a member this client does
|
|
102
|
+
* not model -- `plaintext`, or one a newer server serves -- survives a write
|
|
103
|
+
* it is not about instead of being silently cleared.
|
|
104
|
+
*
|
|
105
|
+
* A governed `encryption` descriptor is deliberately dropped: on a
|
|
106
|
+
* log-governed Collection the served descriptor is the server's projection of
|
|
107
|
+
* the history log's head, and a write that carries it is refused
|
|
108
|
+
* (`encryption-history-log-governed`). Omitting the member leaves the derived
|
|
109
|
+
* descriptor in place.
|
|
110
|
+
*
|
|
111
|
+
* @param stored {StoredCollectionMetadata}
|
|
112
|
+
* @param options {object}
|
|
113
|
+
* @param options.replacing {readonly string[]} the members this write states
|
|
114
|
+
* itself (`CONFIGURATION_MEMBERS` on a configuration write,
|
|
115
|
+
* `ANNOTATION_MEMBERS` on an annotation write)
|
|
116
|
+
* @returns {StoredCollectionMetadata}
|
|
117
|
+
*/
|
|
118
|
+
export function carriedForward(stored, { replacing }) {
|
|
119
|
+
const carried = {};
|
|
120
|
+
for (const [member, value] of Object.entries(stored)) {
|
|
121
|
+
if (value === undefined) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (SERVER_MANAGED_MEMBERS.includes(member) || replacing.includes(member)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
carried[member] = value;
|
|
128
|
+
}
|
|
129
|
+
const encryption = storedEncryption(stored);
|
|
130
|
+
if (encryption !== undefined && isGovernedDescriptor(encryption)) {
|
|
131
|
+
delete carried.encryption;
|
|
132
|
+
}
|
|
133
|
+
return carried;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Reads the Collection Metadata object with its `metaVersion` validator, in the
|
|
137
|
+
* stored wire form. Returns `null` if the collection is missing or not visible
|
|
138
|
+
* to you (WAS returns 404 for both not-found and unauthorized); `etag` is
|
|
139
|
+
* absent against a backend that does not version the object.
|
|
40
140
|
*
|
|
41
141
|
* @param context {ClientContext}
|
|
42
142
|
* @param options {object}
|
|
43
143
|
* @param options.spaceId {string}
|
|
44
144
|
* @param options.collectionId {string}
|
|
45
145
|
* @param [options.capability] {IZcap} capability attached to the request
|
|
46
|
-
* @returns {Promise<
|
|
146
|
+
* @returns {Promise<{ metadata: StoredCollectionMetadata; etag?: string } | null>}
|
|
47
147
|
*/
|
|
48
|
-
export async function
|
|
49
|
-
|
|
50
|
-
path:
|
|
148
|
+
export async function readCollectionMetadata(context, options) {
|
|
149
|
+
const read = await readDataWithEtag(context, {
|
|
150
|
+
path: collectionMeta(options.spaceId, options.collectionId),
|
|
51
151
|
capability: options.capability
|
|
52
152
|
});
|
|
153
|
+
if (read === null) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
metadata: read.data,
|
|
158
|
+
...(read.etag !== undefined && { etag: read.etag })
|
|
159
|
+
};
|
|
53
160
|
}
|
|
54
161
|
/**
|
|
55
|
-
* Builds the fail-closed error for an operation that needs a
|
|
56
|
-
* could not read. The one owner of the masked-404 policy
|
|
57
|
-
* returns 404 for both not-found and unauthorized, so a null
|
|
58
|
-
* ambiguous -- fail closed"); callers supply the operation, its
|
|
59
|
-
* and the recovery advice.
|
|
162
|
+
* Builds the fail-closed error for an operation that needs a Collection
|
|
163
|
+
* Metadata object it could not read. The one owner of the masked-404 policy
|
|
164
|
+
* statement ("WAS returns 404 for both not-found and unauthorized, so a null
|
|
165
|
+
* read is ambiguous -- fail closed"); callers supply the operation, its
|
|
166
|
+
* consequence, and the recovery advice.
|
|
60
167
|
*
|
|
61
168
|
* @param options {object}
|
|
62
169
|
* @param options.operation {string} what was refused, continuing "Cannot ..."
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/internal/describe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/internal/describe.ts"],"names":[],"mappings":"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"}
|