@cloudbitmaps/core 0.21.0 → 0.23.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 +23 -8
- package/dist/chunk-7GT632UF.js +641 -0
- package/dist/chunk-7GT632UF.js.map +7 -0
- package/dist/chunk-CGILDXGP.js +73 -0
- package/dist/chunk-CGILDXGP.js.map +7 -0
- package/dist/chunk-GKHERVVQ.js +121 -0
- package/dist/chunk-GKHERVVQ.js.map +7 -0
- package/dist/{chunk-IGLIZBR7.js → chunk-MVUD4R72.js} +253 -765
- package/dist/chunk-MVUD4R72.js.map +7 -0
- package/dist/core/audit.d.ts +53 -15
- package/dist/core/bit-route.d.ts +9 -0
- package/dist/core/blob.d.ts +4 -0
- package/dist/core/budget.d.ts +8 -3
- package/dist/core/check.d.ts +27 -0
- package/dist/core/codec.d.ts +1 -1
- package/dist/core/combine-expr.d.ts +9 -5
- package/dist/core/combine-feed.d.ts +11 -3
- package/dist/core/combine-many.d.ts +28 -13
- package/dist/core/consistency.d.ts +11 -2
- package/dist/core/cooperative.d.ts +7 -0
- package/dist/core/crbm-storage-source.d.ts +7 -4
- package/dist/core/crypto.d.ts +5 -0
- package/dist/core/determinism.d.ts +2 -1
- package/dist/core/discover.d.ts +5 -3
- package/dist/core/engine.d.ts +4 -4
- package/dist/core/erase-id.d.ts +52 -19
- package/dist/core/erasure.d.ts +62 -28
- package/dist/core/errors.d.ts +83 -9
- package/dist/core/leases.d.ts +2 -0
- package/dist/core/load-input.d.ts +48 -0
- package/dist/core/load.d.ts +71 -16
- package/dist/core/metrics.d.ts +22 -1
- package/dist/core/pinned-storage-source.d.ts +27 -8
- package/dist/core/pointer-id.d.ts +9 -0
- package/dist/core/ports.d.ts +107 -13
- package/dist/core/preflight.d.ts +80 -0
- package/dist/core/registry-scan.d.ts +0 -5
- package/dist/core/retention-sweep.d.ts +61 -16
- package/dist/core/retention.d.ts +18 -7
- package/dist/core/retry.d.ts +5 -2
- package/dist/core/rollback.d.ts +23 -12
- package/dist/core/validate.d.ts +33 -2
- package/dist/driver-kit.d.ts +9 -4
- package/dist/driver-kit.js +63 -27
- package/dist/driver-kit.js.map +2 -2
- package/dist/drivers/_shared/object-registry.d.ts +24 -1
- package/dist/drivers/_shared/options.d.ts +15 -7
- package/dist/drivers/backends.d.ts +19 -2
- package/dist/drivers/crypto.d.ts +18 -3
- package/dist/export/index.d.ts +25 -10
- package/dist/index.d.ts +19 -17
- package/dist/index.js +2457 -2283
- package/dist/index.js.map +4 -4
- package/dist/node.d.ts +14 -0
- package/dist/node.js +1064 -0
- package/dist/node.js.map +7 -0
- package/package.json +16 -2
- package/dist/chunk-IGLIZBR7.js.map +0 -7
- package/dist/core/absent-operands.d.ts +0 -8
- package/dist/core/bulk-load.d.ts +0 -148
- package/dist/core/cas-retry.d.ts +0 -27
- package/dist/core/chunk-checks.d.ts +0 -39
- package/dist/core/chunk-stream.d.ts +0 -22
- package/dist/core/chunk-window.d.ts +0 -37
- package/dist/core/combine-ledger.d.ts +0 -43
- package/dist/core/crbm/crc32c.d.ts +0 -10
- package/dist/core/crbm/fingerprint.d.ts +0 -23
- package/dist/core/crbm/format.d.ts +0 -150
- package/dist/core/crbm/frame.d.ts +0 -10
- package/dist/core/crbm/plan-reads.d.ts +0 -50
- package/dist/core/crbm/varint.d.ts +0 -14
- package/dist/core/crbm/writer.d.ts +0 -72
- package/dist/core/crbm-open.d.ts +0 -154
- package/dist/core/crbm-write.d.ts +0 -75
- package/dist/core/due-index.d.ts +0 -53
- package/dist/core/generation-gc.d.ts +0 -293
- package/dist/core/generation-list.d.ts +0 -11
- package/dist/core/id-window.d.ts +0 -46
- package/dist/core/invalidation-scope.d.ts +0 -77
- package/dist/core/item-pull.d.ts +0 -29
- package/dist/core/known-generations-shape.d.ts +0 -13
- package/dist/core/known-generations.d.ts +0 -147
- package/dist/core/ledger-seed.d.ts +0 -17
- package/dist/core/metadata.d.ts +0 -42
- package/dist/core/order.d.ts +0 -2
- package/dist/core/publish.d.ts +0 -207
- package/dist/core/reader-defaults.d.ts +0 -29
- package/dist/core/summary.d.ts +0 -110
- package/dist/core/token.d.ts +0 -41
- package/dist/drivers/_shared/entropy.d.ts +0 -5
- package/dist/drivers/_shared/registry.d.ts +0 -107
- package/dist/drivers/localfs/exact-case.d.ts +0 -34
- package/dist/drivers/localfs/fs-util.d.ts +0 -55
- package/dist/drivers/localfs/paths.d.ts +0 -40
- package/dist/drivers/localfs/registry.d.ts +0 -50
- package/dist/drivers/localfs/storage.d.ts +0 -28
- package/dist/drivers/memory.d.ts +0 -64
- package/dist/testing/fuzz-core.d.ts +0 -15
|
@@ -3,8 +3,9 @@ var ERROR_BRAND = /* @__PURE__ */ Symbol.for("cloudbitmaps.error");
|
|
|
3
3
|
var TRANSIENT_BRAND = /* @__PURE__ */ Symbol.for("cloudbitmaps.error.transient");
|
|
4
4
|
var NAMES = /* @__PURE__ */ new WeakMap();
|
|
5
5
|
var CloudRoaringError = class extends Error {
|
|
6
|
-
/** Cross-bundle brand — see
|
|
6
|
+
/** Cross-bundle brand — see {@link errorKind}. Non-enumerable-ish (symbol key ⇒ not in JSON). */
|
|
7
7
|
[ERROR_BRAND] = true;
|
|
8
|
+
/** Builds the error from `message`, and sets `name` to the class's name as written. */
|
|
8
9
|
constructor(message) {
|
|
9
10
|
super(message);
|
|
10
11
|
this.name = NAMES.get(new.target) ?? new.target.name;
|
|
@@ -12,6 +13,7 @@ var CloudRoaringError = class extends Error {
|
|
|
12
13
|
};
|
|
13
14
|
var ValidationError = class extends CloudRoaringError {
|
|
14
15
|
};
|
|
16
|
+
var CONTENTION_NEXT_STEP = "; another writer changed the segment's row while this call ran. Re-run the call: it reads the row afresh";
|
|
15
17
|
var WriteConflictError = class extends CloudRoaringError {
|
|
16
18
|
};
|
|
17
19
|
var IntegrityError = class extends CloudRoaringError {
|
|
@@ -23,6 +25,7 @@ var LeaseExpiredError = class extends CloudRoaringError {
|
|
|
23
25
|
until;
|
|
24
26
|
/** `'expired'` when the clock reached `until`, `'released'` after `release()`. */
|
|
25
27
|
reason;
|
|
28
|
+
/** Builds the error from its `message`, the epoch-ms the lease ran until, and why it ended. */
|
|
26
29
|
constructor(message, until, reason) {
|
|
27
30
|
super(message);
|
|
28
31
|
this.until = until;
|
|
@@ -32,11 +35,13 @@ var LeaseExpiredError = class extends CloudRoaringError {
|
|
|
32
35
|
var LeaseLimitError = class extends CloudRoaringError {
|
|
33
36
|
};
|
|
34
37
|
var StaleOperandError = class extends CloudRoaringError {
|
|
38
|
+
/** The stable code `'stale-operand'`, to match on. */
|
|
35
39
|
code = "stale-operand";
|
|
36
40
|
/** The operand's name in the call that found it stale. */
|
|
37
41
|
operand;
|
|
38
42
|
/** Why it is stale. */
|
|
39
43
|
reason;
|
|
44
|
+
/** Builds the error from its `message`, the operand's name and why it is stale. */
|
|
40
45
|
constructor(message, operand, reason) {
|
|
41
46
|
super(message);
|
|
42
47
|
this.operand = operand;
|
|
@@ -48,12 +53,29 @@ var UnsupportedError = class extends CloudRoaringError {
|
|
|
48
53
|
var CapabilityError = class extends CloudRoaringError {
|
|
49
54
|
};
|
|
50
55
|
var BudgetExceededError = class extends CloudRoaringError {
|
|
56
|
+
/** The option to raise to let the call through. */
|
|
57
|
+
option;
|
|
58
|
+
/** The bound in force: requests, bytes or rows, by `option`. */
|
|
59
|
+
limit;
|
|
60
|
+
/**
|
|
61
|
+
* What the call had reached when refused. By `option`: the requests the call needs (`'budget.maxRequests'`), a
|
|
62
|
+
* lower bound on the resident bytes it needs (`'maxBufferedBytes'`), or `limit + 1` (`'maxScanSegments'`).
|
|
63
|
+
*/
|
|
64
|
+
spent;
|
|
65
|
+
/** Builds the error from its `message` and the `option`, `limit` and `spent` it reports. */
|
|
66
|
+
constructor(message, details) {
|
|
67
|
+
super(message);
|
|
68
|
+
this.option = details.option;
|
|
69
|
+
this.limit = details.limit;
|
|
70
|
+
this.spent = details.spent;
|
|
71
|
+
}
|
|
51
72
|
};
|
|
52
73
|
var KeyUnavailableError = class extends CloudRoaringError {
|
|
53
74
|
};
|
|
54
75
|
var TransientError = class extends CloudRoaringError {
|
|
55
76
|
/** A second brand so a transient fault is classifiable cross-bundle. */
|
|
56
77
|
[TRANSIENT_BRAND] = true;
|
|
78
|
+
/** Builds the error from `message`; `options.cause`, when given, is kept as `cause`. */
|
|
57
79
|
constructor(message, options) {
|
|
58
80
|
super(message);
|
|
59
81
|
if (options && "cause" in options) this.cause = options.cause;
|
|
@@ -81,17 +103,17 @@ function isCloudRoaringError(err) {
|
|
|
81
103
|
function isWriteConflictError(err) {
|
|
82
104
|
return isCloudRoaringError(err) && err.name === "WriteConflictError";
|
|
83
105
|
}
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
var UNSETTLED_BRAND = /* @__PURE__ */ Symbol.for("cloudbitmaps.error.unsettled-conflict");
|
|
107
|
+
function unsettledConflict(message) {
|
|
108
|
+
const err = new WriteConflictError(message);
|
|
109
|
+
Object.defineProperty(err, UNSETTLED_BRAND, { value: true });
|
|
110
|
+
return err;
|
|
86
111
|
}
|
|
87
|
-
function
|
|
88
|
-
return
|
|
112
|
+
function isUnsettledConflict(err) {
|
|
113
|
+
return isWriteConflictError(err) && hasBrand(err, UNSETTLED_BRAND);
|
|
89
114
|
}
|
|
90
|
-
function
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
function isLeaseLimitError(err) {
|
|
94
|
-
return isCloudRoaringError(err) && err.name === "LeaseLimitError";
|
|
115
|
+
function isTransientError(err) {
|
|
116
|
+
return hasBrand(err, TRANSIENT_BRAND);
|
|
95
117
|
}
|
|
96
118
|
function isNotFoundError(err) {
|
|
97
119
|
return isCloudRoaringError(err) && err.name === "NotFoundError";
|
|
@@ -102,32 +124,29 @@ function isIntegrityError(err) {
|
|
|
102
124
|
function isValidationError(err) {
|
|
103
125
|
return isCloudRoaringError(err) && err.name === "ValidationError";
|
|
104
126
|
}
|
|
105
|
-
function isUnsupportedError(err) {
|
|
106
|
-
return isCloudRoaringError(err) && err.name === "UnsupportedError";
|
|
107
|
-
}
|
|
108
|
-
function isCapabilityError(err) {
|
|
109
|
-
return isCloudRoaringError(err) && err.name === "CapabilityError";
|
|
110
|
-
}
|
|
111
|
-
function isBudgetExceededError(err) {
|
|
112
|
-
return isCloudRoaringError(err) && err.name === "BudgetExceededError";
|
|
113
|
-
}
|
|
114
127
|
function isKeyUnavailableError(err) {
|
|
115
128
|
return isCloudRoaringError(err) && err.name === "KeyUnavailableError";
|
|
116
129
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
var KIND_NAMES = {
|
|
131
|
+
CloudRoaringError: true,
|
|
132
|
+
ValidationError: true,
|
|
133
|
+
WriteConflictError: true,
|
|
134
|
+
IntegrityError: true,
|
|
135
|
+
NotFoundError: true,
|
|
136
|
+
UnsupportedError: true,
|
|
137
|
+
CapabilityError: true,
|
|
138
|
+
TransientError: true,
|
|
139
|
+
KeyUnavailableError: true,
|
|
140
|
+
BudgetExceededError: true,
|
|
141
|
+
LeaseExpiredError: true,
|
|
142
|
+
LeaseLimitError: true,
|
|
143
|
+
StaleOperandError: true
|
|
144
|
+
};
|
|
145
|
+
function errorKind(err) {
|
|
146
|
+
if (hasBrand(err, TRANSIENT_BRAND)) return "TransientError";
|
|
147
|
+
if (!hasBrand(err, ERROR_BRAND)) return void 0;
|
|
148
|
+
const name = err.name;
|
|
149
|
+
return typeof name === "string" && Object.hasOwn(KIND_NAMES, name) ? name : "CloudRoaringError";
|
|
131
150
|
}
|
|
132
151
|
|
|
133
152
|
// src/core/check.ts
|
|
@@ -153,6 +172,11 @@ function requireInteger(value, bounds) {
|
|
|
153
172
|
}
|
|
154
173
|
return value;
|
|
155
174
|
}
|
|
175
|
+
function checkRequireEncryption(value) {
|
|
176
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
177
|
+
throw new ValidationError(`requireEncryption must be a boolean; got ${shown(value)}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
156
180
|
function requirePositiveInteger(value, what) {
|
|
157
181
|
return requireInteger(value, { min: 1, what });
|
|
158
182
|
}
|
|
@@ -165,69 +189,71 @@ function requireFiniteNumber(value, bounds) {
|
|
|
165
189
|
}
|
|
166
190
|
return value;
|
|
167
191
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
results[i] = await fn(items[i], i);
|
|
182
|
-
} catch (err) {
|
|
183
|
-
if (!failed) {
|
|
184
|
-
failed = true;
|
|
185
|
-
firstError = err;
|
|
186
|
-
}
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
const workers = Array.from({ length: Math.min(limit, items.length) }, () => worker());
|
|
192
|
-
await Promise.all(workers);
|
|
193
|
-
if (failed) throw firstError;
|
|
194
|
-
return results;
|
|
192
|
+
function refuseUnknownOptions(name, options, keys, hint) {
|
|
193
|
+
if (options === null || typeof options !== "object") {
|
|
194
|
+
throw new ValidationError(
|
|
195
|
+
`${name} needs an options object \u2014 got ${options === null ? "null" : typeof options}`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const unknown = Object.keys(options).filter((k) => !keys.includes(k));
|
|
199
|
+
if (unknown.length > 0) {
|
|
200
|
+
const list = (ks) => ks.map((k) => `\`${k}\``).join(", ");
|
|
201
|
+
throw new ValidationError(
|
|
202
|
+
`${name} does not take ${list(unknown)}. It takes ${list(keys)}${hint === void 0 ? "" : `; ${hint}`}.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
195
205
|
}
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return Promise.reject(err);
|
|
206
|
+
function requireBool(name, value) {
|
|
207
|
+
if (value === void 0) return void 0;
|
|
208
|
+
if (typeof value !== "boolean") {
|
|
209
|
+
throw new ValidationError(`${name} must be a boolean; got ${shown(value)}`);
|
|
201
210
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
function requireNonEmptyString(name, value) {
|
|
214
|
+
if (value === void 0) return void 0;
|
|
215
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
216
|
+
throw new ValidationError(
|
|
217
|
+
`${name} must be a non-empty string; got ${typeof value === "string" ? "an empty string" : shown(value)}`
|
|
218
|
+
);
|
|
211
219
|
}
|
|
212
|
-
return
|
|
220
|
+
return value;
|
|
213
221
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
222
|
+
|
|
223
|
+
// src/core/bit-route.ts
|
|
224
|
+
var U32_MAX = 4294967295;
|
|
225
|
+
var CHUNK_COUNT = 65536;
|
|
226
|
+
var LOW_16 = 65535;
|
|
227
|
+
var idErrors = /* @__PURE__ */ new WeakSet();
|
|
228
|
+
function isBadIdError(err) {
|
|
229
|
+
return err instanceof ValidationError && idErrors.has(err);
|
|
230
|
+
}
|
|
231
|
+
function badId(id) {
|
|
232
|
+
let got;
|
|
233
|
+
if (id === null) got = "null";
|
|
234
|
+
else if (id === void 0) got = "undefined";
|
|
235
|
+
else if (typeof id === "object") got = "an object";
|
|
236
|
+
else if (typeof id !== "number") got = `${/^[aeiou]/.test(typeof id) ? "an" : "a"} ${typeof id}`;
|
|
237
|
+
else if (!Number.isFinite(id)) got = "NaN or an infinity";
|
|
238
|
+
else if (id < 0) got = "a negative number";
|
|
239
|
+
else if (!Number.isInteger(id)) got = "a number with a fraction";
|
|
240
|
+
else got = `a number above ${U32_MAX} (ids are 32-bit)`;
|
|
241
|
+
const err = new ValidationError(`an id must be an integer from 0 to ${U32_MAX}; got ${got}`);
|
|
242
|
+
idErrors.add(err);
|
|
243
|
+
return err;
|
|
244
|
+
}
|
|
245
|
+
function refusalOfId(id) {
|
|
246
|
+
return badId(id);
|
|
247
|
+
}
|
|
248
|
+
function splitId(id) {
|
|
249
|
+
if (!Number.isInteger(id) || id < 0 || id > U32_MAX) {
|
|
250
|
+
throw badId(id);
|
|
251
|
+
}
|
|
252
|
+
return { chunkKey: id >>> 16, remainder: id & LOW_16 };
|
|
253
|
+
}
|
|
254
|
+
var MAX_REMAINDER = CHUNK_COUNT - 1;
|
|
255
|
+
function joinId(chunkKey, remainder) {
|
|
256
|
+
return ((chunkKey & LOW_16) << 16 >>> 0) + (remainder & LOW_16);
|
|
231
257
|
}
|
|
232
258
|
|
|
233
259
|
// src/core/name-codec.ts
|
|
@@ -322,7 +348,15 @@ function validatePart(value, field) {
|
|
|
322
348
|
);
|
|
323
349
|
}
|
|
324
350
|
}
|
|
351
|
+
var REF_KEYS = ["segment", "namespace", "currentGen", "status"];
|
|
352
|
+
function requireRefObject(ref, hint = "") {
|
|
353
|
+
if (typeof ref !== "object" || ref === null) {
|
|
354
|
+
throw new ValidationError(`a segment ref is an object such as { segment: 'name' }${hint}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
325
357
|
function validateSegmentRef(ref) {
|
|
358
|
+
requireRefObject(ref);
|
|
359
|
+
refuseUnknownKeys(ref);
|
|
326
360
|
validatePart(ref.segment, "segment");
|
|
327
361
|
if (ref.namespace !== void 0) validatePart(ref.namespace, "namespace");
|
|
328
362
|
}
|
|
@@ -338,7 +372,56 @@ function validateUserNamespace(namespace) {
|
|
|
338
372
|
);
|
|
339
373
|
}
|
|
340
374
|
}
|
|
341
|
-
|
|
375
|
+
var PORT_KEYS = [
|
|
376
|
+
"generation",
|
|
377
|
+
"chunkKey",
|
|
378
|
+
"wrappedDeks",
|
|
379
|
+
"keyId",
|
|
380
|
+
"retention",
|
|
381
|
+
"residency",
|
|
382
|
+
"summary",
|
|
383
|
+
"knownGens",
|
|
384
|
+
"leases",
|
|
385
|
+
"createdAt",
|
|
386
|
+
"updatedAt",
|
|
387
|
+
"token",
|
|
388
|
+
"pointerId"
|
|
389
|
+
];
|
|
390
|
+
var SEGMENT_HANDLE_MARK = /* @__PURE__ */ Symbol.for("cloudbitmaps.roaring.segment/1");
|
|
391
|
+
function unknownKeysOf(ref, extraKeys) {
|
|
392
|
+
return Object.keys(ref).filter(
|
|
393
|
+
(k) => !REF_KEYS.includes(k) && !extraKeys.includes(k)
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
function refuseUnknownKeys(ref) {
|
|
397
|
+
const unknown = unknownKeysOf(ref, PORT_KEYS);
|
|
398
|
+
if (unknown.length === 0) return;
|
|
399
|
+
const list = unknown.map((k) => `"${k}"`).join(", ");
|
|
400
|
+
throw new ValidationError(
|
|
401
|
+
`a driver port: unknown ${unknown.length === 1 ? "key" : "keys"} ${list} in the segment ref; it takes { segment, namespace } and a generation key's \`generation\`, a chunk ref's \`chunkKey\`, a \`segments()\` row's \`currentGen\` and \`status\`, or a registry row's own fields (a segment addressed without its namespace is a different segment)`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
function refuseUnknownRefKeys(ref, verb, extraKeys = []) {
|
|
405
|
+
if (ref[SEGMENT_HANDLE_MARK] === true) {
|
|
406
|
+
throw new ValidationError(
|
|
407
|
+
`${verb}: a segment handle is not a ref; pass { segment, namespace }`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
if (Array.isArray(ref)) {
|
|
411
|
+
throw new ValidationError(
|
|
412
|
+
`${verb}: a segment ref is an object such as { segment: 'name' }, not an array`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
const unknown = unknownKeysOf(ref, extraKeys);
|
|
416
|
+
if (unknown.length === 0) return;
|
|
417
|
+
const list = unknown.map((k) => `"${k}"`).join(", ");
|
|
418
|
+
throw new ValidationError(
|
|
419
|
+
`${verb}: unknown ${unknown.length === 1 ? "key" : "keys"} ${list} in the segment ref; a ref takes { segment, namespace } (and a \`segments()\` row's \`currentGen\` and \`status\`, which are read for nothing); a segment addressed without its namespace is a different segment`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
function validateUserRef(ref, verb, extraKeys = []) {
|
|
423
|
+
requireRefObject(ref, "; store.segment() takes the bare name");
|
|
424
|
+
if (verb !== void 0) refuseUnknownRefKeys(ref, verb, extraKeys);
|
|
342
425
|
validatePart(ref.segment, "segment");
|
|
343
426
|
if (ref.namespace !== void 0) validateUserNamespace(ref.namespace);
|
|
344
427
|
}
|
|
@@ -401,6 +484,22 @@ function isStorageBackend(value) {
|
|
|
401
484
|
return typeof value === "object" && value !== null && value[STORAGE_BACKEND_BRAND] === true;
|
|
402
485
|
}
|
|
403
486
|
|
|
487
|
+
// src/core/token.ts
|
|
488
|
+
var INCARNATION_TOKEN = /^([0-9a-f]{32})\.(0|[1-9]\d*)\.([0-9a-f]{16})$/;
|
|
489
|
+
function incarnationOf(token) {
|
|
490
|
+
return INCARNATION_TOKEN.exec(token)?.[1];
|
|
491
|
+
}
|
|
492
|
+
function incarnationField(token) {
|
|
493
|
+
const incarnation = token === void 0 ? void 0 : incarnationOf(token);
|
|
494
|
+
return incarnation === void 0 ? {} : { incarnation };
|
|
495
|
+
}
|
|
496
|
+
function sameIncarnation(a, b) {
|
|
497
|
+
const ia = incarnationOf(a.token);
|
|
498
|
+
const ib = incarnationOf(b.token);
|
|
499
|
+
if (ia !== void 0 || ib !== void 0) return ia === ib;
|
|
500
|
+
return a.createdAt === b.createdAt;
|
|
501
|
+
}
|
|
502
|
+
|
|
404
503
|
// src/core/pointer-id.ts
|
|
405
504
|
var RESOLVED_FIELDS = [
|
|
406
505
|
"currentGen",
|
|
@@ -424,6 +523,11 @@ function pointerIdOf(row) {
|
|
|
424
523
|
}
|
|
425
524
|
return pointerId;
|
|
426
525
|
}
|
|
526
|
+
function pointerSetBy(now, before, generation, sent) {
|
|
527
|
+
if (now === null || now.status === "destroyed" || now.currentGen !== generation) return false;
|
|
528
|
+
if (before !== null && !sameIncarnation(before, now)) return false;
|
|
529
|
+
return sent.has(now.pointerId);
|
|
530
|
+
}
|
|
427
531
|
|
|
428
532
|
// src/core/crypto.ts
|
|
429
533
|
var UTF82 = new TextEncoder();
|
|
@@ -516,22 +620,6 @@ async function withRetry(op, policy, deps) {
|
|
|
516
620
|
throw lastErr;
|
|
517
621
|
}
|
|
518
622
|
|
|
519
|
-
// src/core/token.ts
|
|
520
|
-
var INCARNATION_TOKEN = /^([0-9a-f]{32})\.(0|[1-9]\d*)\.([0-9a-f]{16})$/;
|
|
521
|
-
function incarnationOf(token) {
|
|
522
|
-
return INCARNATION_TOKEN.exec(token)?.[1];
|
|
523
|
-
}
|
|
524
|
-
function incarnationField(token) {
|
|
525
|
-
const incarnation = token === void 0 ? void 0 : incarnationOf(token);
|
|
526
|
-
return incarnation === void 0 ? {} : { incarnation };
|
|
527
|
-
}
|
|
528
|
-
function sameIncarnation(a, b) {
|
|
529
|
-
const ia = incarnationOf(a.token);
|
|
530
|
-
const ib = incarnationOf(b.token);
|
|
531
|
-
if (ia !== void 0 || ib !== void 0) return ia === ib;
|
|
532
|
-
return a.createdAt === b.createdAt;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
623
|
// src/core/leases.ts
|
|
536
624
|
var MAX_LEASE_MS = 14 * 864e5;
|
|
537
625
|
var LEASE_SKEW_MS = 6e4;
|
|
@@ -657,7 +745,9 @@ async function takeLease(ref, deps, take) {
|
|
|
657
745
|
}
|
|
658
746
|
}
|
|
659
747
|
if (unanswered !== void 0) throw unanswered;
|
|
660
|
-
throw new WriteConflictError(
|
|
748
|
+
throw new WriteConflictError(
|
|
749
|
+
`lease: contention taking a lease on segment "${ref.segment}"${CONTENTION_NEXT_STEP}`
|
|
750
|
+
);
|
|
661
751
|
}
|
|
662
752
|
async function releaseLease(ref, deps, holder) {
|
|
663
753
|
let resends = 0;
|
|
@@ -691,54 +781,9 @@ async function releaseLease(ref, deps, holder) {
|
|
|
691
781
|
}
|
|
692
782
|
}
|
|
693
783
|
if (unanswered !== void 0) throw unanswered;
|
|
694
|
-
throw new WriteConflictError(
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// src/drivers/_shared/keys.ts
|
|
698
|
-
var DEFAULT_NAMESPACE = "_default";
|
|
699
|
-
function namespaceKeyPart(namespace) {
|
|
700
|
-
return namespace === void 0 ? DEFAULT_NAMESPACE : encodeNameForKey(namespace);
|
|
701
|
-
}
|
|
702
|
-
function namespacePathPart(namespace) {
|
|
703
|
-
return namespace === void 0 ? DEFAULT_NAMESPACE : encodeNameForPath(namespace);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
// src/drivers/_shared/options.ts
|
|
707
|
-
function refuseUnknownOptions(name, options, keys, hint) {
|
|
708
|
-
if (options === null || typeof options !== "object") {
|
|
709
|
-
throw new ValidationError(
|
|
710
|
-
`${name} needs an options object \u2014 got ${options === null ? "null" : typeof options}`
|
|
711
|
-
);
|
|
712
|
-
}
|
|
713
|
-
const unknown = Object.keys(options).filter((k) => !keys.includes(k));
|
|
714
|
-
if (unknown.length > 0) {
|
|
715
|
-
const list = (ks) => ks.map((k) => `\`${k}\``).join(", ");
|
|
716
|
-
throw new ValidationError(
|
|
717
|
-
`${name} does not take ${list(unknown)}. It takes ${list(keys)}${hint === void 0 ? "" : `; ${hint}`}.`
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
function checkNow(name, now) {
|
|
722
|
-
if (now !== void 0 && typeof now !== "function") {
|
|
723
|
-
throw new ValidationError(`${name}: \`now\` must be a function returning epoch milliseconds`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
function requirePositiveInt(name, value) {
|
|
727
|
-
return value === void 0 ? void 0 : requirePositiveInteger(value, name);
|
|
728
|
-
}
|
|
729
|
-
function requireBool(name, value) {
|
|
730
|
-
if (value === void 0) return void 0;
|
|
731
|
-
if (typeof value !== "boolean") {
|
|
732
|
-
throw new ValidationError(`${name} must be a boolean; got ${shown2(value)}`);
|
|
733
|
-
}
|
|
734
|
-
return value;
|
|
735
|
-
}
|
|
736
|
-
function shown2(value) {
|
|
737
|
-
if (typeof value === "string") return JSON.stringify(value);
|
|
738
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
739
|
-
return String(value);
|
|
740
|
-
}
|
|
741
|
-
return value === null ? "null" : typeof value;
|
|
784
|
+
throw new WriteConflictError(
|
|
785
|
+
`lease: contention releasing a lease on segment "${ref.segment}"${CONTENTION_NEXT_STEP}`
|
|
786
|
+
);
|
|
742
787
|
}
|
|
743
788
|
|
|
744
789
|
// src/core/crbm/frame.ts
|
|
@@ -1019,35 +1064,6 @@ function ownSummary(ref, generation, description, aead) {
|
|
|
1019
1064
|
return summary;
|
|
1020
1065
|
}
|
|
1021
1066
|
|
|
1022
|
-
// src/core/known-generations-shape.ts
|
|
1023
|
-
var ENTRY_KEYS = ["generation", "footerCrc"];
|
|
1024
|
-
function knownGensShapeFault(value, max, show = String) {
|
|
1025
|
-
if (value === void 0) return void 0;
|
|
1026
|
-
if (!Array.isArray(value)) return "must be an array";
|
|
1027
|
-
const list = value;
|
|
1028
|
-
if (list.length > max) return `has ${list.length} entries, cap ${max}`;
|
|
1029
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1030
|
-
for (const e of list) {
|
|
1031
|
-
if (typeof e !== "object" || e === null || Array.isArray(e))
|
|
1032
|
-
return "an entry must be an object";
|
|
1033
|
-
const entry = e;
|
|
1034
|
-
const extra = Object.keys(entry).filter((k) => !ENTRY_KEYS.includes(k));
|
|
1035
|
-
if (extra.length > 0) {
|
|
1036
|
-
return `an entry carries an undeclared field (${show(extra.join(", "))})`;
|
|
1037
|
-
}
|
|
1038
|
-
const { generation, footerCrc } = entry;
|
|
1039
|
-
if (!Number.isSafeInteger(generation) || generation < 0) {
|
|
1040
|
-
return `a generation must be a non-negative safe integer (got ${show(generation)})`;
|
|
1041
|
-
}
|
|
1042
|
-
if (!Number.isInteger(footerCrc) || footerCrc < 0 || footerCrc > 4294967295) {
|
|
1043
|
-
return `a footerCrc must be an integer from 0 to 2^32 - 1 (got ${show(footerCrc)})`;
|
|
1044
|
-
}
|
|
1045
|
-
if (seen.has(generation)) return `generation ${String(generation)} is repeated`;
|
|
1046
|
-
seen.add(generation);
|
|
1047
|
-
}
|
|
1048
|
-
return void 0;
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
1067
|
// src/core/order.ts
|
|
1052
1068
|
var ascending = (a, b) => a - b;
|
|
1053
1069
|
|
|
@@ -1200,558 +1216,39 @@ function leasedByRow(record) {
|
|
|
1200
1216
|
return new Set((record.leases ?? []).map((e) => e.generation));
|
|
1201
1217
|
}
|
|
1202
1218
|
|
|
1203
|
-
// src/
|
|
1204
|
-
var
|
|
1205
|
-
|
|
1206
|
-
"namespace",
|
|
1207
|
-
"segment",
|
|
1208
|
-
"currentGen",
|
|
1209
|
-
"wrappedDeks",
|
|
1210
|
-
"keyId",
|
|
1211
|
-
"status",
|
|
1212
|
-
"retention",
|
|
1213
|
-
"residency",
|
|
1214
|
-
"summary",
|
|
1215
|
-
"createdAt",
|
|
1216
|
-
"updatedAt",
|
|
1217
|
-
"token",
|
|
1218
|
-
"knownGens",
|
|
1219
|
-
"leases",
|
|
1220
|
-
"pointerId"
|
|
1221
|
-
];
|
|
1222
|
-
var DRIVER_MANAGED = ["token", "pointerId"];
|
|
1223
|
-
var ENVELOPE_FIELDS = ["schemaVersion", "deleted", "record"];
|
|
1224
|
-
var MAX_GOVERNANCE_BYTES = 64 * 1024;
|
|
1225
|
-
var MAX_WRAPPED_DEKS = 8;
|
|
1226
|
-
var MAX_WRAPPED_DEK_BYTES = 4 * 1024;
|
|
1227
|
-
var SEALED_SUMMARY_MIN_BYTES = 12 + 8 + 8 + 4 + 4 + 16;
|
|
1228
|
-
var SEALED_SUMMARY_MAX_BYTES = SEALED_SUMMARY_MIN_BYTES + MAX_METADATA_BYTES;
|
|
1229
|
-
var BASE642 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
1230
|
-
function validateGeneration(gen) {
|
|
1231
|
-
if (gen === null) return;
|
|
1232
|
-
if (!Number.isSafeInteger(gen) || gen < 0) {
|
|
1233
|
-
throw new ValidationError(
|
|
1234
|
-
`currentGen must be a non-negative safe integer or null (no Storage generation yet); got ${gen}`
|
|
1235
|
-
);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
function validatePatchGeneration(patch) {
|
|
1239
|
-
if (!("currentGen" in patch)) return;
|
|
1240
|
-
if (patch.currentGen === void 0) {
|
|
1241
|
-
throw new ValidationError(
|
|
1242
|
-
`currentGen was present in the patch but undefined. Pass \`null\` to clear the pointer (the segment has no Storage generation), or omit the key to leave it unchanged \u2014 an undefined value is refused because it would un-publish the segment's Storage data.`
|
|
1243
|
-
);
|
|
1244
|
-
}
|
|
1245
|
-
validateGeneration(patch.currentGen);
|
|
1246
|
-
}
|
|
1247
|
-
function validateStatus(status) {
|
|
1248
|
-
if (!STATUSES.includes(status)) {
|
|
1249
|
-
throw new ValidationError(`status must be one of ${STATUSES.join("/")}; got ${status}`);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
function validateGovernance(meta, field) {
|
|
1253
|
-
if (meta === void 0) return;
|
|
1254
|
-
if (meta === null || typeof meta !== "object" || Array.isArray(meta)) {
|
|
1255
|
-
throw new ValidationError(
|
|
1256
|
-
`${field} must be a plain object (got ${meta === null ? "null" : typeof meta})`
|
|
1257
|
-
);
|
|
1258
|
-
}
|
|
1259
|
-
let json;
|
|
1260
|
-
try {
|
|
1261
|
-
json = JSON.stringify(meta);
|
|
1262
|
-
} catch {
|
|
1263
|
-
throw new ValidationError(`${field} must be JSON-serializable`);
|
|
1264
|
-
}
|
|
1265
|
-
if (json.length > MAX_GOVERNANCE_BYTES) {
|
|
1266
|
-
throw new ValidationError(`${field} is ${json.length}B, exceeds cap ${MAX_GOVERNANCE_BYTES}B`);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
function validateWrappedDeks(value, origin) {
|
|
1270
|
-
if (value === void 0) return;
|
|
1271
|
-
const fail = (msg) => {
|
|
1272
|
-
throw origin === "stored" ? new IntegrityError(msg) : new ValidationError(msg);
|
|
1273
|
-
};
|
|
1274
|
-
if (!Array.isArray(value)) fail("wrappedDeks must be an array");
|
|
1275
|
-
const list = value;
|
|
1276
|
-
if (list.length === 0) fail("wrappedDeks must be non-empty when present");
|
|
1277
|
-
if (list.length > MAX_WRAPPED_DEKS)
|
|
1278
|
-
fail(`wrappedDeks has ${list.length} entries, cap ${MAX_WRAPPED_DEKS}`);
|
|
1279
|
-
for (const w of list) {
|
|
1280
|
-
if (w === null || typeof w !== "object") fail("wrappedDeks entry must be an object");
|
|
1281
|
-
const { keyId, wrapped } = w;
|
|
1282
|
-
if (typeof keyId !== "string" || keyId.length === 0)
|
|
1283
|
-
fail("wrappedDeks entry needs a non-empty keyId");
|
|
1284
|
-
if (typeof wrapped !== "string" || wrapped.length === 0)
|
|
1285
|
-
fail("wrappedDeks entry needs a non-empty wrapped blob");
|
|
1286
|
-
if (wrapped.length > MAX_WRAPPED_DEK_BYTES)
|
|
1287
|
-
fail(`wrappedDeks entry is ${wrapped.length}B, cap ${MAX_WRAPPED_DEK_BYTES}B`);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
1291
|
-
function base64PadBitsAreZero(text) {
|
|
1292
|
-
const pad = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
|
|
1293
|
-
if (pad === 0) return true;
|
|
1294
|
-
const last = BASE64_ALPHABET.indexOf(text[text.length - pad - 1]);
|
|
1295
|
-
return pad === 2 ? (last & 15) === 0 : (last & 3) === 0;
|
|
1296
|
-
}
|
|
1297
|
-
function validateSummary(value, origin, ctx) {
|
|
1298
|
-
if (value === void 0) return void 0;
|
|
1299
|
-
const fail = (msg) => {
|
|
1300
|
-
const where = ctx === void 0 ? "" : `: ${ctx}`;
|
|
1301
|
-
throw origin === "stored" ? new IntegrityError(`registry record summary: ${msg}${where}`) : new ValidationError(`summary: ${msg}${where}`);
|
|
1302
|
-
};
|
|
1303
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1304
|
-
fail(
|
|
1305
|
-
`must be an object (got ${value === null ? "null" : Array.isArray(value) ? "an array" : typeof value})`
|
|
1306
|
-
);
|
|
1307
|
-
}
|
|
1308
|
-
const s = value;
|
|
1309
|
-
const keys = Object.keys(s);
|
|
1310
|
-
const isSealed = keys.includes("sealed");
|
|
1311
|
-
const allowed = isSealed ? ["generation", "sealed"] : ["generation", "cardinality", "fingerprint", "tailBytes", "metadata"];
|
|
1312
|
-
const extra = keys.filter((k) => !allowed.includes(k));
|
|
1313
|
-
if (extra.length > 0) {
|
|
1314
|
-
fail(
|
|
1315
|
-
`has fields its ${isSealed ? "sealed" : "clear"} shape does not declare (${extra.join(", ")})`
|
|
1316
|
-
);
|
|
1317
|
-
}
|
|
1318
|
-
const generation = s.generation;
|
|
1319
|
-
if (!Number.isSafeInteger(generation) || generation < 0) {
|
|
1320
|
-
fail(`generation must be a non-negative safe integer (got ${String(generation)})`);
|
|
1321
|
-
}
|
|
1322
|
-
if (isSealed) {
|
|
1323
|
-
const sealed = s.sealed;
|
|
1324
|
-
if (typeof sealed !== "string" || !BASE642.test(sealed) || !base64PadBitsAreZero(sealed)) {
|
|
1325
|
-
fail("sealed must be canonical, padded standard base64");
|
|
1326
|
-
}
|
|
1327
|
-
const text = sealed;
|
|
1328
|
-
const bytes = text.length / 4 * 3 - (text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0);
|
|
1329
|
-
if (bytes < SEALED_SUMMARY_MIN_BYTES || bytes > SEALED_SUMMARY_MAX_BYTES) {
|
|
1330
|
-
fail(
|
|
1331
|
-
`sealed is ${bytes}B, outside ${SEALED_SUMMARY_MIN_BYTES}..${SEALED_SUMMARY_MAX_BYTES}B (a nonce, a fixed-width count, fingerprint and tail size, a tag, and metadata up to its cap)`
|
|
1332
|
-
);
|
|
1333
|
-
}
|
|
1334
|
-
return Object.freeze({ generation, sealed: text });
|
|
1335
|
-
}
|
|
1336
|
-
const n = s.cardinality;
|
|
1337
|
-
if (!Number.isInteger(n) || n < 0 || n > MAX_SUMMARY_CARDINALITY) {
|
|
1338
|
-
fail(`cardinality must be an integer from 0 to 2^32 (got ${String(n)})`);
|
|
1339
|
-
}
|
|
1340
|
-
const fingerprint = s.fingerprint;
|
|
1341
|
-
const parts = fingerprintParts(fingerprint);
|
|
1342
|
-
if (parts === void 0) {
|
|
1343
|
-
fail(
|
|
1344
|
-
`fingerprint must be an object's, <size>:<footer checksum> in decimal (got ${shown3(JSON.stringify(fingerprint))})`
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
const tailBytes = s.tailBytes;
|
|
1348
|
-
if (!tailBytesFit(tailBytes, parts.size)) {
|
|
1349
|
-
fail(
|
|
1350
|
-
`tailBytes must be an integer from the footer's size to the object's size less its preamble, and at most the cap of one open's tail read (got ${shown3(JSON.stringify(tailBytes))} for an object of ${parts.size} bytes)`
|
|
1351
|
-
);
|
|
1352
|
-
}
|
|
1353
|
-
if (s.metadata === void 0) {
|
|
1354
|
-
return Object.freeze({
|
|
1355
|
-
generation,
|
|
1356
|
-
cardinality: n,
|
|
1357
|
-
fingerprint,
|
|
1358
|
-
tailBytes
|
|
1359
|
-
});
|
|
1360
|
-
}
|
|
1361
|
-
const canonical = canonicalMetadataJson(s.metadata, fail);
|
|
1362
|
-
if (canonical === "{}") fail("metadata is empty; a generation without metadata carries none");
|
|
1363
|
-
if (origin === "stored") return s;
|
|
1364
|
-
const metadata = Object.freeze(JSON.parse(canonical));
|
|
1365
|
-
return Object.freeze({
|
|
1366
|
-
generation,
|
|
1367
|
-
cardinality: n,
|
|
1368
|
-
fingerprint,
|
|
1369
|
-
tailBytes,
|
|
1370
|
-
metadata
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
function validateSummaryNames(summary, currentGen) {
|
|
1374
|
-
if (summary !== void 0 && summary.generation !== currentGen) {
|
|
1375
|
-
throw new ValidationError(
|
|
1376
|
-
`summary describes generation ${summary.generation}, but the row points at ${String(currentGen)}`
|
|
1377
|
-
);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
function summaryAgreesWithKeys(summary, wrappedDeks) {
|
|
1381
|
-
return "sealed" in summary === (wrappedDeks !== void 0);
|
|
1382
|
-
}
|
|
1383
|
-
function validateSummaryKeys(summary, wrappedDeks) {
|
|
1384
|
-
if (summary !== void 0 && !summaryAgreesWithKeys(summary, wrappedDeks)) {
|
|
1385
|
-
throw new ValidationError(
|
|
1386
|
-
wrappedDeks === void 0 ? "summary is sealed, but the row has no wrapped keys to open it with" : "summary is in the clear, but the row is encrypted: an encrypted segment's summary must be sealed"
|
|
1387
|
-
);
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
function validateKnownGens(value, origin, ctx) {
|
|
1391
|
-
if (value === void 0) return void 0;
|
|
1392
|
-
const fail = (msg) => {
|
|
1393
|
-
const where = ctx === void 0 ? "" : `: ${ctx}`;
|
|
1394
|
-
throw origin === "stored" ? new IntegrityError(`registry record knownGens: ${msg}${where}`) : new ValidationError(`knownGens: ${msg}`);
|
|
1395
|
-
};
|
|
1396
|
-
const max = origin === "stored" ? MAX_STORED_KNOWN_GENERATIONS : MAX_KNOWN_GENERATIONS;
|
|
1397
|
-
const fault = knownGensShapeFault(value, max, shown3);
|
|
1398
|
-
if (fault !== void 0) fail(fault);
|
|
1399
|
-
const out = [];
|
|
1400
|
-
for (const entry of value) {
|
|
1401
|
-
out.push(
|
|
1402
|
-
origin === "stored" ? entry : Object.freeze({ generation: entry.generation, footerCrc: entry.footerCrc })
|
|
1403
|
-
);
|
|
1404
|
-
}
|
|
1405
|
-
return origin === "stored" ? out : Object.freeze(out);
|
|
1406
|
-
}
|
|
1407
|
-
var HOLDER = /^[0-9a-f]{16}$/;
|
|
1408
|
-
var LEASE_ENTRY_KEYS = ["holder", "generation", "until"];
|
|
1409
|
-
function validateLeases(value, origin, ctx) {
|
|
1219
|
+
// src/core/known-generations-shape.ts
|
|
1220
|
+
var ENTRY_KEYS = ["generation", "footerCrc"];
|
|
1221
|
+
function knownGensShapeFault(value, max, show = String) {
|
|
1410
1222
|
if (value === void 0) return void 0;
|
|
1411
|
-
|
|
1412
|
-
const where = ctx === void 0 ? "" : `: ${ctx}`;
|
|
1413
|
-
throw origin === "stored" ? new IntegrityError(`registry record leases: ${msg}${where}`) : new ValidationError(`leases: ${msg}`);
|
|
1414
|
-
};
|
|
1415
|
-
if (!Array.isArray(value)) fail("must be an array");
|
|
1223
|
+
if (!Array.isArray(value)) return "must be an array";
|
|
1416
1224
|
const list = value;
|
|
1417
|
-
|
|
1418
|
-
if (list.length > max) fail(`has ${list.length} entries, cap ${max}`);
|
|
1225
|
+
if (list.length > max) return `has ${list.length} entries, cap ${max}`;
|
|
1419
1226
|
const seen = /* @__PURE__ */ new Set();
|
|
1420
|
-
const out = [];
|
|
1421
1227
|
for (const e of list) {
|
|
1422
|
-
if (typeof e !== "object" || e === null || Array.isArray(e))
|
|
1228
|
+
if (typeof e !== "object" || e === null || Array.isArray(e))
|
|
1229
|
+
return "an entry must be an object";
|
|
1423
1230
|
const entry = e;
|
|
1424
|
-
const extra = Object.keys(entry).filter((k) => !
|
|
1425
|
-
if (extra.length > 0)
|
|
1426
|
-
|
|
1427
|
-
if (typeof holder !== "string" || !HOLDER.test(holder)) {
|
|
1428
|
-
fail("a holder must be 16 lowercase hex digits");
|
|
1429
|
-
}
|
|
1430
|
-
if (seen.has(holder)) fail("holders must be unique");
|
|
1431
|
-
seen.add(holder);
|
|
1432
|
-
for (const [name, n] of [
|
|
1433
|
-
["generation", generation],
|
|
1434
|
-
["until", until]
|
|
1435
|
-
]) {
|
|
1436
|
-
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1437
|
-
fail(`${name} must be a non-negative safe integer (got ${String(n)})`);
|
|
1438
|
-
}
|
|
1231
|
+
const extra = Object.keys(entry).filter((k) => !ENTRY_KEYS.includes(k));
|
|
1232
|
+
if (extra.length > 0) {
|
|
1233
|
+
return `an entry carries an undeclared field (${show(extra.join(", "))})`;
|
|
1439
1234
|
}
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
generation,
|
|
1444
|
-
until
|
|
1445
|
-
})
|
|
1446
|
-
);
|
|
1447
|
-
}
|
|
1448
|
-
if (origin === "stored") return out;
|
|
1449
|
-
return out.length === 0 ? void 0 : Object.freeze(out);
|
|
1450
|
-
}
|
|
1451
|
-
function validateLeasesPointer(leases, currentGen) {
|
|
1452
|
-
if (leases !== void 0 && leases.length > 0 && currentGen === null) {
|
|
1453
|
-
throw new ValidationError("leases: a row with no pointer has no generation to lease");
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
function validateKnownGensFit(knownGens, currentGen, summary) {
|
|
1457
|
-
if (knownGens === void 0) return;
|
|
1458
|
-
if (currentGen === null) {
|
|
1459
|
-
throw new ValidationError("knownGens: a row with no pointer has no generation to know");
|
|
1460
|
-
}
|
|
1461
|
-
const last = knownGens[knownGens.length - 1];
|
|
1462
|
-
if (last === void 0 || last.generation !== currentGen) {
|
|
1463
|
-
throw new ValidationError(
|
|
1464
|
-
`knownGens must end with the row's pointer ${currentGen}, in the order the generations were made current (its last entry is ${last === void 0 ? "missing" : last.generation})`
|
|
1465
|
-
);
|
|
1466
|
-
}
|
|
1467
|
-
if (summary !== void 0 && summary.generation === currentGen && "fingerprint" in summary && fingerprintParts(summary.fingerprint)?.footerCrc !== last.footerCrc) {
|
|
1468
|
-
throw new ValidationError(
|
|
1469
|
-
`knownGens records footerCrc ${last.footerCrc} for generation ${currentGen}, but the summary's fingerprint ${summary.fingerprint} carries another: both describe the one current object`
|
|
1470
|
-
);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
function refuseDriverManaged(write, what) {
|
|
1474
|
-
const named = DRIVER_MANAGED.filter((field) => field in write);
|
|
1475
|
-
if (named.length > 0) {
|
|
1476
|
-
throw new ValidationError(
|
|
1477
|
-
`${what} names ${named.join(" and ")}, which the registry sets on every write and a caller never does`
|
|
1478
|
-
);
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
function validateKeyId(keyId) {
|
|
1482
|
-
if (keyId !== void 0 && (typeof keyId !== "string" || keyId.length === 0)) {
|
|
1483
|
-
throw new ValidationError("keyId must be a non-empty string, or absent");
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
function validateNewRegistryRecord(rec) {
|
|
1487
|
-
refuseDriverManaged(rec, "a new record");
|
|
1488
|
-
validateKeyId(rec.keyId);
|
|
1489
|
-
validateGeneration(rec.currentGen);
|
|
1490
|
-
if (rec.status !== void 0) validateStatus(rec.status);
|
|
1491
|
-
validateWrappedDeks(rec.wrappedDeks, "caller");
|
|
1492
|
-
validateGovernance(rec.retention, "retention");
|
|
1493
|
-
validateGovernance(rec.residency, "residency");
|
|
1494
|
-
const knownGens = validateKnownGens(rec.knownGens, "caller");
|
|
1495
|
-
const withKnown = knownGens === void 0 ? rec : { ...rec, knownGens };
|
|
1496
|
-
const summary = "summary" in rec ? validateSummary(rec.summary, "caller") : void 0;
|
|
1497
|
-
validateKnownGensFit(knownGens, rec.currentGen, summary);
|
|
1498
|
-
if (!("summary" in rec)) return withKnown;
|
|
1499
|
-
validateSummaryNames(summary, rec.currentGen);
|
|
1500
|
-
validateSummaryKeys(summary, rec.wrappedDeks);
|
|
1501
|
-
return { ...withKnown, summary };
|
|
1502
|
-
}
|
|
1503
|
-
function validateRegistryPatch(patch) {
|
|
1504
|
-
refuseDriverManaged(patch, "a patch");
|
|
1505
|
-
if ("keyId" in patch) validateKeyId(patch.keyId);
|
|
1506
|
-
validatePatchGeneration(patch);
|
|
1507
|
-
if (patch.status !== void 0) validateStatus(patch.status);
|
|
1508
|
-
if ("wrappedDeks" in patch) validateWrappedDeks(patch.wrappedDeks, "caller");
|
|
1509
|
-
if ("retention" in patch) validateGovernance(patch.retention, "retention");
|
|
1510
|
-
if ("residency" in patch) validateGovernance(patch.residency, "residency");
|
|
1511
|
-
const withKnown = patch.knownGens === void 0 ? patch : { ...patch, knownGens: validateKnownGens(patch.knownGens, "caller") };
|
|
1512
|
-
const withLeases = "leases" in withKnown ? { ...withKnown, leases: validateLeases(withKnown.leases, "caller") } : withKnown;
|
|
1513
|
-
if (!("summary" in patch)) return withLeases;
|
|
1514
|
-
return { ...withLeases, summary: validateSummary(patch.summary, "caller") };
|
|
1515
|
-
}
|
|
1516
|
-
var REGISTRY_SCHEMA_VERSION = 5;
|
|
1517
|
-
function assertRegistrySchemaVersion(raw, ctx) {
|
|
1518
|
-
if (raw === void 0) {
|
|
1519
|
-
throw new IntegrityError(`registry row has no schemaVersion: ${ctx}`);
|
|
1520
|
-
}
|
|
1521
|
-
if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 1) {
|
|
1522
|
-
throw new IntegrityError(`registry row has a malformed schemaVersion (${shown3(raw)}): ${ctx}`);
|
|
1523
|
-
}
|
|
1524
|
-
if (raw < REGISTRY_SCHEMA_VERSION) {
|
|
1525
|
-
throw new UnsupportedError(
|
|
1526
|
-
`registry row schemaVersion ${raw} is one this build does not read: it reads schema ${REGISTRY_SCHEMA_VERSION} only. Export the segments with the release that wrote the row and load them with this one into a new prefix (steps: https://github.com/cloudbitmaps/cloudbitmaps/blob/main/CHANGELOG.md, the Breaking entry on registry schema 5): ${ctx}`
|
|
1527
|
-
);
|
|
1528
|
-
}
|
|
1529
|
-
if (raw > REGISTRY_SCHEMA_VERSION) {
|
|
1530
|
-
throw new UnsupportedError(
|
|
1531
|
-
`registry row schemaVersion ${raw} is newer than this build reads (v${REGISTRY_SCHEMA_VERSION}): ${ctx}`
|
|
1532
|
-
);
|
|
1533
|
-
}
|
|
1534
|
-
return raw;
|
|
1535
|
-
}
|
|
1536
|
-
function serializeRegistryEnvelope(env) {
|
|
1537
|
-
return JSON.stringify({
|
|
1538
|
-
schemaVersion: REGISTRY_SCHEMA_VERSION,
|
|
1539
|
-
deleted: env.deleted,
|
|
1540
|
-
record: env.record
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
var INCARNATION_BYTES = 16;
|
|
1544
|
-
var WRITE_BYTES = 8;
|
|
1545
|
-
function tokenParts(token, ctx, what = "token") {
|
|
1546
|
-
const match = typeof token === "string" ? INCARNATION_TOKEN.exec(token) : null;
|
|
1547
|
-
if (match === null) {
|
|
1548
|
-
throw new IntegrityError(
|
|
1549
|
-
`registry row ${what} is not one a shipped registry writes (${shown3(JSON.stringify(token))}): ${ctx}`
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
const counter = Number(match[2]);
|
|
1553
|
-
if (!Number.isSafeInteger(counter)) {
|
|
1554
|
-
throw new IntegrityError(`registry row ${what}'s counter is out of safe-integer range: ${ctx}`);
|
|
1555
|
-
}
|
|
1556
|
-
return { incarnation: match[1], counter };
|
|
1557
|
-
}
|
|
1558
|
-
function checkPointerId(pointerId, token, ctx) {
|
|
1559
|
-
const parts = tokenParts(pointerId, ctx, "pointerId");
|
|
1560
|
-
if (parts.incarnation !== token.incarnation) {
|
|
1561
|
-
throw new IntegrityError(
|
|
1562
|
-
`registry row pointerId names another incarnation than its token: ${ctx}`
|
|
1563
|
-
);
|
|
1564
|
-
}
|
|
1565
|
-
if (parts.counter > token.counter) {
|
|
1566
|
-
throw new IntegrityError(`registry row pointerId is a write after its token: ${ctx}`);
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
function drawHex(entropy, bytes) {
|
|
1570
|
-
const drawn = entropy(bytes);
|
|
1571
|
-
if (!(drawn instanceof Uint8Array) || drawn.length !== bytes) {
|
|
1572
|
-
throw new ValidationError(
|
|
1573
|
-
`the registry's entropy source must return ${bytes} bytes as a Uint8Array`
|
|
1574
|
-
);
|
|
1575
|
-
}
|
|
1576
|
-
let hex = "";
|
|
1577
|
-
for (const b of drawn) hex += b.toString(16).padStart(2, "0");
|
|
1578
|
-
return hex;
|
|
1579
|
-
}
|
|
1580
|
-
function drawIncarnation(entropy) {
|
|
1581
|
-
return drawHex(entropy, INCARNATION_BYTES);
|
|
1582
|
-
}
|
|
1583
|
-
function drawWrite(entropy) {
|
|
1584
|
-
return drawHex(entropy, WRITE_BYTES);
|
|
1585
|
-
}
|
|
1586
|
-
function nextRegistryToken(record, entropy) {
|
|
1587
|
-
const { incarnation, counter } = tokenParts(record.token, record.segment);
|
|
1588
|
-
return `${incarnation}.${counter + 1}.${drawWrite(entropy)}`;
|
|
1589
|
-
}
|
|
1590
|
-
function newIncarnationToken(entropy, tombstone) {
|
|
1591
|
-
const counter = tombstone === void 0 ? 0 : tokenParts(tombstone.token, tombstone.segment).counter + 1;
|
|
1592
|
-
return `${drawIncarnation(entropy)}.${counter}.${drawWrite(entropy)}`;
|
|
1593
|
-
}
|
|
1594
|
-
function shown3(v) {
|
|
1595
|
-
const text = String(v);
|
|
1596
|
-
return text.length > 64 ? `${text.slice(0, 64)}\u2026` : text;
|
|
1597
|
-
}
|
|
1598
|
-
function parseRegistryEnvelope(text, ctx, expected) {
|
|
1599
|
-
let parsed;
|
|
1600
|
-
try {
|
|
1601
|
-
parsed = JSON.parse(text);
|
|
1602
|
-
} catch {
|
|
1603
|
-
throw new IntegrityError(`registry row is not valid JSON: ${ctx}`);
|
|
1604
|
-
}
|
|
1605
|
-
if (parsed === null || typeof parsed !== "object") {
|
|
1606
|
-
throw new IntegrityError(`registry row has a malformed envelope: ${ctx}`);
|
|
1607
|
-
}
|
|
1608
|
-
const env = parsed;
|
|
1609
|
-
assertRegistrySchemaVersion(env.schemaVersion, ctx);
|
|
1610
|
-
const extra = Object.keys(env).filter((k) => !ENVELOPE_FIELDS.includes(k));
|
|
1611
|
-
if (extra.length > 0) {
|
|
1612
|
-
throw new IntegrityError(
|
|
1613
|
-
`registry row has fields its envelope does not declare (${shown3(extra.join(", "))}): ${ctx}`
|
|
1614
|
-
);
|
|
1615
|
-
}
|
|
1616
|
-
if (typeof env.deleted !== "boolean" || env.record === null || typeof env.record !== "object") {
|
|
1617
|
-
throw new IntegrityError(`registry row has a malformed envelope: ${ctx}`);
|
|
1618
|
-
}
|
|
1619
|
-
const r = env.record;
|
|
1620
|
-
assertStoredRecordShape(r, ctx);
|
|
1621
|
-
if (typeof r.token !== "string") {
|
|
1622
|
-
throw new IntegrityError(`registry row is missing its token: ${ctx}`);
|
|
1623
|
-
}
|
|
1624
|
-
checkPointerId(r.pointerId, tokenParts(r.token, ctx), ctx);
|
|
1625
|
-
if (expected !== void 0 && (r.segment !== expected.segment || (r.namespace ?? void 0) !== (expected.namespace ?? void 0))) {
|
|
1626
|
-
throw new IntegrityError(
|
|
1627
|
-
`registry row names another segment than the one it is stored for: ${ctx}`
|
|
1628
|
-
);
|
|
1629
|
-
}
|
|
1630
|
-
return { deleted: env.deleted, record: env.record };
|
|
1631
|
-
}
|
|
1632
|
-
function recordFromNew(ref, rec, now, token) {
|
|
1633
|
-
return {
|
|
1634
|
-
namespace: ref.namespace,
|
|
1635
|
-
segment: ref.segment,
|
|
1636
|
-
currentGen: rec.currentGen,
|
|
1637
|
-
wrappedDeks: rec.wrappedDeks,
|
|
1638
|
-
keyId: rec.keyId,
|
|
1639
|
-
status: rec.status ?? "active",
|
|
1640
|
-
retention: rec.retention,
|
|
1641
|
-
residency: rec.residency,
|
|
1642
|
-
summary: rec.summary,
|
|
1643
|
-
knownGens: rec.knownGens,
|
|
1644
|
-
// A new row has no holder: a lease is written only against a row that already exists.
|
|
1645
|
-
leases: void 0,
|
|
1646
|
-
createdAt: now,
|
|
1647
|
-
updatedAt: now,
|
|
1648
|
-
token,
|
|
1649
|
-
pointerId: token
|
|
1650
|
-
};
|
|
1651
|
-
}
|
|
1652
|
-
function assertStoredRecordShape(r, ctx) {
|
|
1653
|
-
if (typeof r.segment !== "string" || typeof r.pointerId !== "string" || r.namespace !== void 0 && typeof r.namespace !== "string" || r.currentGen !== null && typeof r.currentGen !== "number" || typeof r.status !== "string" || typeof r.createdAt !== "number" || typeof r.updatedAt !== "number") {
|
|
1654
|
-
throw new IntegrityError(`registry record is missing required fields: ${ctx}`);
|
|
1655
|
-
}
|
|
1656
|
-
if (r.currentGen !== null && (!Number.isSafeInteger(r.currentGen) || r.currentGen < 0)) {
|
|
1657
|
-
throw new IntegrityError(
|
|
1658
|
-
`registry record has an invalid currentGen (${shown3(r.currentGen)}): ${ctx}`
|
|
1659
|
-
);
|
|
1660
|
-
}
|
|
1661
|
-
if (!STATUSES.includes(r.status)) {
|
|
1662
|
-
throw new IntegrityError(`registry record has an unknown status (${shown3(r.status)}): ${ctx}`);
|
|
1663
|
-
}
|
|
1664
|
-
const declared = RECORD_FIELDS;
|
|
1665
|
-
const extra = Object.keys(r).filter((k) => !declared.includes(k));
|
|
1666
|
-
if (extra.length > 0) {
|
|
1667
|
-
throw new IntegrityError(
|
|
1668
|
-
`registry record has fields a schema-${REGISTRY_SCHEMA_VERSION} row does not declare (${shown3(extra.join(", "))}): ${ctx}`
|
|
1669
|
-
);
|
|
1670
|
-
}
|
|
1671
|
-
if (r.keyId !== void 0 && typeof r.keyId !== "string") {
|
|
1672
|
-
throw new IntegrityError(`registry record has an invalid keyId: ${ctx}`);
|
|
1673
|
-
}
|
|
1674
|
-
validateWrappedDeks(r.wrappedDeks, "stored");
|
|
1675
|
-
for (const field of ["retention", "residency"]) {
|
|
1676
|
-
const meta = r[field];
|
|
1677
|
-
if (meta !== void 0 && (meta === null || typeof meta !== "object" || Array.isArray(meta))) {
|
|
1678
|
-
throw new IntegrityError(`registry record has a non-object ${field}: ${ctx}`);
|
|
1235
|
+
const { generation, footerCrc } = entry;
|
|
1236
|
+
if (!Number.isSafeInteger(generation) || generation < 0) {
|
|
1237
|
+
return `a generation must be a non-negative safe integer (got ${show(generation)})`;
|
|
1679
1238
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
validateKnownGens(r.knownGens, "stored", ctx);
|
|
1683
|
-
validateLeases(r.leases, "stored", ctx);
|
|
1684
|
-
}
|
|
1685
|
-
function applyRegistryPatch(prev, patch, now, token) {
|
|
1686
|
-
const currentGen = "currentGen" in patch ? patch.currentGen ?? null : prev.currentGen;
|
|
1687
|
-
const wrappedDeks = "wrappedDeks" in patch ? patch.wrappedDeks : prev.wrappedDeks;
|
|
1688
|
-
let summary;
|
|
1689
|
-
if ("summary" in patch) {
|
|
1690
|
-
validateSummaryNames(patch.summary, currentGen);
|
|
1691
|
-
validateSummaryKeys(patch.summary, wrappedDeks);
|
|
1692
|
-
summary = patch.summary;
|
|
1693
|
-
} else {
|
|
1694
|
-
const kept = currentGen === prev.currentGen ? prev.summary : void 0;
|
|
1695
|
-
summary = kept !== void 0 && summaryAgreesWithKeys(kept, wrappedDeks) ? kept : void 0;
|
|
1696
|
-
}
|
|
1697
|
-
let knownGens;
|
|
1698
|
-
if ("knownGens" in patch) {
|
|
1699
|
-
validateKnownGensFit(patch.knownGens, currentGen, summary);
|
|
1700
|
-
knownGens = patch.knownGens;
|
|
1701
|
-
} else {
|
|
1702
|
-
knownGens = currentGen === prev.currentGen ? prev.knownGens : void 0;
|
|
1703
|
-
}
|
|
1704
|
-
let leases;
|
|
1705
|
-
if ("leases" in patch) {
|
|
1706
|
-
leases = patch.leases;
|
|
1707
|
-
validateLeasesPointer(leases, currentGen);
|
|
1708
|
-
const most = Math.max(MAX_LEASES_PER_SEGMENT, prev.leases?.length ?? 0);
|
|
1709
|
-
if (leases !== void 0 && leases.length > most) {
|
|
1710
|
-
throw new ValidationError(`leases: has ${leases.length} entries, cap ${most}`);
|
|
1239
|
+
if (!Number.isInteger(footerCrc) || footerCrc < 0 || footerCrc > 4294967295) {
|
|
1240
|
+
return `a footerCrc must be an integer from 0 to 2^32 - 1 (got ${show(footerCrc)})`;
|
|
1711
1241
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
}
|
|
1715
|
-
return {
|
|
1716
|
-
namespace: prev.namespace,
|
|
1717
|
-
segment: prev.segment,
|
|
1718
|
-
currentGen,
|
|
1719
|
-
wrappedDeks,
|
|
1720
|
-
keyId: "keyId" in patch ? patch.keyId : prev.keyId,
|
|
1721
|
-
status: patch.status ?? prev.status,
|
|
1722
|
-
retention: "retention" in patch ? patch.retention : prev.retention,
|
|
1723
|
-
residency: "residency" in patch ? patch.residency : prev.residency,
|
|
1724
|
-
summary,
|
|
1725
|
-
knownGens,
|
|
1726
|
-
leases,
|
|
1727
|
-
createdAt: prev.createdAt,
|
|
1728
|
-
updatedAt: now,
|
|
1729
|
-
token,
|
|
1730
|
-
pointerId: renewsPointer(patch) ? token : prev.pointerId
|
|
1731
|
-
};
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// src/drivers/_shared/entropy.ts
|
|
1735
|
-
function webCrypto() {
|
|
1736
|
-
const c = globalThis.crypto;
|
|
1737
|
-
return c !== void 0 && typeof c.getRandomValues === "function" ? c : void 0;
|
|
1738
|
-
}
|
|
1739
|
-
var webCryptoEntropy = (length) => {
|
|
1740
|
-
const c = webCrypto();
|
|
1741
|
-
if (c === void 0) {
|
|
1742
|
-
throw new UnsupportedError(
|
|
1743
|
-
"this runtime has no Web Crypto (crypto.getRandomValues), which a registry needs for the token of every row it writes: run on a runtime that has it"
|
|
1744
|
-
);
|
|
1242
|
+
if (seen.has(generation)) return `generation ${String(generation)} is repeated`;
|
|
1243
|
+
seen.add(generation);
|
|
1745
1244
|
}
|
|
1746
|
-
return
|
|
1747
|
-
};
|
|
1748
|
-
function entropyIsAvailable(entropy) {
|
|
1749
|
-
return entropy !== webCryptoEntropy || webCrypto() !== void 0;
|
|
1245
|
+
return void 0;
|
|
1750
1246
|
}
|
|
1751
1247
|
|
|
1752
1248
|
export {
|
|
1753
1249
|
CloudRoaringError,
|
|
1754
1250
|
ValidationError,
|
|
1251
|
+
CONTENTION_NEXT_STEP,
|
|
1755
1252
|
WriteConflictError,
|
|
1756
1253
|
IntegrityError,
|
|
1757
1254
|
NotFoundError,
|
|
@@ -1763,29 +1260,30 @@ export {
|
|
|
1763
1260
|
BudgetExceededError,
|
|
1764
1261
|
KeyUnavailableError,
|
|
1765
1262
|
TransientError,
|
|
1766
|
-
isCloudRoaringError,
|
|
1767
1263
|
isWriteConflictError,
|
|
1264
|
+
unsettledConflict,
|
|
1265
|
+
isUnsettledConflict,
|
|
1768
1266
|
isTransientError,
|
|
1769
|
-
isLeaseExpiredError,
|
|
1770
|
-
isStaleOperandError,
|
|
1771
|
-
isLeaseLimitError,
|
|
1772
1267
|
isNotFoundError,
|
|
1773
1268
|
isIntegrityError,
|
|
1774
1269
|
isValidationError,
|
|
1775
|
-
isUnsupportedError,
|
|
1776
|
-
isCapabilityError,
|
|
1777
|
-
isBudgetExceededError,
|
|
1778
1270
|
isKeyUnavailableError,
|
|
1271
|
+
errorKind,
|
|
1272
|
+
shown,
|
|
1779
1273
|
requireInteger,
|
|
1274
|
+
checkRequireEncryption,
|
|
1780
1275
|
requirePositiveInteger,
|
|
1781
1276
|
requireFiniteNumber,
|
|
1277
|
+
refuseUnknownOptions,
|
|
1278
|
+
requireBool,
|
|
1279
|
+
requireNonEmptyString,
|
|
1782
1280
|
U32_MAX,
|
|
1783
1281
|
CHUNK_COUNT,
|
|
1282
|
+
isBadIdError,
|
|
1283
|
+
refusalOfId,
|
|
1784
1284
|
splitId,
|
|
1785
1285
|
MAX_REMAINDER,
|
|
1786
1286
|
joinId,
|
|
1787
|
-
mapWithConcurrency,
|
|
1788
|
-
boundedAll,
|
|
1789
1287
|
PREAMBLE_BYTES,
|
|
1790
1288
|
FOOTER_BYTES,
|
|
1791
1289
|
encodeNameForKey,
|
|
@@ -1798,6 +1296,8 @@ export {
|
|
|
1798
1296
|
RESERVED_NAMESPACE_PREFIX,
|
|
1799
1297
|
isReservedNamespace,
|
|
1800
1298
|
validateUserNamespace,
|
|
1299
|
+
PORT_KEYS,
|
|
1300
|
+
refuseUnknownRefKeys,
|
|
1801
1301
|
validateUserRef,
|
|
1802
1302
|
validateChunkKeyOrder,
|
|
1803
1303
|
validateChunkRef,
|
|
@@ -1806,15 +1306,7 @@ export {
|
|
|
1806
1306
|
STORAGE_BACKEND,
|
|
1807
1307
|
brandAsBackend,
|
|
1808
1308
|
isStorageBackend,
|
|
1809
|
-
|
|
1810
|
-
metadataBytes,
|
|
1811
|
-
copiedMetadata,
|
|
1812
|
-
metadataFromBytes,
|
|
1813
|
-
sizePart,
|
|
1814
|
-
fingerprintFor,
|
|
1815
|
-
fingerprintParts,
|
|
1816
|
-
footerCrcOf,
|
|
1817
|
-
compactFingerprint,
|
|
1309
|
+
INCARNATION_TOKEN,
|
|
1818
1310
|
incarnationOf,
|
|
1819
1311
|
incarnationField,
|
|
1820
1312
|
sameIncarnation,
|
|
@@ -1822,14 +1314,28 @@ export {
|
|
|
1822
1314
|
renewsPointer,
|
|
1823
1315
|
renewPointer,
|
|
1824
1316
|
pointerIdOf,
|
|
1317
|
+
pointerSetBy,
|
|
1825
1318
|
aadFor,
|
|
1826
1319
|
sameKeys,
|
|
1320
|
+
MAX_METADATA_BYTES,
|
|
1321
|
+
canonicalMetadataJson,
|
|
1322
|
+
metadataBytes,
|
|
1323
|
+
copiedMetadata,
|
|
1324
|
+
metadataFromBytes,
|
|
1325
|
+
sizePart,
|
|
1326
|
+
fingerprintFor,
|
|
1327
|
+
fingerprintParts,
|
|
1328
|
+
footerCrcOf,
|
|
1329
|
+
compactFingerprint,
|
|
1330
|
+
MAX_SUMMARY_CARDINALITY,
|
|
1331
|
+
tailBytesFit,
|
|
1827
1332
|
sizeOfFingerprint,
|
|
1828
1333
|
usableSummary,
|
|
1829
1334
|
summaryAgrees,
|
|
1830
1335
|
metadataToCarry,
|
|
1831
1336
|
summaryOf,
|
|
1832
1337
|
ownSummary,
|
|
1338
|
+
ascending,
|
|
1833
1339
|
DEFAULT_RETRY_POLICY,
|
|
1834
1340
|
jitteredWait,
|
|
1835
1341
|
retryRead,
|
|
@@ -1838,6 +1344,7 @@ export {
|
|
|
1838
1344
|
MAX_LEASE_MS,
|
|
1839
1345
|
LEASE_SKEW_MS,
|
|
1840
1346
|
MAX_LEASES_PER_SEGMENT,
|
|
1347
|
+
MAX_STORED_LEASES,
|
|
1841
1348
|
UNANSWERED_RESENDS,
|
|
1842
1349
|
UNANSWERED_BASE_MS,
|
|
1843
1350
|
isLive,
|
|
@@ -1846,8 +1353,7 @@ export {
|
|
|
1846
1353
|
leaseChurn,
|
|
1847
1354
|
takeLease,
|
|
1848
1355
|
releaseLease,
|
|
1849
|
-
|
|
1850
|
-
ascending,
|
|
1356
|
+
MAX_KNOWN_GENERATIONS,
|
|
1851
1357
|
MAX_STORED_KNOWN_GENERATIONS,
|
|
1852
1358
|
usableKnownGens,
|
|
1853
1359
|
windowOf,
|
|
@@ -1859,24 +1365,6 @@ export {
|
|
|
1859
1365
|
describingKnown,
|
|
1860
1366
|
isFullLedger,
|
|
1861
1367
|
fallbackBound,
|
|
1862
|
-
|
|
1863
|
-
validateRegistryPatch,
|
|
1864
|
-
serializeRegistryEnvelope,
|
|
1865
|
-
drawIncarnation,
|
|
1866
|
-
drawWrite,
|
|
1867
|
-
nextRegistryToken,
|
|
1868
|
-
newIncarnationToken,
|
|
1869
|
-
parseRegistryEnvelope,
|
|
1870
|
-
recordFromNew,
|
|
1871
|
-
applyRegistryPatch,
|
|
1872
|
-
webCryptoEntropy,
|
|
1873
|
-
entropyIsAvailable,
|
|
1874
|
-
DEFAULT_NAMESPACE,
|
|
1875
|
-
namespaceKeyPart,
|
|
1876
|
-
namespacePathPart,
|
|
1877
|
-
refuseUnknownOptions,
|
|
1878
|
-
checkNow,
|
|
1879
|
-
requirePositiveInt,
|
|
1880
|
-
requireBool
|
|
1368
|
+
knownGensShapeFault
|
|
1881
1369
|
};
|
|
1882
|
-
//# sourceMappingURL=chunk-
|
|
1370
|
+
//# sourceMappingURL=chunk-MVUD4R72.js.map
|