@interop/was-client 0.65.0 → 0.66.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 +29 -22
- package/dist/Collection.d.ts +23 -1
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +17 -2
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +7 -3
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +18 -8
- package/dist/Resource.js.map +1 -1
- package/dist/WasClient.d.ts.map +1 -1
- package/dist/WasClient.js +5 -1
- package/dist/WasClient.js.map +1 -1
- package/dist/codec.d.ts +6 -5
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/codec.js.map +1 -1
- package/dist/edv/EdvCodec.d.ts.map +1 -1
- package/dist/edv/EdvCodec.js +3 -2
- package/dist/edv/EdvCodec.js.map +1 -1
- package/dist/edv/descriptorStore.d.ts +14 -11
- package/dist/edv/descriptorStore.d.ts.map +1 -1
- package/dist/edv/descriptorStore.js +7 -5
- package/dist/edv/descriptorStore.js.map +1 -1
- package/dist/edv/docCipher.d.ts +11 -1
- package/dist/edv/docCipher.d.ts.map +1 -1
- package/dist/edv/docCipher.js +24 -6
- package/dist/edv/docCipher.js.map +1 -1
- package/dist/edv/logGovernedDescriptorStore.d.ts.map +1 -1
- package/dist/edv/logGovernedDescriptorStore.js +5 -2
- package/dist/edv/logGovernedDescriptorStore.js.map +1 -1
- package/dist/edv/refreshingDocCipher.d.ts +4 -1
- package/dist/edv/refreshingDocCipher.d.ts.map +1 -1
- package/dist/edv/refreshingDocCipher.js +7 -4
- package/dist/edv/refreshingDocCipher.js.map +1 -1
- package/dist/errors.d.ts +17 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +20 -1
- package/dist/errors.js.map +1 -1
- package/dist/internal/cas.d.ts +14 -2
- package/dist/internal/cas.d.ts.map +1 -1
- package/dist/internal/cas.js +21 -2
- package/dist/internal/cas.js.map +1 -1
- package/dist/internal/conditional.d.ts +69 -2
- package/dist/internal/conditional.d.ts.map +1 -1
- package/dist/internal/conditional.js +81 -1
- package/dist/internal/conditional.js.map +1 -1
- package/dist/internal/features.d.ts +9 -3
- package/dist/internal/features.d.ts.map +1 -1
- package/dist/internal/features.js +33 -4
- package/dist/internal/features.js.map +1 -1
- package/dist/internal/meta.d.ts +20 -2
- package/dist/internal/meta.d.ts.map +1 -1
- package/dist/internal/meta.js +30 -4
- package/dist/internal/meta.js.map +1 -1
- package/dist/internal/request.d.ts +10 -0
- package/dist/internal/request.d.ts.map +1 -1
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/write.d.ts +9 -2
- package/dist/internal/write.d.ts.map +1 -1
- package/dist/internal/write.js +15 -3
- package/dist/internal/write.js.map +1 -1
- package/dist/log/logStore.d.ts +11 -5
- package/dist/log/logStore.d.ts.map +1 -1
- package/dist/log/logStore.js +18 -5
- package/dist/log/logStore.js.map +1 -1
- package/dist/sync/index.d.ts +8 -5
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +8 -5
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/plaintextCipher.d.ts +6 -4
- package/dist/sync/plaintextCipher.d.ts.map +1 -1
- package/dist/sync/plaintextCipher.js +19 -6
- package/dist/sync/plaintextCipher.js.map +1 -1
- package/dist/sync/port.d.ts +7 -1
- package/dist/sync/port.d.ts.map +1 -1
- package/dist/sync/port.js +18 -2
- package/dist/sync/port.js.map +1 -1
- package/dist/sync/predicates.d.ts +14 -3
- package/dist/sync/predicates.d.ts.map +1 -1
- package/dist/sync/predicates.js +16 -3
- package/dist/sync/predicates.js.map +1 -1
- package/dist/sync/types.d.ts +21 -1
- package/dist/sync/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/internal/meta.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { WasServerError } from '../errors.js';
|
|
16
16
|
import { compareAndSwap } from './cas.js';
|
|
17
17
|
import { send } from './request.js';
|
|
18
|
-
import { readEtag, writeHeaders } from './conditional.js';
|
|
18
|
+
import { assertPreconditionEnforced, preconditionsEnforced, readEtag, writeHeaders } from './conditional.js';
|
|
19
19
|
import { withCodec } from './withCodec.js';
|
|
20
20
|
/**
|
|
21
21
|
* Reads a metadata document and decodes its user-writable `custom` value.
|
|
@@ -93,12 +93,22 @@ export async function readMeta(context, { metaPath, codec: codecPromise, subject
|
|
|
93
93
|
* properties, as a full replacement
|
|
94
94
|
* @param options.slot {MetaWriteSlot} the `meta` slot being written, which
|
|
95
95
|
* an encrypting codec binds into the envelope
|
|
96
|
+
* @param options.features {FeatureProbe} the handle's backend-feature probe.
|
|
97
|
+
* A Resource's metadata validator is a Resource-level validator, so a named
|
|
98
|
+
* precondition is refused when the backend advertises no `conditional-writes`
|
|
99
|
+
* (unlike the Collection Metadata object's `metaVersion`, which a server
|
|
100
|
+
* maintains regardless and `Collection.setMeta` therefore does not gate)
|
|
96
101
|
* @param [options.ifMatch] {string} update only if the `meta` ETag matches
|
|
97
102
|
* @param [options.ifNoneMatch] {boolean} write only if no metadata is set
|
|
98
103
|
* @param [options.capability] {IZcap}
|
|
99
104
|
* @returns {Promise<{ etag?: string }>} the metadata's new ETag
|
|
100
105
|
*/
|
|
101
|
-
export async function writeMeta(context, { metaPath, codec: codecPromise, custom, slot, ifMatch, ifNoneMatch, capability }) {
|
|
106
|
+
export async function writeMeta(context, { metaPath, codec: codecPromise, custom, slot, features, ifMatch, ifNoneMatch, capability }) {
|
|
107
|
+
await assertPreconditionEnforced({
|
|
108
|
+
features,
|
|
109
|
+
precondition: { ifMatch, ifNoneMatch },
|
|
110
|
+
operation: `Cannot write the metadata at "${metaPath}"`
|
|
111
|
+
});
|
|
102
112
|
const codec = await codecPromise;
|
|
103
113
|
const { custom: encoded } = await codec.encodeMeta({ custom, slot });
|
|
104
114
|
const response = await send(context, {
|
|
@@ -126,21 +136,34 @@ export async function writeMeta(context, { metaPath, codec: codecPromise, custom
|
|
|
126
136
|
* alike, so a concurrent `configure` -- or an epoch rotation -- legitimately
|
|
127
137
|
* invalidates an in-flight annotation write.
|
|
128
138
|
*
|
|
139
|
+
* `features` is the Resource side's: a Resource's metadata validator is
|
|
140
|
+
* gated on `conditional-writes`, so on a backend that advertises none the read
|
|
141
|
+
* reports no validator and the loop takes its `allowUnconditional` path -- the
|
|
142
|
+
* same last-write-wins update a backend serving no validator at all gets. That
|
|
143
|
+
* keeps `setName` / `setTags` working there rather than refusing, which is what
|
|
144
|
+
* `setMeta` does for a precondition the caller named itself. The Collection
|
|
145
|
+
* side passes none: its `metaVersion` is maintained regardless of the backend
|
|
146
|
+
* feature, so its pin always stands.
|
|
147
|
+
*
|
|
129
148
|
* @param handle {object} the Collection or Resource handle to patch
|
|
130
149
|
* @param patch {ResourceMetadataCustom} the properties to merge over the
|
|
131
150
|
* current `custom`
|
|
132
151
|
* @param operation {string} what the caller is doing, for the exhaustion
|
|
133
152
|
* error (e.g. `Metadata update`)
|
|
153
|
+
* @param [features] {FeatureProbe} the handle's backend-feature probe, when
|
|
154
|
+
* its metadata validator is gated on `conditional-writes`
|
|
134
155
|
* @returns {Promise<void>}
|
|
135
156
|
*/
|
|
136
|
-
export async function patchCustom(handle, patch, operation = 'Metadata update') {
|
|
157
|
+
export async function patchCustom(handle, patch, operation = 'Metadata update', features) {
|
|
137
158
|
await compareAndSwap({
|
|
138
159
|
store: {
|
|
139
160
|
read: async () => {
|
|
140
161
|
const current = await handle.meta();
|
|
162
|
+
const pinnable = features === undefined || (await preconditionsEnforced(features));
|
|
163
|
+
const etag = pinnable ? current?.etag : undefined;
|
|
141
164
|
return {
|
|
142
165
|
value: current?.custom ?? {},
|
|
143
|
-
...(
|
|
166
|
+
...(etag !== undefined && { etag })
|
|
144
167
|
};
|
|
145
168
|
},
|
|
146
169
|
replace: async (custom, { ifMatch }) => {
|
|
@@ -148,6 +171,9 @@ export async function patchCustom(handle, patch, operation = 'Metadata update')
|
|
|
148
171
|
}
|
|
149
172
|
},
|
|
150
173
|
operation,
|
|
174
|
+
// A handle's name and tags stay writable on a backend that serves no
|
|
175
|
+
// metadata validator; the write is then last-write-wins.
|
|
176
|
+
allowUnconditional: true,
|
|
151
177
|
mutate: custom => ({ ...custom, ...patch })
|
|
152
178
|
});
|
|
153
179
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type { ZcapClient } from '@interop/ezcap';
|
|
14
14
|
import type { HttpResponse } from '@interop/http-client';
|
|
15
15
|
import type { EncryptionProvider } from '../codec.js';
|
|
16
|
+
import type { BackendFeatures } from './features.js';
|
|
16
17
|
import type { IZcap, RequestInput, ServiceInfo } from '../types.js';
|
|
17
18
|
/**
|
|
18
19
|
* The shared context threaded through every handle: the server base URL, the
|
|
@@ -27,6 +28,15 @@ export interface ClientContext {
|
|
|
27
28
|
controllerDid: string;
|
|
28
29
|
encryption?: EncryptionProvider;
|
|
29
30
|
service: () => Promise<ServiceInfo>;
|
|
31
|
+
/**
|
|
32
|
+
* The client's shared backend-feature probes, keyed by descriptor request
|
|
33
|
+
* (collection path plus bound capability id). Handles built separately --
|
|
34
|
+
* `fromCapability` per resource, `collection(id)` in a loop -- then share one
|
|
35
|
+
* `GET .../backend` instead of repeating it per handle. Optional: a context
|
|
36
|
+
* assembled without one (a test fixture, `WasTransport`'s own requester)
|
|
37
|
+
* simply builds an unshared probe per handle, as before.
|
|
38
|
+
*/
|
|
39
|
+
backendFeatures?: Map<string, BackendFeatures>;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* A single signed request: the public `RequestInput` shape (either `path`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAKxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAKxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,UAAU,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACnC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CAC/C;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAYD;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,CAAC,CAcvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC,CAMnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA4B/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAe9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,OAAO,EAAE,aAAa,EACtB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACzD,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,aAAa,EACtB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACzD,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAY5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/write.d.ts
CHANGED
|
@@ -154,6 +154,13 @@ export declare function insertResource(context: ClientContext, { itemsPath, path
|
|
|
154
154
|
* masked-404 insert would silently overwrite the existing document and reset
|
|
155
155
|
* its sequence. The insert-after-null-pre-read is therefore refused (fail
|
|
156
156
|
* closed) unless the backend advertises the feature.
|
|
157
|
+
* - A caller's named precondition is refused with `NotSupportedError` when the
|
|
158
|
+
* backend descriptor was read and advertises no `conditional-writes`,
|
|
159
|
+
* whatever the collection's codec. A backend that ignores `If-Match` would
|
|
160
|
+
* otherwise turn the caller's compare-and-swap into a silent overwrite. This
|
|
161
|
+
* is the one gate every guarded write through a handle passes, so the stores
|
|
162
|
+
* layered over `Resource.put` (the resource log, the descriptor stores) do
|
|
163
|
+
* not repeat it.
|
|
157
164
|
*
|
|
158
165
|
* @param context {ClientContext}
|
|
159
166
|
* @param options {object}
|
|
@@ -162,8 +169,8 @@ export declare function insertResource(context: ClientContext, { itemsPath, path
|
|
|
162
169
|
* @param options.id {string} the resource id
|
|
163
170
|
* @param options.data {ResourceData} the plaintext value
|
|
164
171
|
* @param options.features {FeatureProbe} the handle's shared
|
|
165
|
-
* `BackendFeatures` probe; consulted
|
|
166
|
-
* insert-after-null-pre-read
|
|
172
|
+
* `BackendFeatures` probe; consulted for a named precondition and for a
|
|
173
|
+
* conditional codec's insert-after-null-pre-read
|
|
167
174
|
* @param [options.contentType] {string} caller-supplied content type
|
|
168
175
|
* @param [options.capability] {IZcap}
|
|
169
176
|
* @param [options.precondition] {WritePrecondition} the caller's explicit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACd,MAAM,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/write.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isChunkedWrite } from '../codec.js';
|
|
2
2
|
import { PreconditionFailedError, ValidationError } from '../errors.js';
|
|
3
3
|
import { send } from './request.js';
|
|
4
|
-
import { assertPreconditionAgainstPreRead, assertSinglePrecondition, encodedPrecondition, writeHeaders, namedPrecondition } from './conditional.js';
|
|
4
|
+
import { assertPreconditionAgainstPreRead, assertPreconditionEnforced, assertSinglePrecondition, encodedPrecondition, writeHeaders, namedPrecondition } from './conditional.js';
|
|
5
5
|
/**
|
|
6
6
|
* Sends an encoded write (`PUT`/`POST`) to a resource path, applying the
|
|
7
7
|
* encoded body (`json` or `body`), its content-type, and the conditional-write
|
|
@@ -146,6 +146,13 @@ export async function insertResource(context, { itemsPath, pathForId, codec, dat
|
|
|
146
146
|
* masked-404 insert would silently overwrite the existing document and reset
|
|
147
147
|
* its sequence. The insert-after-null-pre-read is therefore refused (fail
|
|
148
148
|
* closed) unless the backend advertises the feature.
|
|
149
|
+
* - A caller's named precondition is refused with `NotSupportedError` when the
|
|
150
|
+
* backend descriptor was read and advertises no `conditional-writes`,
|
|
151
|
+
* whatever the collection's codec. A backend that ignores `If-Match` would
|
|
152
|
+
* otherwise turn the caller's compare-and-swap into a silent overwrite. This
|
|
153
|
+
* is the one gate every guarded write through a handle passes, so the stores
|
|
154
|
+
* layered over `Resource.put` (the resource log, the descriptor stores) do
|
|
155
|
+
* not repeat it.
|
|
149
156
|
*
|
|
150
157
|
* @param context {ClientContext}
|
|
151
158
|
* @param options {object}
|
|
@@ -154,8 +161,8 @@ export async function insertResource(context, { itemsPath, pathForId, codec, dat
|
|
|
154
161
|
* @param options.id {string} the resource id
|
|
155
162
|
* @param options.data {ResourceData} the plaintext value
|
|
156
163
|
* @param options.features {FeatureProbe} the handle's shared
|
|
157
|
-
* `BackendFeatures` probe; consulted
|
|
158
|
-
* insert-after-null-pre-read
|
|
164
|
+
* `BackendFeatures` probe; consulted for a named precondition and for a
|
|
165
|
+
* conditional codec's insert-after-null-pre-read
|
|
159
166
|
* @param [options.contentType] {string} caller-supplied content type
|
|
160
167
|
* @param [options.capability] {IZcap}
|
|
161
168
|
* @param [options.precondition] {WritePrecondition} the caller's explicit
|
|
@@ -168,6 +175,11 @@ export async function upsertResource(context, { path, codec, id, data, features,
|
|
|
168
175
|
// Checked before the pre-read, whose comparison would otherwise answer the
|
|
169
176
|
// pair with a 412 either way.
|
|
170
177
|
assertSinglePrecondition(precondition);
|
|
178
|
+
await assertPreconditionEnforced({
|
|
179
|
+
features,
|
|
180
|
+
precondition,
|
|
181
|
+
operation: `Cannot write the resource at "${path}"`
|
|
182
|
+
});
|
|
171
183
|
let current;
|
|
172
184
|
if (codec.conditionalWrites) {
|
|
173
185
|
current = await send(context, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"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"}
|
package/dist/log/logStore.d.ts
CHANGED
|
@@ -19,11 +19,17 @@
|
|
|
19
19
|
* document under a human-readable id. A Collection's history log is never
|
|
20
20
|
* encrypted and runs no codec: the server reads its head itself.
|
|
21
21
|
*
|
|
22
|
-
* Both the append and the create
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* Both the append and the create depend on their precondition being enforced --
|
|
23
|
+
* the profile requires it (without it, concurrent appends silently overwrite
|
|
24
|
+
* one another instead of failing into the caller's rebase-and-retry loop). On
|
|
25
|
+
* a Resource host that is the backend's `conditional-writes` feature, and
|
|
26
|
+
* `Resource.put` refuses the write before it is sent when the backend was read
|
|
27
|
+
* and does not advertise it. A Collection's history log carries its own
|
|
28
|
+
* validator, which a server implementing the sub-resource honors whether or
|
|
29
|
+
* not the backend advertises the feature, so nothing gates that host. Either
|
|
30
|
+
* way an append is refused when the read it extends returned no validator.
|
|
31
|
+
* A lost race -- a stale `ifMatch`, or a guarded create against a log that
|
|
32
|
+
* already exists -- is rethrown as the library's
|
|
27
33
|
* `ResourceLogConflictError` with the transport's `PreconditionFailedError`
|
|
28
34
|
* as `cause`, which is the port's one conflict signal and what the library's
|
|
29
35
|
* rebase loop catches (by `name` rather than `instanceof`, since the error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logStore.d.ts","sourceRoot":"","sources":["../../src/log/logStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"logStore.d.ts","sourceRoot":"","sources":["../../src/log/logStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C,OAAO,EAAW,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAElE,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAwD3B;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EACH;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,CAAA;CAAE,GAC9C;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GACnD,gBAAgB,CAgGlB"}
|
package/dist/log/logStore.js
CHANGED
|
@@ -19,11 +19,17 @@
|
|
|
19
19
|
* document under a human-readable id. A Collection's history log is never
|
|
20
20
|
* encrypted and runs no codec: the server reads its head itself.
|
|
21
21
|
*
|
|
22
|
-
* Both the append and the create
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* Both the append and the create depend on their precondition being enforced --
|
|
23
|
+
* the profile requires it (without it, concurrent appends silently overwrite
|
|
24
|
+
* one another instead of failing into the caller's rebase-and-retry loop). On
|
|
25
|
+
* a Resource host that is the backend's `conditional-writes` feature, and
|
|
26
|
+
* `Resource.put` refuses the write before it is sent when the backend was read
|
|
27
|
+
* and does not advertise it. A Collection's history log carries its own
|
|
28
|
+
* validator, which a server implementing the sub-resource honors whether or
|
|
29
|
+
* not the backend advertises the feature, so nothing gates that host. Either
|
|
30
|
+
* way an append is refused when the read it extends returned no validator.
|
|
31
|
+
* A lost race -- a stale `ifMatch`, or a guarded create against a log that
|
|
32
|
+
* already exists -- is rethrown as the library's
|
|
27
33
|
* `ResourceLogConflictError` with the transport's `PreconditionFailedError`
|
|
28
34
|
* as `cause`, which is the port's one conflict signal and what the library's
|
|
29
35
|
* rebase loop catches (by `name` rather than `instanceof`, since the error
|
|
@@ -31,6 +37,7 @@
|
|
|
31
37
|
*/
|
|
32
38
|
import { ResourceLogConflictError, parseResourceLog, serializeResourceLog, serializeResourceLogEntry } from '@interop/vh-resource-log';
|
|
33
39
|
import { PreconditionFailedError, ValidationError } from '../errors.js';
|
|
40
|
+
import { unenforcedPreconditionError } from '../internal/conditional.js';
|
|
34
41
|
import { ENCODER, LOG_CONTENT_TYPE } from '../internal/content.js';
|
|
35
42
|
export { LOG_CONTENT_TYPE };
|
|
36
43
|
/**
|
|
@@ -122,6 +129,12 @@ export function resourceLogStore(options) {
|
|
|
122
129
|
throw new ValidationError('Cannot append to resource log: append must follow a read on the ' +
|
|
123
130
|
'same store instance.');
|
|
124
131
|
}
|
|
132
|
+
if (ifMatch === undefined) {
|
|
133
|
+
throw unenforcedPreconditionError({
|
|
134
|
+
operation: 'Cannot append to the resource log',
|
|
135
|
+
reason: 'no-validator'
|
|
136
|
+
});
|
|
137
|
+
}
|
|
125
138
|
const separator = lastReadBody.endsWith('\n') ? '' : '\n';
|
|
126
139
|
const extended = lastReadBody + separator + serializeResourceLogEntry(entry) + '\n';
|
|
127
140
|
await putOrConflict({
|
package/dist/log/logStore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logStore.js","sourceRoot":"","sources":["../../src/log/logStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"logStore.js","sourceRoot":"","sources":["../../src/log/logStore.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/index.d.ts
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* Collection provisioning, and its Space half alone (ensure the Space once,
|
|
18
18
|
* then thread the returned description through every collection).
|
|
19
19
|
* - `isSyncConflictError` / `isSyncNotFoundError` / `isSyncAuthError` /
|
|
20
|
-
* `isUnknownEpochError`
|
|
20
|
+
* `isUnknownEpochError` / `isKeyUnwrapError` / `isIntegrityError` -- the
|
|
21
|
+
* classification contract for the signals
|
|
21
22
|
* below. A consumer matches by `err.name` and never with `instanceof`,
|
|
22
23
|
* because every one of these errors is raised inside a seam the app injects
|
|
23
24
|
* (the port, the caller's `DocCipher`) and that seam can resolve to a second
|
|
@@ -33,8 +34,10 @@
|
|
|
33
34
|
* signal (`UnknownEpochError`: the envelope's epoch is not on the descriptor at
|
|
34
35
|
* all, so re-read it and rebuild the cipher) and the membership signal
|
|
35
36
|
* (`KeyUnwrapError`: the epoch is on the descriptor but this reader holds no
|
|
36
|
-
* key for it, so a refresh cannot help).
|
|
37
|
-
*
|
|
37
|
+
* key for it, so a refresh cannot help). So is the tamper signal
|
|
38
|
+
* (`IntegrityError`: the stored body does not verify against the resource id
|
|
39
|
+
* it was read under). `EncryptionError`, the fail-closed umbrella both
|
|
40
|
+
* `KeyUnwrapError` and `IntegrityError` fall under, rides along. The classes are exported
|
|
38
41
|
* for construction and for a caller inside one resolved copy; across a package
|
|
39
42
|
* boundary the predicates are the contract
|
|
40
43
|
* (`decisions/0001-cross-package-errors-match-by-name.md`).
|
|
@@ -45,7 +48,7 @@ export { contentCid, cidFrom, deriveSpaceId } from './cid.js';
|
|
|
45
48
|
export { isEncryptedEnvelope } from './envelope.js';
|
|
46
49
|
export { createPlaintextDocCipher } from './plaintextCipher.js';
|
|
47
50
|
export { ensureSpace, ensureSpaceAndCollection } from './provisioning.js';
|
|
48
|
-
export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isKeyUnwrapError, isUnknownEpochError } from './predicates.js';
|
|
49
|
-
export { EncryptionError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
|
|
51
|
+
export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isIntegrityError, isKeyUnwrapError, isUnknownEpochError } from './predicates.js';
|
|
52
|
+
export { EncryptionError, IntegrityError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
|
|
50
53
|
export type { Json, SyncCheckpoint, WireDoc, SyncPage, MasterState, WriteAck, SyncStatus, WasSyncPort, DocCipher } from './types.js';
|
|
51
54
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/sync/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAI1E,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,IAAI,EACJ,cAAc,EACd,OAAO,EACP,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACX,SAAS,EACV,MAAM,YAAY,CAAA"}
|
package/dist/sync/index.js
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* Collection provisioning, and its Space half alone (ensure the Space once,
|
|
18
18
|
* then thread the returned description through every collection).
|
|
19
19
|
* - `isSyncConflictError` / `isSyncNotFoundError` / `isSyncAuthError` /
|
|
20
|
-
* `isUnknownEpochError`
|
|
20
|
+
* `isUnknownEpochError` / `isKeyUnwrapError` / `isIntegrityError` -- the
|
|
21
|
+
* classification contract for the signals
|
|
21
22
|
* below. A consumer matches by `err.name` and never with `instanceof`,
|
|
22
23
|
* because every one of these errors is raised inside a seam the app injects
|
|
23
24
|
* (the port, the caller's `DocCipher`) and that seam can resolve to a second
|
|
@@ -33,8 +34,10 @@
|
|
|
33
34
|
* signal (`UnknownEpochError`: the envelope's epoch is not on the descriptor at
|
|
34
35
|
* all, so re-read it and rebuild the cipher) and the membership signal
|
|
35
36
|
* (`KeyUnwrapError`: the epoch is on the descriptor but this reader holds no
|
|
36
|
-
* key for it, so a refresh cannot help).
|
|
37
|
-
*
|
|
37
|
+
* key for it, so a refresh cannot help). So is the tamper signal
|
|
38
|
+
* (`IntegrityError`: the stored body does not verify against the resource id
|
|
39
|
+
* it was read under). `EncryptionError`, the fail-closed umbrella both
|
|
40
|
+
* `KeyUnwrapError` and `IntegrityError` fall under, rides along. The classes are exported
|
|
38
41
|
* for construction and for a caller inside one resolved copy; across a package
|
|
39
42
|
* boundary the predicates are the contract
|
|
40
43
|
* (`decisions/0001-cross-package-errors-match-by-name.md`).
|
|
@@ -48,6 +51,6 @@ export { contentCid, cidFrom, deriveSpaceId } from './cid.js';
|
|
|
48
51
|
export { isEncryptedEnvelope } from './envelope.js';
|
|
49
52
|
export { createPlaintextDocCipher } from './plaintextCipher.js';
|
|
50
53
|
export { ensureSpace, ensureSpaceAndCollection } from './provisioning.js';
|
|
51
|
-
export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isKeyUnwrapError, isUnknownEpochError } from './predicates.js';
|
|
52
|
-
export { EncryptionError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
|
|
54
|
+
export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isIntegrityError, isKeyUnwrapError, isUnknownEpochError } from './predicates.js';
|
|
55
|
+
export { EncryptionError, IntegrityError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
|
|
53
56
|
//# sourceMappingURL=index.js.map
|
package/dist/sync/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1E,sEAAsE;AACtE,6EAA6E;AAC7E,SAAS;AACT,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA"}
|
|
@@ -2,12 +2,14 @@ import type { DocCipher } from './types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Builds the identity {@link DocCipher} for a plaintext, content-addressed,
|
|
4
4
|
* insert-only collection. `encrypt` is the identity transform with a content-id
|
|
5
|
-
* key; `decrypt` returns the stored body unchanged
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* key; `decrypt` returns the stored body unchanged once its content id matches
|
|
6
|
+
* the resource id it was stored under, and throws {@link IntegrityError}
|
|
7
|
+
* otherwise (`ValidationError` when no id is passed); `encryptUpdate` throws -- a content-addressed document is never
|
|
8
|
+
* updated in place (a changed document is a different id).
|
|
8
9
|
*
|
|
9
10
|
* @param options {object}
|
|
10
|
-
* @param options.collectionId {string} labels the `encryptUpdate`
|
|
11
|
+
* @param options.collectionId {string} labels the `encryptUpdate` and
|
|
12
|
+
* `decrypt` errors
|
|
11
13
|
* @returns {DocCipher}
|
|
12
14
|
*/
|
|
13
15
|
export declare function createPlaintextDocCipher({ collectionId }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plaintextCipher.d.ts","sourceRoot":"","sources":["../../src/sync/plaintextCipher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plaintextCipher.d.ts","sourceRoot":"","sources":["../../src/sync/plaintextCipher.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAQ,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,YAAY,EACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,SAAS,CA2BZ"}
|
|
@@ -4,19 +4,24 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* The no-encryption (identity) {@link DocCipher} for a plaintext, content-
|
|
6
6
|
* addressed collection: the stored "envelope" IS the document, and the resource
|
|
7
|
-
* id is the document's content id
|
|
7
|
+
* id is the document's content id, so the content id is also the only
|
|
8
|
+
* integrity check a read has: `decrypt` recomputes it and refuses a document
|
|
9
|
+
* stored under an id it does not hash to. Kept free of the `@interop/was-client/edv`
|
|
8
10
|
* crypto graph so a plaintext-only consumer imports nothing it does not need.
|
|
9
11
|
*/
|
|
12
|
+
import { IntegrityError, requireResourceId } from '../errors.js';
|
|
10
13
|
import { contentCid } from './cid.js';
|
|
11
14
|
/**
|
|
12
15
|
* Builds the identity {@link DocCipher} for a plaintext, content-addressed,
|
|
13
16
|
* insert-only collection. `encrypt` is the identity transform with a content-id
|
|
14
|
-
* key; `decrypt` returns the stored body unchanged
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* key; `decrypt` returns the stored body unchanged once its content id matches
|
|
18
|
+
* the resource id it was stored under, and throws {@link IntegrityError}
|
|
19
|
+
* otherwise (`ValidationError` when no id is passed); `encryptUpdate` throws -- a content-addressed document is never
|
|
20
|
+
* updated in place (a changed document is a different id).
|
|
17
21
|
*
|
|
18
22
|
* @param options {object}
|
|
19
|
-
* @param options.collectionId {string} labels the `encryptUpdate`
|
|
23
|
+
* @param options.collectionId {string} labels the `encryptUpdate` and
|
|
24
|
+
* `decrypt` errors
|
|
20
25
|
* @returns {DocCipher}
|
|
21
26
|
*/
|
|
22
27
|
export function createPlaintextDocCipher({ collectionId }) {
|
|
@@ -28,7 +33,15 @@ export function createPlaintextDocCipher({ collectionId }) {
|
|
|
28
33
|
throw new Error(`Collection "${collectionId}" is content-addressed plaintext; ` +
|
|
29
34
|
'documents are never updated in place.');
|
|
30
35
|
},
|
|
31
|
-
async decrypt({ envelope }) {
|
|
36
|
+
async decrypt({ id, envelope }) {
|
|
37
|
+
requireResourceId({ id, collectionId });
|
|
38
|
+
const derived = contentCid(envelope);
|
|
39
|
+
if (derived !== id) {
|
|
40
|
+
throw new IntegrityError(`Cannot read resource "${id}" of collection "${collectionId}": its ` +
|
|
41
|
+
`content id is "${derived}", so the document was stored under an ` +
|
|
42
|
+
'id it was not written for. The server altered the document or ' +
|
|
43
|
+
'served it under another id.');
|
|
44
|
+
}
|
|
32
45
|
return envelope;
|
|
33
46
|
}
|
|
34
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plaintextCipher.js","sourceRoot":"","sources":["../../src/sync/plaintextCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"plaintextCipher.js","sourceRoot":"","sources":["../../src/sync/plaintextCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAGrC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CAAC,EACvC,YAAY,EAGb;IACC,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAkB;YACpC,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QACjD,CAAC;QAED,KAAK,CAAC,aAAa;YACjB,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,oCAAoC;gBAC7D,uCAAuC,CAC1C,CAAA;QACH,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAkC;YAC5D,iBAAiB,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;YACvC,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;YACpC,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;gBACnB,MAAM,IAAI,cAAc,CACtB,yBAAyB,EAAE,oBAAoB,YAAY,SAAS;oBAClE,kBAAkB,OAAO,yCAAyC;oBAClE,gEAAgE;oBAChE,6BAA6B,CAChC,CAAA;YACH,CAAC;YACD,OAAO,QAAQ,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/dist/sync/port.d.ts
CHANGED
|
@@ -28,7 +28,13 @@
|
|
|
28
28
|
* WriteAck} -- the write's raw `etag` (re-read only if the backend sent
|
|
29
29
|
* none) plus its `version` parsed out of it -- so a caller can record acked
|
|
30
30
|
* revisions immediately and echo `etag` back verbatim as a later write's
|
|
31
|
-
* `ifMatch`.
|
|
31
|
+
* `ifMatch`. A write carrying `ifMatch` or `ifNoneMatch` is refused with
|
|
32
|
+
* `NotSupportedError` before it is sent when the collection's backend
|
|
33
|
+
* descriptor was read and advertises no `conditional-writes`, since a backend
|
|
34
|
+
* that ignores the header would turn a guarded push into a silent overwrite. A
|
|
35
|
+
* descriptor that could not be read is not evidence either way and the push
|
|
36
|
+
* goes out, so a collection that is briefly absent does not disable guarded
|
|
37
|
+
* pushes for the port's lifetime.
|
|
32
38
|
*
|
|
33
39
|
* Bypassing the codec is not bypassing the error mapper. Every failure caught
|
|
34
40
|
* here goes through the client's own `mapError` first, so the port's signals
|
package/dist/sync/port.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EACL,gBAAgB,EAIjB,MAAM,4BAA4B,CAAA;AAYnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAIV,WAAW,EAEZ,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AACH,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAyG3B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAW7E;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAqB,EACtB,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,GAAG,WAAW,CA4Pd"}
|
package/dist/sync/port.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KEY_EPOCH_HEADER, readEtag, writeHeaders } from '../internal/conditional.js';
|
|
1
|
+
import { KEY_EPOCH_HEADER, assertPreconditionEnforced, readEtag, writeHeaders } from '../internal/conditional.js';
|
|
2
2
|
import { resourceMeta, resourcePath } from '../internal/paths.js';
|
|
3
3
|
import { mapError, NotFoundError, PreconditionFailedError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError, WasServerError } from '../errors.js';
|
|
4
4
|
/**
|
|
@@ -187,7 +187,8 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
|
|
|
187
187
|
const metaPath = (id) => resourceMeta(spaceId, collectionId, id);
|
|
188
188
|
// Construction is I/O-free (the codec/feature probes are lazy thunks) and
|
|
189
189
|
// `changes()` never resolves the codec, so it ships the stored bodies
|
|
190
|
-
// verbatim -- what this codec-bypassing port requires.
|
|
190
|
+
// verbatim -- what this codec-bypassing port requires. Its feature probe
|
|
191
|
+
// also gates the port's precondition-bearing writes.
|
|
191
192
|
const changesCollection = was
|
|
192
193
|
.space(spaceId)
|
|
193
194
|
.collection(collectionId, { capability });
|
|
@@ -273,6 +274,11 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
|
|
|
273
274
|
},
|
|
274
275
|
async putContent({ id, data, ifMatch, ifNoneMatch, epoch }) {
|
|
275
276
|
try {
|
|
277
|
+
await assertPreconditionEnforced({
|
|
278
|
+
features: changesCollection.features,
|
|
279
|
+
precondition: { ifMatch, ifNoneMatch },
|
|
280
|
+
operation: `Cannot write the resource "${id}"`
|
|
281
|
+
});
|
|
276
282
|
const response = await was.request({
|
|
277
283
|
capability,
|
|
278
284
|
path: contentPath(id),
|
|
@@ -291,6 +297,11 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
|
|
|
291
297
|
},
|
|
292
298
|
async deleteContent({ id, ifMatch }) {
|
|
293
299
|
try {
|
|
300
|
+
await assertPreconditionEnforced({
|
|
301
|
+
features: changesCollection.features,
|
|
302
|
+
precondition: { ifMatch },
|
|
303
|
+
operation: `Cannot delete the resource "${id}"`
|
|
304
|
+
});
|
|
294
305
|
const response = await was.request({
|
|
295
306
|
capability,
|
|
296
307
|
path: contentPath(id),
|
|
@@ -315,6 +326,11 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
|
|
|
315
326
|
},
|
|
316
327
|
async putMeta({ id, custom, ifMatch, ifNoneMatch }) {
|
|
317
328
|
try {
|
|
329
|
+
await assertPreconditionEnforced({
|
|
330
|
+
features: changesCollection.features,
|
|
331
|
+
precondition: { ifMatch, ifNoneMatch },
|
|
332
|
+
operation: `Cannot write the metadata of resource "${id}"`
|
|
333
|
+
});
|
|
318
334
|
const response = await was.request({
|
|
319
335
|
capability,
|
|
320
336
|
path: metaPath(id),
|