@interop/was-client 0.6.0 → 0.7.1
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 +95 -1
- package/dist/Collection.d.ts +28 -3
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +74 -13
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +58 -9
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +104 -26
- package/dist/Resource.js.map +1 -1
- package/dist/Space.d.ts +11 -1
- package/dist/Space.d.ts.map +1 -1
- package/dist/Space.js +13 -2
- package/dist/Space.js.map +1 -1
- package/dist/WasClient.d.ts +10 -2
- package/dist/WasClient.d.ts.map +1 -1
- package/dist/WasClient.js +11 -4
- package/dist/WasClient.js.map +1 -1
- package/dist/codec.d.ts +127 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +2 -0
- package/dist/codec.js.map +1 -0
- package/dist/edv/EdvCodec.d.ts +148 -0
- package/dist/edv/EdvCodec.d.ts.map +1 -0
- package/dist/edv/EdvCodec.js +284 -0
- package/dist/edv/EdvCodec.js.map +1 -0
- package/dist/edv/index.d.ts +10 -0
- package/dist/edv/index.d.ts.map +1 -1
- package/dist/edv/index.js +10 -0
- package/dist/edv/index.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/codec.d.ts +27 -0
- package/dist/internal/codec.d.ts.map +1 -0
- package/dist/internal/codec.js +44 -0
- package/dist/internal/codec.js.map +1 -0
- package/dist/internal/conditional.d.ts +40 -0
- package/dist/internal/conditional.d.ts.map +1 -0
- package/dist/internal/conditional.js +35 -0
- package/dist/internal/conditional.js.map +1 -0
- package/dist/internal/request.d.ts +5 -1
- package/dist/internal/request.d.ts.map +1 -1
- package/dist/internal/request.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,9 +19,10 @@
|
|
|
19
19
|
- [Delegation and sharing](#delegation-and-sharing)
|
|
20
20
|
- [Public sharing and access-control policies](#public-sharing-and-access-control-policies)
|
|
21
21
|
- [Resource metadata](#resource-metadata)
|
|
22
|
+
- [Conditional writes (optimistic concurrency)](#conditional-writes-optimistic-concurrency)
|
|
22
23
|
- [Storage introspection: backends and quotas](#storage-introspection-backends-and-quotas)
|
|
23
|
-
- [Export and import](#export-and-import)
|
|
24
24
|
- [Encrypted collections (EDV-over-WAS)](#encrypted-collections-edv-over-was)
|
|
25
|
+
- [Export and import](#export-and-import)
|
|
25
26
|
- [The manual-request escape hatch](#the-manual-request-escape-hatch)
|
|
26
27
|
- [Errors and the 404/null caveat](#errors-and-the-404null-caveat)
|
|
27
28
|
- [Contribute](#contribute)
|
|
@@ -373,6 +374,37 @@ await resource.setTags({ status: 'verified' }) // keeps existing name
|
|
|
373
374
|
The `custom.name` is the same value surfaced as a resource's `name` in
|
|
374
375
|
collection listings; updating one updates the other.
|
|
375
376
|
|
|
377
|
+
### Conditional writes (optimistic concurrency)
|
|
378
|
+
|
|
379
|
+
Against a backend that advertises the `conditional-writes` feature (see below),
|
|
380
|
+
a Resource carries a strong **`ETag`** validator that changes on every write.
|
|
381
|
+
Use it to prevent the lost-update problem -- two clients that both read version
|
|
382
|
+
_N_ and each write _N+1_, the second silently clobbering the first.
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
const { etag } = await collection.put('doc', { v: 1 }) // writes return the ETag
|
|
386
|
+
const meta = await collection.resource('doc').meta() // meta().etag also carries it
|
|
387
|
+
|
|
388
|
+
// Update-if-unchanged: succeeds only if `doc` is still at `etag`, else throws
|
|
389
|
+
// PreconditionFailedError (HTTP 412).
|
|
390
|
+
await collection.put('doc', { v: 2 }, { ifMatch: etag })
|
|
391
|
+
|
|
392
|
+
// Create-if-absent: succeeds only if `doc` does not yet exist (else 412).
|
|
393
|
+
await collection.put('new-doc', { v: 1 }, { ifNoneMatch: true })
|
|
394
|
+
|
|
395
|
+
// Delete-if-unchanged.
|
|
396
|
+
await collection.resource('doc').delete({ ifMatch: someEtag })
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Recover from a `PreconditionFailedError` by re-reading the current `etag`,
|
|
400
|
+
re-applying your change on top of the new version, and retrying.
|
|
401
|
+
|
|
402
|
+
On an **encrypted collection** this is automatic: the EDV codec advances the
|
|
403
|
+
document `sequence` and pins each write to the current ETag for you, so a stale
|
|
404
|
+
write surfaces as a `PreconditionFailedError` (the EDV `sequence` becomes
|
|
405
|
+
enforced rather than advisory). The explicit `ifMatch` / `ifNoneMatch` options
|
|
406
|
+
above are for plaintext collections.
|
|
407
|
+
|
|
376
408
|
### Storage introspection: backends and quotas
|
|
377
409
|
|
|
378
410
|
A Space can report the storage backends available to it and a per-backend usage
|
|
@@ -394,6 +426,68 @@ const usage = await collection.quota() // BackendUsage | null
|
|
|
394
426
|
// usage: { id, state, usageBytes, limit, restrictedActions, measuredAt, ... }
|
|
395
427
|
```
|
|
396
428
|
|
|
429
|
+
A `BackendDescriptor`'s optional `features` array advertises optional **server
|
|
430
|
+
affordances** -- things the backend actively does beyond the baseline read/write
|
|
431
|
+
API (e.g. `conditional-writes`, `blinded-index-query`, `chunked-streams`). An
|
|
432
|
+
absent token means the backend makes no claim to it, so treat it as unsupported
|
|
433
|
+
rather than assuming a default. (Client-side encryption is _not_ a backend
|
|
434
|
+
feature -- see below.)
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
const backend = await collection.backend()
|
|
438
|
+
if (backend?.features?.includes('conditional-writes')) {
|
|
439
|
+
// backend enforces If-Match / If-None-Match write preconditions
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Encrypted collections (EDV-over-WAS)
|
|
444
|
+
|
|
445
|
+
Client-side end-to-end encryption is a per-collection concern, gated on whether
|
|
446
|
+
your client holds keys for the collection -- **not** a backend feature (an
|
|
447
|
+
encrypted document is opaque JSON any document backend stores faithfully).
|
|
448
|
+
Construct a `WasClient` with an `encryption` provider (built from the opt-in
|
|
449
|
+
`@interop/was-client/edv` subpath, so plaintext consumers never pull the crypto
|
|
450
|
+
graph), and the ordinary `Collection`/`Resource` handles transparently encrypt
|
|
451
|
+
on write and decrypt on read -- for any collection your `resolveKeys` returns
|
|
452
|
+
keys for. Keys live in your wallet; the server only ever stores opaque JWE
|
|
453
|
+
envelopes.
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
import { WasClient } from '@interop/was-client'
|
|
457
|
+
import { createEdvEncryption } from '@interop/was-client/edv'
|
|
458
|
+
|
|
459
|
+
const encryption = createEdvEncryption({
|
|
460
|
+
// Return the collection's keys to encrypt it, or null to use it in plaintext.
|
|
461
|
+
async resolveKeys({ spaceId, collectionId }) {
|
|
462
|
+
return { keyAgreementKey, keyResolver } // from your wallet
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
const was = WasClient.fromSigner({ serverUrl, signer, encryption })
|
|
466
|
+
|
|
467
|
+
const vault = was.space(spaceId).collection('vault')
|
|
468
|
+
const { id } = await vault.add({ secret: 'hello' }) // encrypted; id is an EDV id
|
|
469
|
+
const back = await vault.get(id) // { secret: 'hello' } -- decrypted
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
The switch is **keys**: a handle encrypts a collection exactly when
|
|
473
|
+
`resolveKeys` returns keys for it (else it stays plaintext). Resolution happens
|
|
474
|
+
once per collection handle and is cached -- no backend round-trip.
|
|
475
|
+
|
|
476
|
+
Encrypted collections are a **stricter contract**, not a drop-in (documents-only
|
|
477
|
+
scope for now):
|
|
478
|
+
|
|
479
|
+
- **Ids.** `add()` mints an EDV id (a `z`-prefixed multibase value used verbatim
|
|
480
|
+
as the WAS resource id). `put(id, ...)` accepts only an EDV-format id; a
|
|
481
|
+
human-readable id is rejected (it would leak onto the URL) -- carry a
|
|
482
|
+
human-readable label inside the encrypted content instead.
|
|
483
|
+
- **Metadata.** `resource.setName()` / `setTags()` throw on an encrypted
|
|
484
|
+
collection (they write server-visible plaintext); store those values inside
|
|
485
|
+
the encrypted content.
|
|
486
|
+
- **Binary.** A small `Blob`/`Uint8Array` is encrypted as a single document;
|
|
487
|
+
larger binaries are rejected until chunked encrypted blobs land.
|
|
488
|
+
- **Raw reads.** `get()` decrypts; the `getText()` / `getBytes()` escape hatches
|
|
489
|
+
do not (they return the stored representation).
|
|
490
|
+
|
|
397
491
|
### Export and import
|
|
398
492
|
|
|
399
493
|
```ts
|
package/dist/Collection.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class Collection {
|
|
|
6
6
|
readonly id: string;
|
|
7
7
|
private readonly _context;
|
|
8
8
|
private readonly _capability?;
|
|
9
|
+
private _codecPromise?;
|
|
9
10
|
/**
|
|
10
11
|
* @param options {object}
|
|
11
12
|
* @param options.context {ClientContext} - Shared context (serverUrl, ezcap
|
|
@@ -22,6 +23,15 @@ export declare class Collection {
|
|
|
22
23
|
});
|
|
23
24
|
private get _path();
|
|
24
25
|
private get _itemsPath();
|
|
26
|
+
/**
|
|
27
|
+
* Resolves (once, then caches) the codec for this collection's reads and
|
|
28
|
+
* writes: the identity codec for a plaintext collection, or the encrypting
|
|
29
|
+
* codec when an `EncryptionProvider` is injected and supplies one for this
|
|
30
|
+
* collection (i.e. the client holds keys for it).
|
|
31
|
+
*
|
|
32
|
+
* @returns {Promise<ResourceCodec>}
|
|
33
|
+
*/
|
|
34
|
+
private _codec;
|
|
25
35
|
/**
|
|
26
36
|
* Reads the Collection Description. Returns `null` if the collection is
|
|
27
37
|
* missing or not visible to you (WAS returns 404 for both not-found and
|
|
@@ -82,17 +92,25 @@ export declare class Collection {
|
|
|
82
92
|
*/
|
|
83
93
|
get(resourceId: string): Promise<Json | Blob | null>;
|
|
84
94
|
/**
|
|
85
|
-
* Creates or replaces a resource by id (upsert).
|
|
95
|
+
* Creates or replaces a resource by id (upsert). Forwards the conditional-write
|
|
96
|
+
* options (`ifMatch` / `ifNoneMatch`) to `Resource.put`; see it for the
|
|
97
|
+
* `conditional-writes` semantics. Returns the stored resource's new `etag`.
|
|
86
98
|
*
|
|
87
99
|
* @param resourceId {string}
|
|
88
100
|
* @param data {Json | Blob | Uint8Array}
|
|
89
101
|
* @param options {object}
|
|
90
102
|
* @param [options.contentType] {string} content-type for binary data
|
|
91
|
-
* @
|
|
103
|
+
* @param [options.ifMatch] {string} update only if the ETag matches
|
|
104
|
+
* @param [options.ifNoneMatch] {boolean} create only if absent
|
|
105
|
+
* @returns {Promise<{ etag?: string }>}
|
|
92
106
|
*/
|
|
93
107
|
put(resourceId: string, data: Json | Blob | Uint8Array, options?: {
|
|
94
108
|
contentType?: string;
|
|
95
|
-
|
|
109
|
+
ifMatch?: string;
|
|
110
|
+
ifNoneMatch?: boolean;
|
|
111
|
+
}): Promise<{
|
|
112
|
+
etag?: string;
|
|
113
|
+
}>;
|
|
96
114
|
/**
|
|
97
115
|
* Lists the items in the collection. Returns `null` if the collection is
|
|
98
116
|
* missing or not visible to you (404 conflation caveat).
|
|
@@ -158,6 +176,13 @@ export declare class Collection {
|
|
|
158
176
|
* you (404 conflation caveat). A server without backend support surfaces its
|
|
159
177
|
* 501 as `NotImplementedError`.
|
|
160
178
|
*
|
|
179
|
+
* The descriptor's optional `features` array advertises optional server
|
|
180
|
+
* affordances (e.g. `conditional-writes`, `blinded-index-query`,
|
|
181
|
+
* `chunked-streams`); an absent token means the backend makes no claim to it,
|
|
182
|
+
* so treat it as unsupported rather than assuming a default. (Client-side
|
|
183
|
+
* encryption is not a backend feature -- it is a per-collection client concern
|
|
184
|
+
* gated on the client's keys.)
|
|
185
|
+
*
|
|
161
186
|
* @returns {Promise<BackendDescriptor | null>}
|
|
162
187
|
*/
|
|
163
188
|
backend(): Promise<BackendDescriptor | null>;
|
package/dist/Collection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collection.d.ts","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Collection.d.ts","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAK1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,EACL,IAAI,EACJ,OAAO,EACP,cAAc,EACd,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAEnB,qBAAa,UAAU;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IAEnB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAO;IACpC,OAAO,CAAC,aAAa,CAAC,CAAwB;IAE9C;;;;;;;OAOG;gBACS,EACV,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACX,EAAE;QACD,OAAO,EAAE,aAAa,CAAA;QACtB,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,CAAC,EAAE,KAAK,CAAA;KACnB;IAOD,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,UAAU,GAErB;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM;IAOd;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAUvD;;;;;;;;OAQG;IACG,SAAS,CAAC,IAAI,EAAE;QACpB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,gBAAgB,CAAA;KAC3B,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqBlC;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAS7B;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,QAAQ;IAanE;;;;;;;;;OASG;IACG,GAAG,CACP,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,UAAU,EAC9B,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO,GACrC,OAAO,CAAC,SAAS,CAAC;IAgErB;;;;;;;OAOG;IACG,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAW1D;;;;;;;;;;;;OAYG;IACG,GAAG,CACP,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,UAAU,EAC9B,OAAO,GAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,OAAO,CAAA;KACjB,GACL,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAI7B;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAUrD;;;;;;OAMG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAU3D;;;;;;;OAOG;IACG,SAAS,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAUjD;;;;;OAKG;IACG,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAStD;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAKlC;;;;;;OAMG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IASlC;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAUxC;;;;;;;;;;;;;;OAcG;IACG,OAAO,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAUlD;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;CAS5C"}
|
package/dist/Collection.js
CHANGED
|
@@ -7,16 +7,18 @@
|
|
|
7
7
|
* (`add`/`get`/`put`/`list`, plus `resource(id)` for delete-by-id).
|
|
8
8
|
*/
|
|
9
9
|
import { collectionPath, collectionItems, collectionPolicy, collectionLinkset, collectionBackend, collectionQuota, resourcePath, toUrl } from './internal/paths.js';
|
|
10
|
-
import { prepareBody, parseResource } from './internal/content.js';
|
|
11
10
|
import { assertNotReserved } from './internal/reserved.js';
|
|
12
11
|
import { delegateGrant } from './internal/grant.js';
|
|
13
12
|
import { send } from './internal/request.js';
|
|
13
|
+
import { resolveCodec } from './internal/codec.js';
|
|
14
|
+
import { writeHeaders, readEtag } from './internal/conditional.js';
|
|
14
15
|
import { Resource } from './Resource.js';
|
|
15
16
|
export class Collection {
|
|
16
17
|
spaceId;
|
|
17
18
|
id;
|
|
18
19
|
_context;
|
|
19
20
|
_capability;
|
|
21
|
+
_codecPromise;
|
|
20
22
|
/**
|
|
21
23
|
* @param options {object}
|
|
22
24
|
* @param options.context {ClientContext} - Shared context (serverUrl, ezcap
|
|
@@ -37,6 +39,20 @@ export class Collection {
|
|
|
37
39
|
get _itemsPath() {
|
|
38
40
|
return collectionItems(this.spaceId, this.id);
|
|
39
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolves (once, then caches) the codec for this collection's reads and
|
|
44
|
+
* writes: the identity codec for a plaintext collection, or the encrypting
|
|
45
|
+
* codec when an `EncryptionProvider` is injected and supplies one for this
|
|
46
|
+
* collection (i.e. the client holds keys for it).
|
|
47
|
+
*
|
|
48
|
+
* @returns {Promise<ResourceCodec>}
|
|
49
|
+
*/
|
|
50
|
+
_codec() {
|
|
51
|
+
return (this._codecPromise ??= resolveCodec(this._context, {
|
|
52
|
+
spaceId: this.spaceId,
|
|
53
|
+
collectionId: this.id
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
40
56
|
/**
|
|
41
57
|
* Reads the Collection Description. Returns `null` if the collection is
|
|
42
58
|
* missing or not visible to you (WAS returns 404 for both not-found and
|
|
@@ -110,7 +126,10 @@ export class Collection {
|
|
|
110
126
|
spaceId: this.spaceId,
|
|
111
127
|
collectionId: this.id,
|
|
112
128
|
resourceId,
|
|
113
|
-
capability: options.capability ?? this._capability
|
|
129
|
+
capability: options.capability ?? this._capability,
|
|
130
|
+
// Share this collection's resolved codec so a resource handle does not
|
|
131
|
+
// repeat the backend() round-trip.
|
|
132
|
+
codec: () => this._codec()
|
|
114
133
|
});
|
|
115
134
|
}
|
|
116
135
|
/**
|
|
@@ -124,16 +143,45 @@ export class Collection {
|
|
|
124
143
|
* @returns {Promise<AddResult>}
|
|
125
144
|
*/
|
|
126
145
|
async add(data, options = {}) {
|
|
127
|
-
const
|
|
146
|
+
const codec = await this._codec();
|
|
147
|
+
const encoded = await codec.encode({
|
|
148
|
+
data,
|
|
149
|
+
contentType: options.contentType
|
|
150
|
+
});
|
|
151
|
+
// A codec may attach a create-if-absent precondition for its minted id (the
|
|
152
|
+
// EDV codec guards a fresh insert with `If-None-Match: *`); plaintext add
|
|
153
|
+
// carries none.
|
|
154
|
+
const headers = writeHeaders(encoded.contentType, {
|
|
155
|
+
ifMatch: encoded.ifMatch,
|
|
156
|
+
ifNoneMatch: encoded.ifNoneMatch
|
|
157
|
+
});
|
|
158
|
+
// A codec that mints its own id (e.g. the encrypting codec's EDV id) writes
|
|
159
|
+
// by `PUT`; the identity codec returns no id and lets the server mint one
|
|
160
|
+
// via `POST`.
|
|
161
|
+
if (encoded.id !== undefined) {
|
|
162
|
+
const path = resourcePath(this.spaceId, this.id, encoded.id);
|
|
163
|
+
const response = await send(this._context, {
|
|
164
|
+
path,
|
|
165
|
+
method: 'PUT',
|
|
166
|
+
capability: this._capability,
|
|
167
|
+
json: encoded.json,
|
|
168
|
+
body: encoded.body,
|
|
169
|
+
headers
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
id: encoded.id,
|
|
173
|
+
url: toUrl({ serverUrl: this._context.serverUrl, path }),
|
|
174
|
+
contentType: encoded.contentType,
|
|
175
|
+
etag: readEtag(response)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
128
178
|
const response = await send(this._context, {
|
|
129
179
|
path: this._itemsPath,
|
|
130
180
|
method: 'POST',
|
|
131
181
|
capability: this._capability,
|
|
132
|
-
json:
|
|
133
|
-
body:
|
|
134
|
-
headers
|
|
135
|
-
? { 'content-type': prepared.contentType }
|
|
136
|
-
: undefined
|
|
182
|
+
json: encoded.json,
|
|
183
|
+
body: encoded.body,
|
|
184
|
+
headers
|
|
137
185
|
});
|
|
138
186
|
// POST always returns a response (404/errors throw via send()).
|
|
139
187
|
const created = response.data;
|
|
@@ -145,7 +193,8 @@ export class Collection {
|
|
|
145
193
|
serverUrl: this._context.serverUrl,
|
|
146
194
|
path: resourcePath(this.spaceId, this.id, created.id)
|
|
147
195
|
}),
|
|
148
|
-
contentType: created['content-type']
|
|
196
|
+
contentType: created['content-type'],
|
|
197
|
+
etag: readEtag(response)
|
|
149
198
|
};
|
|
150
199
|
}
|
|
151
200
|
/**
|
|
@@ -157,25 +206,30 @@ export class Collection {
|
|
|
157
206
|
* @returns {Promise<Json | Blob | null>}
|
|
158
207
|
*/
|
|
159
208
|
async get(resourceId) {
|
|
209
|
+
const codec = await this._codec();
|
|
160
210
|
const response = await send(this._context, {
|
|
161
211
|
path: resourcePath(this.spaceId, this.id, resourceId),
|
|
162
212
|
method: 'GET',
|
|
163
213
|
capability: this._capability,
|
|
164
214
|
read: true
|
|
165
215
|
});
|
|
166
|
-
return
|
|
216
|
+
return response === null ? null : codec.decode(response);
|
|
167
217
|
}
|
|
168
218
|
/**
|
|
169
|
-
* Creates or replaces a resource by id (upsert).
|
|
219
|
+
* Creates or replaces a resource by id (upsert). Forwards the conditional-write
|
|
220
|
+
* options (`ifMatch` / `ifNoneMatch`) to `Resource.put`; see it for the
|
|
221
|
+
* `conditional-writes` semantics. Returns the stored resource's new `etag`.
|
|
170
222
|
*
|
|
171
223
|
* @param resourceId {string}
|
|
172
224
|
* @param data {Json | Blob | Uint8Array}
|
|
173
225
|
* @param options {object}
|
|
174
226
|
* @param [options.contentType] {string} content-type for binary data
|
|
175
|
-
* @
|
|
227
|
+
* @param [options.ifMatch] {string} update only if the ETag matches
|
|
228
|
+
* @param [options.ifNoneMatch] {boolean} create only if absent
|
|
229
|
+
* @returns {Promise<{ etag?: string }>}
|
|
176
230
|
*/
|
|
177
231
|
async put(resourceId, data, options = {}) {
|
|
178
|
-
|
|
232
|
+
return this.resource(resourceId).put(data, options);
|
|
179
233
|
}
|
|
180
234
|
/**
|
|
181
235
|
* Lists the items in the collection. Returns `null` if the collection is
|
|
@@ -292,6 +346,13 @@ export class Collection {
|
|
|
292
346
|
* you (404 conflation caveat). A server without backend support surfaces its
|
|
293
347
|
* 501 as `NotImplementedError`.
|
|
294
348
|
*
|
|
349
|
+
* The descriptor's optional `features` array advertises optional server
|
|
350
|
+
* affordances (e.g. `conditional-writes`, `blinded-index-query`,
|
|
351
|
+
* `chunked-streams`); an absent token means the backend makes no claim to it,
|
|
352
|
+
* so treat it as unsupported rather than assuming a default. (Client-side
|
|
353
|
+
* encryption is not a backend feature -- it is a per-collection client concern
|
|
354
|
+
* gated on the client's keys.)
|
|
355
|
+
*
|
|
295
356
|
* @returns {Promise<BackendDescriptor | null>}
|
|
296
357
|
*/
|
|
297
358
|
async backend() {
|
package/dist/Collection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collection.js","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;GAIG;AACH,OAAO,EACL,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,KAAK,EACN,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Collection.js","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"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"}
|
package/dist/Resource.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClientContext } from './internal/request.js';
|
|
2
|
+
import type { ResourceCodec } from './codec.js';
|
|
2
3
|
import type { IZcap, Json, PolicyDocument, ResourceMetadata, ResourceMetadataCustom } from './types.js';
|
|
3
4
|
export declare class Resource {
|
|
4
5
|
readonly spaceId: string;
|
|
@@ -6,6 +7,8 @@ export declare class Resource {
|
|
|
6
7
|
readonly id: string;
|
|
7
8
|
private readonly _context;
|
|
8
9
|
private readonly _capability?;
|
|
10
|
+
private readonly _codecThunk?;
|
|
11
|
+
private _codecPromise?;
|
|
9
12
|
/**
|
|
10
13
|
* @param options {object}
|
|
11
14
|
* @param options.context {ClientContext}
|
|
@@ -13,15 +16,28 @@ export declare class Resource {
|
|
|
13
16
|
* @param options.collectionId {string}
|
|
14
17
|
* @param options.resourceId {string}
|
|
15
18
|
* @param [options.capability] {IZcap} capability attached to every request
|
|
19
|
+
* @param [options.codec] {function} resolver sharing the parent collection's
|
|
20
|
+
* codec, so a resource handle obtained via `collection.resource(id)` does
|
|
21
|
+
* not repeat the backend() round-trip. A standalone resource resolves its
|
|
22
|
+
* own.
|
|
16
23
|
*/
|
|
17
|
-
constructor({ context, spaceId, collectionId, resourceId, capability }: {
|
|
24
|
+
constructor({ context, spaceId, collectionId, resourceId, capability, codec }: {
|
|
18
25
|
context: ClientContext;
|
|
19
26
|
spaceId: string;
|
|
20
27
|
collectionId: string;
|
|
21
28
|
resourceId: string;
|
|
22
29
|
capability?: IZcap;
|
|
30
|
+
codec?: () => Promise<ResourceCodec>;
|
|
23
31
|
});
|
|
24
32
|
private get _path();
|
|
33
|
+
/**
|
|
34
|
+
* Resolves (once, then caches) the codec for this resource: the parent
|
|
35
|
+
* collection's shared codec when this handle came from
|
|
36
|
+
* `collection.resource(id)`, otherwise one resolved for its own collection.
|
|
37
|
+
*
|
|
38
|
+
* @returns {Promise<ResourceCodec>}
|
|
39
|
+
*/
|
|
40
|
+
private _codec;
|
|
25
41
|
/**
|
|
26
42
|
* Reads the resource, auto-parsing JSON to an object and returning binary as
|
|
27
43
|
* a `Blob`. Returns `null` if the resource is missing or not visible to you
|
|
@@ -32,14 +48,18 @@ export declare class Resource {
|
|
|
32
48
|
get(): Promise<Json | Blob | null>;
|
|
33
49
|
/**
|
|
34
50
|
* Reads the resource body as text. Returns `null` on a missing/unauthorized
|
|
35
|
-
* resource (404 conflation caveat).
|
|
51
|
+
* resource (404 conflation caveat). A raw escape hatch: it does NOT run the
|
|
52
|
+
* codec, so on an encrypted collection it never decrypts -- use `get()` to
|
|
53
|
+
* decrypt.
|
|
36
54
|
*
|
|
37
55
|
* @returns {Promise<string | null>}
|
|
38
56
|
*/
|
|
39
57
|
getText(): Promise<string | null>;
|
|
40
58
|
/**
|
|
41
59
|
* Reads the resource body as raw bytes. Returns `null` on a
|
|
42
|
-
* missing/unauthorized resource (404 conflation caveat).
|
|
60
|
+
* missing/unauthorized resource (404 conflation caveat). A raw escape hatch:
|
|
61
|
+
* it does NOT run the codec, so on an encrypted collection it never decrypts
|
|
62
|
+
* -- use `get()` to decrypt.
|
|
43
63
|
*
|
|
44
64
|
* @returns {Promise<Uint8Array | null>}
|
|
45
65
|
*/
|
|
@@ -55,20 +75,39 @@ export declare class Resource {
|
|
|
55
75
|
* `text/html`. An unrecognized/absent extension sends no content-type, and the
|
|
56
76
|
* server applies its own required-`Content-Type` rule.
|
|
57
77
|
*
|
|
78
|
+
* Conditional writes (the backend's `conditional-writes` feature): pass
|
|
79
|
+
* `ifMatch` (the ETag from a prior read/write) for an update-if-unchanged, or
|
|
80
|
+
* `ifNoneMatch: true` for a create-if-absent. A failed precondition throws
|
|
81
|
+
* `PreconditionFailedError` (412). On an encrypted collection these are managed
|
|
82
|
+
* automatically by the codec (the EDV `sequence` becomes the enforced ETag), so
|
|
83
|
+
* the explicit options are for plaintext collections. Returns the new `etag`.
|
|
84
|
+
*
|
|
58
85
|
* @param data {Json | Blob | Uint8Array}
|
|
59
86
|
* @param options {object}
|
|
60
87
|
* @param [options.contentType] {string} content-type for binary data
|
|
61
|
-
* @
|
|
88
|
+
* @param [options.ifMatch] {string} update only if the ETag matches
|
|
89
|
+
* @param [options.ifNoneMatch] {boolean} create only if absent
|
|
90
|
+
* @returns {Promise<{ etag?: string }>} the stored resource's new ETag
|
|
62
91
|
*/
|
|
63
92
|
put(data: Json | Blob | Uint8Array, options?: {
|
|
64
93
|
contentType?: string;
|
|
65
|
-
|
|
94
|
+
ifMatch?: string;
|
|
95
|
+
ifNoneMatch?: boolean;
|
|
96
|
+
}): Promise<{
|
|
97
|
+
etag?: string;
|
|
98
|
+
}>;
|
|
66
99
|
/**
|
|
67
|
-
* Deletes the resource. Idempotent.
|
|
100
|
+
* Deletes the resource. Idempotent. Pass `ifMatch` (the backend's
|
|
101
|
+
* `conditional-writes` feature) to delete only if the resource's current ETag
|
|
102
|
+
* matches; a stale validator throws `PreconditionFailedError` (412).
|
|
68
103
|
*
|
|
104
|
+
* @param options {object}
|
|
105
|
+
* @param [options.ifMatch] {string} delete only if the ETag matches
|
|
69
106
|
* @returns {Promise<void>}
|
|
70
107
|
*/
|
|
71
|
-
delete(
|
|
108
|
+
delete(options?: {
|
|
109
|
+
ifMatch?: string;
|
|
110
|
+
}): Promise<void>;
|
|
72
111
|
private get _metaPath();
|
|
73
112
|
/**
|
|
74
113
|
* Reads the resource's metadata object (server-managed `contentType` / `size`
|
|
@@ -76,9 +115,15 @@ export declare class Resource {
|
|
|
76
115
|
* resource is missing or not visible to you (404 conflation caveat). A server
|
|
77
116
|
* without metadata support surfaces its 501 as `NotImplementedError`.
|
|
78
117
|
*
|
|
79
|
-
*
|
|
118
|
+
* Against a backend with the `conditional-writes` feature the result also
|
|
119
|
+
* carries the resource's current `etag` (the strong validator) -- pass it as
|
|
120
|
+
* `put(data, { ifMatch })` for a lost-update-safe update.
|
|
121
|
+
*
|
|
122
|
+
* @returns {Promise<(ResourceMetadata & { etag?: string }) | null>}
|
|
80
123
|
*/
|
|
81
|
-
meta(): Promise<ResourceMetadata
|
|
124
|
+
meta(): Promise<(ResourceMetadata & {
|
|
125
|
+
etag?: string;
|
|
126
|
+
}) | null>;
|
|
82
127
|
/**
|
|
83
128
|
* Replaces the resource's user-writable metadata (`custom`). This is a full
|
|
84
129
|
* replacement: any property omitted from `custom` is cleared, and an omitted
|
|
@@ -86,6 +131,10 @@ export declare class Resource {
|
|
|
86
131
|
* metadata of a nonexistent resource throws `NotFoundError`. Servers without
|
|
87
132
|
* metadata support surface their 501 as `NotImplementedError`.
|
|
88
133
|
*
|
|
134
|
+
* On an encrypted collection this throws a `ValidationError`: `custom`
|
|
135
|
+
* (`name` / `tags`) would be stored as server-visible plaintext, defeating the
|
|
136
|
+
* encryption. Carry those values inside the encrypted content instead.
|
|
137
|
+
*
|
|
89
138
|
* @param meta {object}
|
|
90
139
|
* @param [meta.custom] {ResourceMetadataCustom} the user-writable properties
|
|
91
140
|
* @returns {Promise<void>}
|
package/dist/Resource.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"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"}
|