@interop/was-client 0.65.0 → 0.67.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 +59 -50
- package/dist/Collection.d.ts +41 -30
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +41 -69
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +28 -37
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +26 -52
- package/dist/Resource.js.map +1 -1
- package/dist/Space.d.ts +14 -14
- package/dist/Space.d.ts.map +1 -1
- package/dist/Space.js +16 -16
- package/dist/Space.js.map +1 -1
- package/dist/WasClient.d.ts +3 -2
- package/dist/WasClient.d.ts.map +1 -1
- package/dist/WasClient.js +3 -2
- package/dist/WasClient.js.map +1 -1
- package/dist/codec.d.ts +8 -14
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js.map +1 -1
- package/dist/edv/EdvCodec.d.ts +3 -3
- package/dist/edv/EdvCodec.d.ts.map +1 -1
- package/dist/edv/EdvCodec.js +25 -74
- package/dist/edv/EdvCodec.js.map +1 -1
- package/dist/edv/WasTransport.d.ts +30 -44
- package/dist/edv/WasTransport.d.ts.map +1 -1
- package/dist/edv/WasTransport.js +38 -119
- package/dist/edv/WasTransport.js.map +1 -1
- package/dist/edv/descriptorStore.d.ts +13 -12
- package/dist/edv/descriptorStore.d.ts.map +1 -1
- package/dist/edv/descriptorStore.js +7 -6
- package/dist/edv/descriptorStore.js.map +1 -1
- package/dist/edv/docCipher.d.ts +10 -1
- package/dist/edv/docCipher.d.ts.map +1 -1
- package/dist/edv/docCipher.js +23 -6
- package/dist/edv/docCipher.js.map +1 -1
- package/dist/edv/logGovernedDescriptorStore.d.ts.map +1 -1
- package/dist/edv/logGovernedDescriptorStore.js +4 -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 +24 -7
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +27 -7
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/cas.d.ts +22 -10
- package/dist/internal/cas.d.ts.map +1 -1
- package/dist/internal/cas.js +37 -11
- package/dist/internal/cas.js.map +1 -1
- package/dist/internal/conditional.d.ts +29 -8
- package/dist/internal/conditional.d.ts.map +1 -1
- package/dist/internal/conditional.js +30 -6
- package/dist/internal/conditional.js.map +1 -1
- package/dist/internal/memo.d.ts +2 -2
- package/dist/internal/memo.js +2 -2
- package/dist/internal/meta.d.ts +12 -10
- package/dist/internal/meta.d.ts.map +1 -1
- package/dist/internal/meta.js +20 -13
- package/dist/internal/meta.js.map +1 -1
- package/dist/internal/paths.d.ts +1 -1
- package/dist/internal/paths.js +1 -1
- package/dist/internal/write.d.ts +12 -29
- package/dist/internal/write.d.ts.map +1 -1
- package/dist/internal/write.js +15 -74
- package/dist/internal/write.js.map +1 -1
- package/dist/log/logStore.d.ts +10 -6
- package/dist/log/logStore.d.ts.map +1 -1
- package/dist/log/logStore.js +16 -6
- package/dist/log/logStore.js.map +1 -1
- package/dist/sync/index.d.ts +12 -5
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +12 -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 +3 -1
- package/dist/sync/port.d.ts.map +1 -1
- package/dist/sync/port.js +3 -3
- package/dist/sync/port.js.map +1 -1
- package/dist/sync/predicates.d.ts +33 -3
- package/dist/sync/predicates.d.ts.map +1 -1
- package/dist/sync/predicates.js +37 -3
- package/dist/sync/predicates.js.map +1 -1
- package/dist/sync/types.d.ts +24 -5
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/types.d.ts +4 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/internal/features.d.ts +0 -105
- package/dist/internal/features.d.ts.map +0 -1
- package/dist/internal/features.js +0 -168
- package/dist/internal/features.js.map +0 -1
package/dist/internal/cas.d.ts
CHANGED
|
@@ -70,6 +70,11 @@ export declare function isPreconditionFailed(err: unknown): boolean;
|
|
|
70
70
|
* retry): nothing is written and the current value is returned as-is. Any other error `mutate` throws
|
|
71
71
|
* propagates unchanged.
|
|
72
72
|
*
|
|
73
|
+
* A read that returns a value with no validator is refused before the write
|
|
74
|
+
* with `NotSupportedError`: the replace would carry no `If-Match`, so a lost
|
|
75
|
+
* race would silently overwrite the rival write instead of rebasing on it. A
|
|
76
|
+
* `mutate` that resolves `null` writes nothing and so is never refused.
|
|
77
|
+
*
|
|
73
78
|
* When the store reports no value yet (`read()` resolves `null`), the optional
|
|
74
79
|
* `onAbsent` supplies the seed to mutate instead, and the result is written
|
|
75
80
|
* with the store's create-if-absent guard. Without `onAbsent`, or on a store
|
|
@@ -100,25 +105,31 @@ export declare function compareAndSwap<T>({ store, mutate, operation, onAbsent,
|
|
|
100
105
|
* `compose` is handed a baseline read and returns the write body, and `write`
|
|
101
106
|
* sends that body pinned to the baseline's validator. A lost race (a `412`)
|
|
102
107
|
* re-reads, re-composes, and re-sends, so a merge is only applied over a
|
|
103
|
-
* version this write observed. A baseline
|
|
104
|
-
*
|
|
105
|
-
*
|
|
108
|
+
* version this write observed. A baseline that was read and carries no
|
|
109
|
+
* validator is refused by the loop, like any other compare-and-swap with
|
|
110
|
+
* nothing to pin to.
|
|
106
111
|
*
|
|
107
112
|
* Unlike a plain {@link CasStore}, the body is not the stored value itself.
|
|
108
|
-
* The stored value may be `null`
|
|
113
|
+
* The stored value may be `null` -- an absent or unreadable object -- and
|
|
109
114
|
* `compose` decides whether proceeding from it is safe; a refusal it throws
|
|
110
|
-
* propagates unchanged. `
|
|
111
|
-
*
|
|
112
|
-
*
|
|
115
|
+
* propagates unchanged. A `null` baseline is the loop's create path: there is
|
|
116
|
+
* no version to pin to, so `write` is called with `ifNoneMatch: true`, the
|
|
117
|
+
* guarded create-if-absent. An object that exists but was unreadable (WAS
|
|
118
|
+
* masks an unauthorized read as 404) then fails the precondition instead of
|
|
119
|
+
* being overwritten. `compose` runs once per attempt, so a caller that needs
|
|
120
|
+
* what was merged reads it from the value `write` resolves, which is the last
|
|
121
|
+
* attempt's.
|
|
113
122
|
*
|
|
114
123
|
* @param options {object}
|
|
115
124
|
* @param options.read {function} reads a fresh baseline and its validator;
|
|
116
125
|
* may throw a caller-specific refusal (e.g. for an unreadable object)
|
|
117
126
|
* @param [options.current] {object} a baseline the caller has already read,
|
|
118
127
|
* used for the first attempt only; a rebase calls `read`
|
|
119
|
-
* @param options.compose {function} baseline to write body (may be async)
|
|
120
|
-
*
|
|
121
|
-
*
|
|
128
|
+
* @param options.compose {function} baseline to write body (may be async);
|
|
129
|
+
* handed `null` when nothing is stored
|
|
130
|
+
* @param options.write {function} sends the body under `ifMatch`, or under
|
|
131
|
+
* `ifNoneMatch: true` on the create path; a failed precondition throws
|
|
132
|
+
* `PreconditionFailedError` (412)
|
|
122
133
|
* @param options.operation {string} what the caller is doing, for the
|
|
123
134
|
* exhaustion error's message
|
|
124
135
|
* @param [options.maxAttempts] {number} defaults to {@link DEFAULT_CAS_ATTEMPTS}
|
|
@@ -136,6 +147,7 @@ export declare function composeAndSwap<B, W extends object, R>({ read, current,
|
|
|
136
147
|
compose: (baseline: B) => W | Promise<W>;
|
|
137
148
|
write: (body: W, precondition: {
|
|
138
149
|
ifMatch?: string;
|
|
150
|
+
ifNoneMatch?: boolean;
|
|
139
151
|
}) => Promise<R>;
|
|
140
152
|
operation: string;
|
|
141
153
|
maxAttempts?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cas.d.ts","sourceRoot":"","sources":["../../src/internal/cas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cas.d.ts","sourceRoot":"","sources":["../../src/internal/cas.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAErC;;;;GAIG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB;;;;;;;;;OASG;IACH,IAAI,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IAEnD;;;;;;;;OAQG;IACH,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/D;;;;;;;OAOG;IACH,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACjC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,EACtC,KAAK,EACL,MAAM,EACN,SAAS,EACT,QAAQ,EACR,WAAkC,EACnC,EAAE;IACD,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IAClD,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,CAAC,CAAC,CA0Eb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EAC3D,IAAI,EACJ,OAAO,EACP,OAAO,EACP,KAAK,EACL,SAAS,EACT,WAAW,EACZ,EAAE;IACD,IAAI,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAChD,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACxC,KAAK,EAAE,CACL,IAAI,EAAE,CAAC,EACP,YAAY,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,KACtD,OAAO,CAAC,CAAC,CAAC,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,CAAC,CAAC,CAkCb"}
|
package/dist/internal/cas.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* than hand-rolling another loop.
|
|
13
13
|
*/
|
|
14
14
|
import { PreconditionFailedError, ValidationError } from '../errors.js';
|
|
15
|
+
import { unenforcedPreconditionError } from './conditional.js';
|
|
15
16
|
/**
|
|
16
17
|
* How many times {@link compareAndSwap} retries a stale (`412`) write before
|
|
17
18
|
* surfacing `PreconditionFailedError`. One shared default, so two callers do
|
|
@@ -45,6 +46,11 @@ export function isPreconditionFailed(err) {
|
|
|
45
46
|
* retry): nothing is written and the current value is returned as-is. Any other error `mutate` throws
|
|
46
47
|
* propagates unchanged.
|
|
47
48
|
*
|
|
49
|
+
* A read that returns a value with no validator is refused before the write
|
|
50
|
+
* with `NotSupportedError`: the replace would carry no `If-Match`, so a lost
|
|
51
|
+
* race would silently overwrite the rival write instead of rebasing on it. A
|
|
52
|
+
* `mutate` that resolves `null` writes nothing and so is never refused.
|
|
53
|
+
*
|
|
48
54
|
* When the store reports no value yet (`read()` resolves `null`), the optional
|
|
49
55
|
* `onAbsent` supplies the seed to mutate instead, and the result is written
|
|
50
56
|
* with the store's create-if-absent guard. Without `onAbsent`, or on a store
|
|
@@ -112,6 +118,11 @@ export async function compareAndSwap({ store, mutate, operation, onAbsent, maxAt
|
|
|
112
118
|
// The value already reflects the desired state: nothing to write.
|
|
113
119
|
return current.value;
|
|
114
120
|
}
|
|
121
|
+
if (current.etag === undefined) {
|
|
122
|
+
throw unenforcedPreconditionError({
|
|
123
|
+
operation: `${operation} was refused`
|
|
124
|
+
});
|
|
125
|
+
}
|
|
115
126
|
try {
|
|
116
127
|
await store.replace(next, { ifMatch: current.etag });
|
|
117
128
|
return next;
|
|
@@ -134,25 +145,31 @@ export async function compareAndSwap({ store, mutate, operation, onAbsent, maxAt
|
|
|
134
145
|
* `compose` is handed a baseline read and returns the write body, and `write`
|
|
135
146
|
* sends that body pinned to the baseline's validator. A lost race (a `412`)
|
|
136
147
|
* re-reads, re-composes, and re-sends, so a merge is only applied over a
|
|
137
|
-
* version this write observed. A baseline
|
|
138
|
-
*
|
|
139
|
-
*
|
|
148
|
+
* version this write observed. A baseline that was read and carries no
|
|
149
|
+
* validator is refused by the loop, like any other compare-and-swap with
|
|
150
|
+
* nothing to pin to.
|
|
140
151
|
*
|
|
141
152
|
* Unlike a plain {@link CasStore}, the body is not the stored value itself.
|
|
142
|
-
* The stored value may be `null`
|
|
153
|
+
* The stored value may be `null` -- an absent or unreadable object -- and
|
|
143
154
|
* `compose` decides whether proceeding from it is safe; a refusal it throws
|
|
144
|
-
* propagates unchanged. `
|
|
145
|
-
*
|
|
146
|
-
*
|
|
155
|
+
* propagates unchanged. A `null` baseline is the loop's create path: there is
|
|
156
|
+
* no version to pin to, so `write` is called with `ifNoneMatch: true`, the
|
|
157
|
+
* guarded create-if-absent. An object that exists but was unreadable (WAS
|
|
158
|
+
* masks an unauthorized read as 404) then fails the precondition instead of
|
|
159
|
+
* being overwritten. `compose` runs once per attempt, so a caller that needs
|
|
160
|
+
* what was merged reads it from the value `write` resolves, which is the last
|
|
161
|
+
* attempt's.
|
|
147
162
|
*
|
|
148
163
|
* @param options {object}
|
|
149
164
|
* @param options.read {function} reads a fresh baseline and its validator;
|
|
150
165
|
* may throw a caller-specific refusal (e.g. for an unreadable object)
|
|
151
166
|
* @param [options.current] {object} a baseline the caller has already read,
|
|
152
167
|
* used for the first attempt only; a rebase calls `read`
|
|
153
|
-
* @param options.compose {function} baseline to write body (may be async)
|
|
154
|
-
*
|
|
155
|
-
*
|
|
168
|
+
* @param options.compose {function} baseline to write body (may be async);
|
|
169
|
+
* handed `null` when nothing is stored
|
|
170
|
+
* @param options.write {function} sends the body under `ifMatch`, or under
|
|
171
|
+
* `ifNoneMatch: true` on the create path; a failed precondition throws
|
|
172
|
+
* `PreconditionFailedError` (412)
|
|
156
173
|
* @param options.operation {string} what the caller is doing, for the
|
|
157
174
|
* exhaustion error's message
|
|
158
175
|
* @param [options.maxAttempts] {number} defaults to {@link DEFAULT_CAS_ATTEMPTS}
|
|
@@ -167,14 +184,23 @@ export async function composeAndSwap({ read, current, compose, write, operation,
|
|
|
167
184
|
// The caller's baseline is consumed once, so a rebase always re-reads.
|
|
168
185
|
const baseline = seed ?? (await read());
|
|
169
186
|
seed = undefined;
|
|
170
|
-
|
|
187
|
+
// Nothing stored: the loop's create path, guarded by `If-None-Match`.
|
|
188
|
+
return baseline.value === null
|
|
189
|
+
? null
|
|
190
|
+
: { value: baseline.value, etag: baseline.etag };
|
|
171
191
|
},
|
|
172
192
|
replace: async (body, { ifMatch }) => {
|
|
173
193
|
written = { result: await write(body, { ifMatch }) };
|
|
194
|
+
},
|
|
195
|
+
create: async (body) => {
|
|
196
|
+
written = { result: await write(body, { ifNoneMatch: true }) };
|
|
174
197
|
}
|
|
175
198
|
},
|
|
176
199
|
// The store only ever reads a baseline and only ever replaces a body.
|
|
177
200
|
mutate: value => compose(value),
|
|
201
|
+
// The seed `compose` builds the create body from is the absent baseline
|
|
202
|
+
// itself, which every caller of this helper spells `null`.
|
|
203
|
+
onAbsent: () => null,
|
|
178
204
|
operation,
|
|
179
205
|
...(maxAttempts !== undefined && { maxAttempts })
|
|
180
206
|
});
|
package/dist/internal/cas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cas.js","sourceRoot":"","sources":["../../src/internal/cas.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;GASG;AACH,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"cas.js","sourceRoot":"","sources":["../../src/internal/cas.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Helpers for conditional writes (
|
|
5
|
+
* Helpers for conditional writes (a baseline WAS server requirement):
|
|
6
6
|
* assembling a write's request headers from an optional content-type plus the
|
|
7
7
|
* `If-Match` / `If-None-Match: *` preconditions, reading the `ETag` a write
|
|
8
|
-
* response returns,
|
|
9
|
-
* conditional codec's write path pre-read
|
|
8
|
+
* response returns, checking a caller's precondition against the document a
|
|
9
|
+
* conditional codec's write path pre-read, and refusing a write whose pin the
|
|
10
|
+
* read it is based on never supplied.
|
|
10
11
|
*/
|
|
11
12
|
import type { EncodedWrite, ResponseLike } from '../codec.js';
|
|
13
|
+
import { NotSupportedError } from '../errors.js';
|
|
12
14
|
/**
|
|
13
15
|
* The request header the server reads a content write's key-epoch id from,
|
|
14
16
|
* stamping it onto the Resource's metadata (an absent header clears any prior
|
|
@@ -81,10 +83,29 @@ export declare function writeHeaders({ contentType, precondition, epoch }: {
|
|
|
81
83
|
precondition?: WritePrecondition;
|
|
82
84
|
epoch?: string;
|
|
83
85
|
}): Record<string, string> | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* The refusal for a guarded write whose pin the read it is based on never
|
|
88
|
+
* supplied: the read returned no `ETag` validator, so the write would go out
|
|
89
|
+
* with no `If-Match` at all. Every such gate builds its error here, so the
|
|
90
|
+
* messages do not drift apart.
|
|
91
|
+
*
|
|
92
|
+
* A WAS server versions every resource, so a missing validator is a transport
|
|
93
|
+
* or deployment problem, not a server declining to version. Most often it is a
|
|
94
|
+
* browser client whose CORS configuration does not expose `ETag` to script.
|
|
95
|
+
*
|
|
96
|
+
* @param options {object}
|
|
97
|
+
* @param options.operation {string} what was refused, as the message's
|
|
98
|
+
* opening clause (e.g. `Cannot append to the resource log`)
|
|
99
|
+
* @returns {NotSupportedError}
|
|
100
|
+
*/
|
|
101
|
+
export declare function unenforcedPreconditionError({ operation }: {
|
|
102
|
+
operation: string;
|
|
103
|
+
}): NotSupportedError;
|
|
84
104
|
/**
|
|
85
105
|
* Reads the strong `ETag` validator a write/read response returned, or
|
|
86
|
-
* `undefined` when
|
|
87
|
-
*
|
|
106
|
+
* `undefined` when none reached the client (a WAS server serves one on every
|
|
107
|
+
* resource; a browser client can still be denied it by a CORS configuration
|
|
108
|
+
* that does not expose the header).
|
|
88
109
|
*
|
|
89
110
|
* @param response {ResponseLike | null}
|
|
90
111
|
* @returns {string | undefined}
|
|
@@ -105,9 +126,9 @@ export declare function readEtag(response: ResponseLike | null): string | undefi
|
|
|
105
126
|
*
|
|
106
127
|
* The thrown error is the same `PreconditionFailedError` (412) the server
|
|
107
128
|
* would answer with, so a compare-and-swap retry loop needs no special case
|
|
108
|
-
* for an encrypted collection. A
|
|
109
|
-
*
|
|
110
|
-
*
|
|
129
|
+
* for an encrypted collection. A pre-read that carried no `ETag` leaves
|
|
130
|
+
* nothing to compare against locally, and the caller's `ifMatch` is left to
|
|
131
|
+
* the server.
|
|
111
132
|
*
|
|
112
133
|
* @param options {object}
|
|
113
134
|
* @param options.path {string} the resource path written
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional.d.ts","sourceRoot":"","sources":["../../src/internal/conditional.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"conditional.d.ts","sourceRoot":"","sources":["../../src/internal/conditional.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EACL,iBAAiB,EAGlB,MAAM,cAAc,CAAA;AAErB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAA;AAE3C;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,iBAAiB,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,CAAC,EAAE,iBAAiB,GAC/B,iBAAiB,GAAG,SAAS,CAK/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,CAAC,EAAE,iBAAiB,GAC/B,IAAI,CAQN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,YAAiB,EACjB,KAAK,EACN,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAiBrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CAAC,EAC1C,SAAS,EACV,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,iBAAiB,CASpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gCAAgC,CAAC,EAC/C,IAAI,EACJ,OAAO,EACP,YAAY,EACb,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC,GAAG,IAAI,CAkCP"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PreconditionFailedError, ValidationError } from '../errors.js';
|
|
1
|
+
import { NotSupportedError, PreconditionFailedError, ValidationError } from '../errors.js';
|
|
2
2
|
/**
|
|
3
3
|
* The request header the server reads a content write's key-epoch id from,
|
|
4
4
|
* stamping it onto the Resource's metadata (an absent header clears any prior
|
|
@@ -87,10 +87,34 @@ export function writeHeaders({ contentType, precondition = {}, epoch }) {
|
|
|
87
87
|
}
|
|
88
88
|
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The refusal for a guarded write whose pin the read it is based on never
|
|
92
|
+
* supplied: the read returned no `ETag` validator, so the write would go out
|
|
93
|
+
* with no `If-Match` at all. Every such gate builds its error here, so the
|
|
94
|
+
* messages do not drift apart.
|
|
95
|
+
*
|
|
96
|
+
* A WAS server versions every resource, so a missing validator is a transport
|
|
97
|
+
* or deployment problem, not a server declining to version. Most often it is a
|
|
98
|
+
* browser client whose CORS configuration does not expose `ETag` to script.
|
|
99
|
+
*
|
|
100
|
+
* @param options {object}
|
|
101
|
+
* @param options.operation {string} what was refused, as the message's
|
|
102
|
+
* opening clause (e.g. `Cannot append to the resource log`)
|
|
103
|
+
* @returns {NotSupportedError}
|
|
104
|
+
*/
|
|
105
|
+
export function unenforcedPreconditionError({ operation }) {
|
|
106
|
+
return new NotSupportedError(`${operation}: the read it is pinned to returned no ETag validator, so ` +
|
|
107
|
+
'the write would go out unconditionally, and a concurrent change could ' +
|
|
108
|
+
'be silently overwritten instead of failing with a 412. A WAS server ' +
|
|
109
|
+
'serves an ETag on every resource read; check that the response is not ' +
|
|
110
|
+
'losing the header on the way (a browser client needs `ETag` in the ' +
|
|
111
|
+
"server's `Access-Control-Expose-Headers`).");
|
|
112
|
+
}
|
|
90
113
|
/**
|
|
91
114
|
* Reads the strong `ETag` validator a write/read response returned, or
|
|
92
|
-
* `undefined` when
|
|
93
|
-
*
|
|
115
|
+
* `undefined` when none reached the client (a WAS server serves one on every
|
|
116
|
+
* resource; a browser client can still be denied it by a CORS configuration
|
|
117
|
+
* that does not expose the header).
|
|
94
118
|
*
|
|
95
119
|
* @param response {ResponseLike | null}
|
|
96
120
|
* @returns {string | undefined}
|
|
@@ -113,9 +137,9 @@ export function readEtag(response) {
|
|
|
113
137
|
*
|
|
114
138
|
* The thrown error is the same `PreconditionFailedError` (412) the server
|
|
115
139
|
* would answer with, so a compare-and-swap retry loop needs no special case
|
|
116
|
-
* for an encrypted collection. A
|
|
117
|
-
*
|
|
118
|
-
*
|
|
140
|
+
* for an encrypted collection. A pre-read that carried no `ETag` leaves
|
|
141
|
+
* nothing to compare against locally, and the caller's `ifMatch` is left to
|
|
142
|
+
* the server.
|
|
119
143
|
*
|
|
120
144
|
* @param options {object}
|
|
121
145
|
* @param options.path {string} the resource path written
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional.js","sourceRoot":"","sources":["../../src/internal/conditional.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conditional.js","sourceRoot":"","sources":["../../src/internal/conditional.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/memo.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* The shared "memoize an in-flight promise, but only cache a success" helper.
|
|
6
|
-
* Several lazily-resolved singletons across the client -- a handle's codec,
|
|
7
|
-
*
|
|
6
|
+
* Several lazily-resolved singletons across the client -- a handle's codec,
|
|
7
|
+
* the service description, a lazily-unwrapped epoch key -- want the same three
|
|
8
8
|
* properties: concurrent callers share one round-trip, a rejection is not
|
|
9
9
|
* cached (so the next call retries rather than replaying a stale failure), and
|
|
10
10
|
* a reset drops whatever is held. Written once here so the three cannot drift
|
package/dist/internal/memo.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* The shared "memoize an in-flight promise, but only cache a success" helper.
|
|
6
|
-
* Several lazily-resolved singletons across the client -- a handle's codec,
|
|
7
|
-
*
|
|
6
|
+
* Several lazily-resolved singletons across the client -- a handle's codec,
|
|
7
|
+
* the service description, a lazily-unwrapped epoch key -- want the same three
|
|
8
8
|
* properties: concurrent callers share one round-trip, a rejection is not
|
|
9
9
|
* cached (so the next call retries rather than replaying a stale failure), and
|
|
10
10
|
* a reset drops whatever is held. Written once here so the three cannot drift
|
package/dist/internal/meta.d.ts
CHANGED
|
@@ -71,18 +71,20 @@ export declare function writeMeta(context: ClientContext, { metaPath, codec: cod
|
|
|
71
71
|
/**
|
|
72
72
|
* The shared read-then-CAS body of the handles' `setName` / `setTags`: reads
|
|
73
73
|
* the current metadata, merges `patch` over its `custom`, and writes it back
|
|
74
|
-
* pinned to the read's `etag
|
|
75
|
-
*
|
|
76
|
-
* the full-replacement write.
|
|
74
|
+
* pinned to the read's `etag`, so a concurrent metadata write is rebased on
|
|
75
|
+
* rather than silently erased by the full-replacement write.
|
|
77
76
|
*
|
|
78
77
|
* A lost race (`412`) re-reads and re-applies the patch, up to the shared
|
|
79
|
-
* compare-and-swap attempt limit.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
78
|
+
* compare-and-swap attempt limit. That is not a rare event at Collection
|
|
79
|
+
* level: one `metaVersion` covers the configuration members and the
|
|
80
|
+
* annotations alike, so a concurrent `configure` -- or an epoch rotation --
|
|
81
|
+
* legitimately invalidates an in-flight annotation write.
|
|
82
|
+
*
|
|
83
|
+
* A handle whose metadata cannot be read at all is refused with
|
|
84
|
+
* `NotFoundError` rather than patched onto an empty object, so a masked 404
|
|
85
|
+
* cannot turn a rename into a create. A read that carried no validator is
|
|
86
|
+
* refused by the compare-and-swap loop: the full-replacement write would go
|
|
87
|
+
* out with no `If-Match` at all.
|
|
86
88
|
*
|
|
87
89
|
* @param handle {object} the Collection or Resource handle to patch
|
|
88
90
|
* @param patch {ResourceMetadataCustom} the properties to merge over the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAIjD,OAAO,KAAK,EACV,KAAK,EACL,sBAAsB,EACtB,2BAA2B,EAC5B,MAAM,aAAa,CAAA;AAEpB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,SAAS;IAAE,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAAE,EAEpD,OAAO,EAAE,aAAa,EACtB,EACE,QAAQ,EACR,KAAK,EAAE,YAAY,EACnB,OAAO,EACP,IAAI,EACJ,UAAU,EACV,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACjC,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,KAAK,IAAI,CAAA;CACX,GACA,OAAO,CAAC,CAAC,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CA4ChD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,EACE,QAAQ,EACR,KAAK,EAAE,YAAY,EACnB,MAAM,EACN,IAAI,EACJ,OAAO,EACP,WAAW,EACX,UAAU,EACX,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,MAAM,EAAE,2BAA2B,CAAA;IACnC,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,GACA,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAW5B;AAED
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAIjD,OAAO,KAAK,EACV,KAAK,EACL,sBAAsB,EACtB,2BAA2B,EAC5B,MAAM,aAAa,CAAA;AAEpB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,SAAS;IAAE,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAAE,EAEpD,OAAO,EAAE,aAAa,EACtB,EACE,QAAQ,EACR,KAAK,EAAE,YAAY,EACnB,OAAO,EACP,IAAI,EACJ,UAAU,EACV,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACjC,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,KAAK,IAAI,CAAA;CACX,GACA,OAAO,CAAC,CAAC,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CA4ChD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,EACE,QAAQ,EACR,KAAK,EAAE,YAAY,EACnB,MAAM,EACN,IAAI,EACJ,OAAO,EACP,WAAW,EACX,UAAU,EACX,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,MAAM,EAAE,2BAA2B,CAAA;IACnC,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,GACA,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAW5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE;IACN,IAAI,IAAI,OAAO,CAAC;QAAE,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IAC1E,OAAO,CACL,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,sBAAsB,CAAA;KAAE,EACzC,OAAO,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC9B,EACD,KAAK,EAAE,sBAAsB,EAC7B,SAAS,SAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
package/dist/internal/meta.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `Collection`, and `patchCustom` below drives both handles' read-modify-write
|
|
13
13
|
* helpers through a bounded compare-and-swap.
|
|
14
14
|
*/
|
|
15
|
-
import { WasServerError } from '../errors.js';
|
|
15
|
+
import { NotFoundError, WasServerError } from '../errors.js';
|
|
16
16
|
import { compareAndSwap } from './cas.js';
|
|
17
17
|
import { send } from './request.js';
|
|
18
18
|
import { readEtag, writeHeaders } from './conditional.js';
|
|
@@ -113,18 +113,20 @@ export async function writeMeta(context, { metaPath, codec: codecPromise, custom
|
|
|
113
113
|
/**
|
|
114
114
|
* The shared read-then-CAS body of the handles' `setName` / `setTags`: reads
|
|
115
115
|
* the current metadata, merges `patch` over its `custom`, and writes it back
|
|
116
|
-
* pinned to the read's `etag
|
|
117
|
-
*
|
|
118
|
-
* the full-replacement write.
|
|
116
|
+
* pinned to the read's `etag`, so a concurrent metadata write is rebased on
|
|
117
|
+
* rather than silently erased by the full-replacement write.
|
|
119
118
|
*
|
|
120
119
|
* A lost race (`412`) re-reads and re-applies the patch, up to the shared
|
|
121
|
-
* compare-and-swap attempt limit.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
120
|
+
* compare-and-swap attempt limit. That is not a rare event at Collection
|
|
121
|
+
* level: one `metaVersion` covers the configuration members and the
|
|
122
|
+
* annotations alike, so a concurrent `configure` -- or an epoch rotation --
|
|
123
|
+
* legitimately invalidates an in-flight annotation write.
|
|
124
|
+
*
|
|
125
|
+
* A handle whose metadata cannot be read at all is refused with
|
|
126
|
+
* `NotFoundError` rather than patched onto an empty object, so a masked 404
|
|
127
|
+
* cannot turn a rename into a create. A read that carried no validator is
|
|
128
|
+
* refused by the compare-and-swap loop: the full-replacement write would go
|
|
129
|
+
* out with no `If-Match` at all.
|
|
128
130
|
*
|
|
129
131
|
* @param handle {object} the Collection or Resource handle to patch
|
|
130
132
|
* @param patch {ResourceMetadataCustom} the properties to merge over the
|
|
@@ -138,9 +140,14 @@ export async function patchCustom(handle, patch, operation = 'Metadata update')
|
|
|
138
140
|
store: {
|
|
139
141
|
read: async () => {
|
|
140
142
|
const current = await handle.meta();
|
|
143
|
+
if (current === null) {
|
|
144
|
+
throw new NotFoundError(`${operation} failed: the metadata is not readable, so there is ` +
|
|
145
|
+
'nothing to patch -- the target does not exist, or it is not ' +
|
|
146
|
+
'visible with this capability (WAS returns 404 for both).');
|
|
147
|
+
}
|
|
141
148
|
return {
|
|
142
|
-
value: current
|
|
143
|
-
...(current
|
|
149
|
+
value: current.custom ?? {},
|
|
150
|
+
...(current.etag !== undefined && { etag: current.etag })
|
|
144
151
|
};
|
|
145
152
|
},
|
|
146
153
|
replace: async (custom, { ifMatch }) => {
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"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"}
|
package/dist/internal/paths.d.ts
CHANGED
|
@@ -122,7 +122,7 @@ export declare function resourceMeta(spaceId: string, collectionId: string, reso
|
|
|
122
122
|
export declare function resourcePolicy(spaceId: string, collectionId: string, resourceId: string): string;
|
|
123
123
|
/**
|
|
124
124
|
* `/space/:spaceId/:collectionId/:resourceId/chunks/:chunkIndex` -- a single
|
|
125
|
-
* stored chunk of a chunked Resource
|
|
125
|
+
* stored chunk of a chunked Resource. Member
|
|
126
126
|
* form, no trailing slash: get / put / delete one chunk by its ordinal index.
|
|
127
127
|
* The `chunkIndex` is a non-negative integer, emitted verbatim (it is never a
|
|
128
128
|
* reserved or dot segment, so it needs no percent-encoding).
|
package/dist/internal/paths.js
CHANGED
|
@@ -274,7 +274,7 @@ export function resourcePolicy(spaceId, collectionId, resourceId) {
|
|
|
274
274
|
}
|
|
275
275
|
/**
|
|
276
276
|
* `/space/:spaceId/:collectionId/:resourceId/chunks/:chunkIndex` -- a single
|
|
277
|
-
* stored chunk of a chunked Resource
|
|
277
|
+
* stored chunk of a chunked Resource. Member
|
|
278
278
|
* form, no trailing slash: get / put / delete one chunk by its ordinal index.
|
|
279
279
|
* The `chunkIndex` is a non-negative integer, emitted verbatim (it is never a
|
|
280
280
|
* reserved or dot segment, so it needs no percent-encoding).
|
package/dist/internal/write.d.ts
CHANGED
|
@@ -22,7 +22,6 @@ import type { HttpResponse } from '@interop/http-client';
|
|
|
22
22
|
import type { CodecRequestContext, EncodedWrite, ResourceCodec } from '../codec.js';
|
|
23
23
|
import type { IZcap, ResourceData } from '../types.js';
|
|
24
24
|
import type { ClientContext } from './request.js';
|
|
25
|
-
import type { FeatureProbe } from './features.js';
|
|
26
25
|
import type { WritePrecondition } from './conditional.js';
|
|
27
26
|
/**
|
|
28
27
|
* Sends an encoded write (`PUT`/`POST`) to a resource path, applying the
|
|
@@ -48,10 +47,10 @@ export declare function sendEncodedWrite(context: ClientContext, { path, method,
|
|
|
48
47
|
}): Promise<HttpResponse>;
|
|
49
48
|
/**
|
|
50
49
|
* Builds the {@link CodecRequestContext} core hands a codec that drives its own
|
|
51
|
-
* I/O: the signed-request primitive bound to this handle's capability
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
50
|
+
* I/O: the signed-request primitive bound to this handle's capability. The
|
|
51
|
+
* codec never sees the zcap machinery, and the raw `HttpResponse` it gets back
|
|
52
|
+
* matches the `was.request()` escape hatch, which is what `WasTransport`
|
|
53
|
+
* consumes.
|
|
55
54
|
*
|
|
56
55
|
* Requests go through the same mapped `send` path the core write paths use, so
|
|
57
56
|
* a codec-driven write fails with the typed `WasError` subclasses the calling
|
|
@@ -61,13 +60,10 @@ export declare function sendEncodedWrite(context: ClientContext, { path, method,
|
|
|
61
60
|
*
|
|
62
61
|
* @param context {ClientContext}
|
|
63
62
|
* @param options {object}
|
|
64
|
-
* @param options.features {FeatureProbe} the handle's memoized backend-feature
|
|
65
|
-
* probe
|
|
66
63
|
* @param [options.capability] {IZcap} capability attached to each request
|
|
67
64
|
* @returns {CodecRequestContext}
|
|
68
65
|
*/
|
|
69
|
-
export declare function codecRequestContext(context: ClientContext, {
|
|
70
|
-
features: FeatureProbe;
|
|
66
|
+
export declare function codecRequestContext(context: ClientContext, { capability }?: {
|
|
71
67
|
capability?: IZcap;
|
|
72
68
|
}): CodecRequestContext;
|
|
73
69
|
/**
|
|
@@ -96,7 +92,7 @@ export type InsertOutcome = {
|
|
|
96
92
|
* A codec may also answer the encode with a multi-request plan (the EDV codec's
|
|
97
93
|
* chunked blob write). The plan is then executed over the handle's signed
|
|
98
94
|
* request context instead of being sent as one request; it owns its own
|
|
99
|
-
* preconditions
|
|
95
|
+
* preconditions.
|
|
100
96
|
*
|
|
101
97
|
* A codec that mints its own id (e.g. the encrypting codec's EDV id) writes it
|
|
102
98
|
* by `PUT` to that id's path; a codec that mints none (the identity codec)
|
|
@@ -117,19 +113,15 @@ export type InsertOutcome = {
|
|
|
117
113
|
* codec-minted id
|
|
118
114
|
* @param options.codec {ResourceCodec} the collection's resolved codec
|
|
119
115
|
* @param options.data {ResourceData} the plaintext value
|
|
120
|
-
* @param options.features {FeatureProbe} the handle's shared backend-feature
|
|
121
|
-
* probe, handed to a codec's multi-request plan so its affordance gate costs
|
|
122
|
-
* no extra round trip
|
|
123
116
|
* @param [options.contentType] {string} caller-supplied content type
|
|
124
117
|
* @param [options.capability] {IZcap}
|
|
125
118
|
* @returns {Promise<InsertOutcome>}
|
|
126
119
|
*/
|
|
127
|
-
export declare function insertResource(context: ClientContext, { itemsPath, pathForId, codec, data,
|
|
120
|
+
export declare function insertResource(context: ClientContext, { itemsPath, pathForId, codec, data, contentType, capability }: {
|
|
128
121
|
itemsPath: string;
|
|
129
122
|
pathForId: (id: string) => string;
|
|
130
123
|
codec: ResourceCodec;
|
|
131
124
|
data: ResourceData;
|
|
132
|
-
features: FeatureProbe;
|
|
133
125
|
contentType?: string;
|
|
134
126
|
capability?: IZcap;
|
|
135
127
|
}): Promise<InsertOutcome>;
|
|
@@ -145,15 +137,10 @@ export declare function insertResource(context: ClientContext, { itemsPath, path
|
|
|
145
137
|
* - The pre-read cannot distinguish "absent" from "unreadable with this
|
|
146
138
|
* capability" (WAS masks unauthorized reads as 404), so a conditional codec
|
|
147
139
|
* encodes a fresh insert (`If-None-Match: *`) in both cases. When the target
|
|
148
|
-
* in fact exists,
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* - A backend that does NOT advertise `conditional-writes` ignores the
|
|
153
|
-
* `If-None-Match: *` guard, so the 412 safety net above never fires there: a
|
|
154
|
-
* masked-404 insert would silently overwrite the existing document and reset
|
|
155
|
-
* its sequence. The insert-after-null-pre-read is therefore refused (fail
|
|
156
|
-
* closed) unless the backend advertises the feature.
|
|
140
|
+
* in fact exists, the server rejects that insert with 412; that 412 is
|
|
141
|
+
* re-thrown here with a message naming the real cause, instead of surfacing
|
|
142
|
+
* as an inexplicable failed create. Conditional codecs therefore need read
|
|
143
|
+
* access to update an existing document.
|
|
157
144
|
*
|
|
158
145
|
* @param context {ClientContext}
|
|
159
146
|
* @param options {object}
|
|
@@ -161,21 +148,17 @@ export declare function insertResource(context: ClientContext, { itemsPath, path
|
|
|
161
148
|
* @param options.codec {ResourceCodec} the collection's resolved codec
|
|
162
149
|
* @param options.id {string} the resource id
|
|
163
150
|
* @param options.data {ResourceData} the plaintext value
|
|
164
|
-
* @param options.features {FeatureProbe} the handle's shared
|
|
165
|
-
* `BackendFeatures` probe; consulted only for a conditional codec's
|
|
166
|
-
* insert-after-null-pre-read
|
|
167
151
|
* @param [options.contentType] {string} caller-supplied content type
|
|
168
152
|
* @param [options.capability] {IZcap}
|
|
169
153
|
* @param [options.precondition] {WritePrecondition} the caller's explicit
|
|
170
154
|
* precondition (used only for a non-conditional codec)
|
|
171
155
|
* @returns {Promise<HttpResponse>}
|
|
172
156
|
*/
|
|
173
|
-
export declare function upsertResource(context: ClientContext, { path, codec, id, data,
|
|
157
|
+
export declare function upsertResource(context: ClientContext, { path, codec, id, data, contentType, capability, precondition: callerPrecondition }: {
|
|
174
158
|
path: string;
|
|
175
159
|
codec: ResourceCodec;
|
|
176
160
|
id: string;
|
|
177
161
|
data: ResourceData;
|
|
178
|
-
features: FeatureProbe;
|
|
179
162
|
contentType?: string;
|
|
180
163
|
capability?: IZcap;
|
|
181
164
|
precondition?: WritePrecondition;
|