@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.
Files changed (99) hide show
  1. package/README.md +59 -50
  2. package/dist/Collection.d.ts +41 -30
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +41 -69
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.d.ts +28 -37
  7. package/dist/Resource.d.ts.map +1 -1
  8. package/dist/Resource.js +26 -52
  9. package/dist/Resource.js.map +1 -1
  10. package/dist/Space.d.ts +14 -14
  11. package/dist/Space.d.ts.map +1 -1
  12. package/dist/Space.js +16 -16
  13. package/dist/Space.js.map +1 -1
  14. package/dist/WasClient.d.ts +3 -2
  15. package/dist/WasClient.d.ts.map +1 -1
  16. package/dist/WasClient.js +3 -2
  17. package/dist/WasClient.js.map +1 -1
  18. package/dist/codec.d.ts +8 -14
  19. package/dist/codec.d.ts.map +1 -1
  20. package/dist/codec.js.map +1 -1
  21. package/dist/edv/EdvCodec.d.ts +3 -3
  22. package/dist/edv/EdvCodec.d.ts.map +1 -1
  23. package/dist/edv/EdvCodec.js +25 -74
  24. package/dist/edv/EdvCodec.js.map +1 -1
  25. package/dist/edv/WasTransport.d.ts +30 -44
  26. package/dist/edv/WasTransport.d.ts.map +1 -1
  27. package/dist/edv/WasTransport.js +38 -119
  28. package/dist/edv/WasTransport.js.map +1 -1
  29. package/dist/edv/descriptorStore.d.ts +13 -12
  30. package/dist/edv/descriptorStore.d.ts.map +1 -1
  31. package/dist/edv/descriptorStore.js +7 -6
  32. package/dist/edv/descriptorStore.js.map +1 -1
  33. package/dist/edv/docCipher.d.ts +10 -1
  34. package/dist/edv/docCipher.d.ts.map +1 -1
  35. package/dist/edv/docCipher.js +23 -6
  36. package/dist/edv/docCipher.js.map +1 -1
  37. package/dist/edv/logGovernedDescriptorStore.d.ts.map +1 -1
  38. package/dist/edv/logGovernedDescriptorStore.js +4 -2
  39. package/dist/edv/logGovernedDescriptorStore.js.map +1 -1
  40. package/dist/edv/refreshingDocCipher.d.ts +4 -1
  41. package/dist/edv/refreshingDocCipher.d.ts.map +1 -1
  42. package/dist/edv/refreshingDocCipher.js +7 -4
  43. package/dist/edv/refreshingDocCipher.js.map +1 -1
  44. package/dist/errors.d.ts +24 -7
  45. package/dist/errors.d.ts.map +1 -1
  46. package/dist/errors.js +27 -7
  47. package/dist/errors.js.map +1 -1
  48. package/dist/index.d.ts +0 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js.map +1 -1
  51. package/dist/internal/cas.d.ts +22 -10
  52. package/dist/internal/cas.d.ts.map +1 -1
  53. package/dist/internal/cas.js +37 -11
  54. package/dist/internal/cas.js.map +1 -1
  55. package/dist/internal/conditional.d.ts +29 -8
  56. package/dist/internal/conditional.d.ts.map +1 -1
  57. package/dist/internal/conditional.js +30 -6
  58. package/dist/internal/conditional.js.map +1 -1
  59. package/dist/internal/memo.d.ts +2 -2
  60. package/dist/internal/memo.js +2 -2
  61. package/dist/internal/meta.d.ts +12 -10
  62. package/dist/internal/meta.d.ts.map +1 -1
  63. package/dist/internal/meta.js +20 -13
  64. package/dist/internal/meta.js.map +1 -1
  65. package/dist/internal/paths.d.ts +1 -1
  66. package/dist/internal/paths.js +1 -1
  67. package/dist/internal/write.d.ts +12 -29
  68. package/dist/internal/write.d.ts.map +1 -1
  69. package/dist/internal/write.js +15 -74
  70. package/dist/internal/write.js.map +1 -1
  71. package/dist/log/logStore.d.ts +10 -6
  72. package/dist/log/logStore.d.ts.map +1 -1
  73. package/dist/log/logStore.js +16 -6
  74. package/dist/log/logStore.js.map +1 -1
  75. package/dist/sync/index.d.ts +12 -5
  76. package/dist/sync/index.d.ts.map +1 -1
  77. package/dist/sync/index.js +12 -5
  78. package/dist/sync/index.js.map +1 -1
  79. package/dist/sync/plaintextCipher.d.ts +6 -4
  80. package/dist/sync/plaintextCipher.d.ts.map +1 -1
  81. package/dist/sync/plaintextCipher.js +19 -6
  82. package/dist/sync/plaintextCipher.js.map +1 -1
  83. package/dist/sync/port.d.ts +3 -1
  84. package/dist/sync/port.d.ts.map +1 -1
  85. package/dist/sync/port.js +3 -3
  86. package/dist/sync/port.js.map +1 -1
  87. package/dist/sync/predicates.d.ts +33 -3
  88. package/dist/sync/predicates.d.ts.map +1 -1
  89. package/dist/sync/predicates.js +37 -3
  90. package/dist/sync/predicates.js.map +1 -1
  91. package/dist/sync/types.d.ts +24 -5
  92. package/dist/sync/types.d.ts.map +1 -1
  93. package/dist/types.d.ts +4 -3
  94. package/dist/types.d.ts.map +1 -1
  95. package/package.json +3 -3
  96. package/dist/internal/features.d.ts +0 -105
  97. package/dist/internal/features.d.ts.map +0 -1
  98. package/dist/internal/features.js +0 -168
  99. package/dist/internal/features.js.map +0 -1
@@ -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 carrying no validator makes its
104
- * attempt an unconditional write (`ifMatch` is `undefined`), which is all a
105
- * backend without `conditional-writes` offers.
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` (an absent or unreadable object), and
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. `compose` runs once per attempt, so a caller that
111
- * needs what was merged reads it from the value `write` resolves, which is the
112
- * last attempt's.
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
- * @param options.write {function} sends the body under `ifMatch`; a stale
121
- * validator throws `PreconditionFailedError` (412)
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":"AAeA;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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,CAqEb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;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,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IAClE,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,CAAC,CAAC,CAyBb"}
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"}
@@ -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 carrying no validator makes its
138
- * attempt an unconditional write (`ifMatch` is `undefined`), which is all a
139
- * backend without `conditional-writes` offers.
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` (an absent or unreadable object), and
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. `compose` runs once per attempt, so a caller that
145
- * needs what was merged reads it from the value `write` resolves, which is the
146
- * last attempt's.
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
- * @param options.write {function} sends the body under `ifMatch`; a stale
155
- * validator throws `PreconditionFailedError` (412)
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
- return { value: baseline.value, etag: baseline.etag };
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
  });
@@ -1 +1 @@
1
- {"version":3,"file":"cas.js","sourceRoot":"","sources":["../../src/internal/cas.ts"],"names":[],"mappings":"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"}
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 (the server's `conditional-writes` feature):
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, and checking a caller's precondition against the document a
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 the backend sent none (it does not advertise the
87
- * `conditional-writes` feature).
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 backend that returned no `ETag` on the
109
- * pre-read advertises no `conditional-writes` feature, so there is nothing to
110
- * compare against and the caller's `ifMatch` is left to the server.
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;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG7D;;;;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;;;;;;;GAOG;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
+ {"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 the backend sent none (it does not advertise the
93
- * `conditional-writes` feature).
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 backend that returned no `ETag` on the
117
- * pre-read advertises no `conditional-writes` feature, so there is nothing to
118
- * compare against and the caller's `ifMatch` is left to the server.
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":"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"}
1
+ {"version":3,"file":"conditional.js","sourceRoot":"","sources":["../../src/internal/conditional.ts"],"names":[],"mappings":"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"}
@@ -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, a
7
- * backend-feature probe, a lazily-unwrapped epoch key -- want the same three
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
@@ -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, a
7
- * backend-feature probe, a lazily-unwrapped epoch key -- want the same three
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
@@ -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` (when the backend supports `conditional-writes`),
75
- * so a concurrent metadata write is rebased on rather than silently erased by
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. A handle whose metadata cannot be read at
80
- * all patches nothing onto an empty object: the write it drives is the one
81
- * that refuses (`Collection.setMeta` throws `NotFoundError`), so a masked 404
82
- * cannot turn a rename into a create. At Collection level that is not a rare event:
83
- * one `metaVersion` covers the configuration members and the annotations
84
- * alike, so a concurrent `configure` -- or an epoch rotation -- legitimately
85
- * invalidates an in-flight annotation write.
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;;;;;;;;;;;;;;;;;;;;;;GAsBG;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,CAiBf"}
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"}
@@ -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` (when the backend supports `conditional-writes`),
117
- * so a concurrent metadata write is rebased on rather than silently erased by
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. A handle whose metadata cannot be read at
122
- * all patches nothing onto an empty object: the write it drives is the one
123
- * that refuses (`Collection.setMeta` throws `NotFoundError`), so a masked 404
124
- * cannot turn a rename into a create. At Collection level that is not a rare event:
125
- * one `metaVersion` covers the configuration members and the annotations
126
- * alike, so a concurrent `configure` -- or an epoch rotation -- legitimately
127
- * invalidates an in-flight annotation write.
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?.custom ?? {},
143
- ...(current?.etag !== undefined && { etag: current.etag })
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":"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"}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/internal/meta.ts"],"names":[],"mappings":"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"}
@@ -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 (the `chunked-streams` feature). Member
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).
@@ -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 (the `chunked-streams` feature). Member
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).
@@ -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, plus the
52
- * handle's memoized backend-feature probe. The codec never sees the zcap
53
- * machinery, and the raw `HttpResponse` it gets back matches the
54
- * `was.request()` escape hatch, which is what `WasTransport` consumes.
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, { features, capability }: {
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 and feature gating.
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, features, contentType, capability }: {
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, a conditional-writes backend rejects that insert with 412;
149
- * that 412 is re-thrown here with a message naming the real cause, instead
150
- * of surfacing as an inexplicable failed create. Conditional codecs
151
- * therefore need read access to update an existing document.
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, features, contentType, capability, precondition: callerPrecondition }: {
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;