@cloudbitmaps/core 0.25.0 → 0.26.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/dist/{chunk-BUDAVGBI.js → chunk-7VNEBKC4.js} +2 -2
- package/dist/{chunk-45ML6YU4.js → chunk-LJLZRVYN.js} +2 -2
- package/dist/{chunk-WPER7R2R.js → chunk-MNXTZJZ6.js} +2 -2
- package/dist/{chunk-2B2QF4FU.js → chunk-UFOMYONZ.js} +1 -1
- package/dist/chunk-UFOMYONZ.js.map +7 -0
- package/dist/core/crbm-storage-source.d.ts +7 -1
- package/dist/core/engine.d.ts +53 -0
- package/dist/core/pinned-storage-source.d.ts +2 -0
- package/dist/core/ports.d.ts +16 -1
- package/dist/driver-kit.js +3 -3
- package/dist/drivers/retry/retrying-chunk-source.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +245 -6
- package/dist/index.js.map +2 -2
- package/dist/node.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-2B2QF4FU.js.map +0 -7
- /package/dist/{chunk-BUDAVGBI.js.map → chunk-7VNEBKC4.js.map} +0 -0
- /package/dist/{chunk-45ML6YU4.js.map → chunk-LJLZRVYN.js.map} +0 -0
- /package/dist/{chunk-WPER7R2R.js.map → chunk-MNXTZJZ6.js.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/errors.ts", "../src/core/check.ts", "../src/core/bit-route.ts", "../src/core/name-codec.ts", "../src/core/validate.ts", "../src/core/ports.ts", "../src/core/token.ts", "../src/core/pointer-id.ts", "../src/core/crypto.ts", "../src/core/retry.ts", "../src/core/leases.ts", "../src/core/crbm/frame.ts", "../src/core/metadata.ts", "../src/core/crbm/fingerprint.ts", "../src/core/summary.ts", "../src/core/order.ts", "../src/core/known-generations.ts", "../src/core/known-generations-shape.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Typed errors \u2014 callers learn *why* something failed, never by parsing strings. Retry is not the engine's job: a\n * driver classifies its backend's failures into this vocabulary, and the store's read wrapper retries the\n * transient ones through `withRetry`.\n */\n\n/**\n * Registry-symbol brands, so an error stays classifiable when the class object is not shared.\n *\n * In an ordinary install there is ONE copy of these classes and `instanceof` holds everywhere \u2014 across the\n * flavor, the driver packages and core itself \u2014 because every package leaves `@cloudbitmaps/*` external and\n * resolves core at runtime rather than inlining it.\n *\n * What still breaks it is a SECOND copy: a version skew between our packages that the installer could not\n * dedupe, or a bundler that emits core twice. Then a driver throws a class the catching side's `instanceof`\n * does not match \u2014 and silently, because a `catch` that stops matching just falls through, defeating\n * transient retry and the publish path's conflict handling with no error of its own.\n *\n * `Symbol.for` is identity-stable across copies, bundles and realms, so classify errors with `errorKind`\n * (never `instanceof`) anywhere an error may cross that boundary.\n */\nconst ERROR_BRAND: unique symbol = Symbol.for('cloudbitmaps.error');\nconst TRANSIENT_BRAND: unique symbol = Symbol.for('cloudbitmaps.error.transient');\n\n/**\n * Each class's name as written. A minifying bundler renames the classes themselves, so the name an error carries, which\n * `errorKind` matches on and a log prints, comes from here: strings no minifier touches. A class not listed (an\n * application's own subclass) keeps the name its class has.\n */\nconst NAMES = new WeakMap<abstract new (...args: never[]) => unknown, string>();\n\n/** Base class for every error CloudRoaring throws. */\nexport class CloudRoaringError extends Error {\n /** Cross-bundle brand \u2014 see {@link errorKind}. Non-enumerable-ish (symbol key \u21D2 not in JSON). */\n readonly [ERROR_BRAND] = true as const;\n /** Builds the error from `message`, and sets `name` to the class's name as written. */\n constructor(message: string) {\n super(message);\n // Also the discriminator `errorKind` matches on: a runtime string, so it survives a second copy of the package\n // where the class identity does not, and a minifier where the class's own name does not.\n this.name = NAMES.get(new.target) ?? new.target.name;\n }\n}\n\n/**\n * Invalid input, which the same call fails on again. Most is refused before any storage call (a bad id, segment name\n * or option); some is found by the call itself: a read past the end of an object, or a bucket or container a cloud\n * driver finds does not exist.\n */\nexport class ValidationError extends CloudRoaringError {}\n\n/** What a contention {@link WriteConflictError} ends with: the call is safe to run again. */\nexport const CONTENTION_NEXT_STEP =\n \"; another writer changed the segment's row while this call ran. Re-run the call: it reads the row afresh\";\n\n/** An OCC conditional write/delete lost the race \u2014 the row changed since it was read. */\nexport class WriteConflictError extends CloudRoaringError {}\n\n/** Bytes from a tier are corrupt, oversized, or fail a checksum/format check. */\nexport class IntegrityError extends CloudRoaringError {}\n\n/**\n * A requested object/row does not exist. Part of the driver error vocabulary: every storage driver this\n * library ships, the in-memory one included, throws it for a read of a generation object that is not there.\n * A registry `get` of a row that is not there returns `null` instead.\n */\nexport class NotFoundError extends CloudRoaringError {}\n\n/**\n * A read of a leased pin came after its lease ended, by `until` or by `release()`. Thrown at every read site of the\n * handle, including a leased handle used as an operand or an exclude of a combine, and never answered empty: a\n * handle that read empty here would be an opt-out list that suppresses nobody. Carries the instant the lease ended\n * and why; never an id or a key.\n */\nexport class LeaseExpiredError extends CloudRoaringError {\n /** Epoch-ms the lease was taken until. */\n readonly until: number;\n /** `'expired'` when the clock reached `until`, `'released'` after `release()`. */\n readonly reason: 'expired' | 'released';\n /** Builds the error from its `message`, the epoch-ms the lease ran until, and why it ended. */\n constructor(message: string, until: number, reason: 'expired' | 'released') {\n super(message);\n this.until = until;\n this.reason = reason;\n }\n}\n\n/**\n * A segment already has as many live leases as one row records, so another cannot be taken. Nothing was written.\n * Release one, wait for one to end, or share one lease across the tasks of a job.\n */\nexport class LeaseLimitError extends CloudRoaringError {}\n\n/**\n * An operand a call relied on changed while the call ran, so what the call built from it is not published. Carries the\n * operand's name in the call and why it is stale (`'moved'`: it was pinned at a generation and its pointer has since\n * moved; `'erased'`: an erasure ran in the store after a call with a feed began, so what the feed gave it may hold an\n * erased id), under the stable `code`\n * `'stale-operand'`. Deterministic: run the call again against the current operand.\n */\nexport class StaleOperandError extends CloudRoaringError {\n /** The stable code `'stale-operand'`, to match on. */\n readonly code = 'stale-operand' as const;\n /** The operand's name in the call that found it stale. */\n readonly operand: string;\n /** Why it is stale. */\n readonly reason: 'moved' | 'erased';\n /** Builds the error from its `message`, the operand's name and why it is stale. */\n constructor(message: string, operand: string, reason: 'moved' | 'erased') {\n super(message);\n this.operand = operand;\n this.reason = reason;\n }\n}\n\n/**\n * This build/configuration cannot perform the requested operation, though nothing is malformed. Two uses:\n * (1) **format** \u2014 the bytes are well-formed but unreadable here (an unknown `.crbm` major version) \u2014\n * distinct from `IntegrityError` (corruption); and (2)\n * **store configuration** \u2014 an operation this store's wiring doesn't support (e.g. a lifecycle helper like\n * `eraseSubject`/`retireExpired` called on a store built without a storage backend). Raised at\n * operation time, before any mutation.\n */\nexport class UnsupportedError extends CloudRoaringError {}\n\n/**\n * A driver cannot meet a capability the chosen topology requires (e.g. a Storage driver without range\n * reads). Raised fail-fast at wiring time, never mid-operation.\n */\nexport class CapabilityError extends CloudRoaringError {}\n\n/**\n * An operation would exceed one of its per-op **denial-of-wallet bounds** \u2014 too many backend requests\n * (`budget.maxRequests`), too many bytes held at once by a combine (`maxBufferedBytes`), or too many registry rows\n * in a scan (`maxScanSegments`) \u2014 so it is refused, before the fan-out where it can be known beforehand (hard\n * invariant 6). Default-on but generous (normal ops never hit it); tune each per store or per op, or disable the\n * request budget with `budget: false`. Deterministic (never retried): the op is too big by policy, not by luck.\n * Each request's bytes are separately capped (the safe-deserialize ceiling), so bounding the request count\n * transitively bounds bytes.\n *\n * Carries an option name and two numbers, and no data: `option` names the option to raise, `limit` is the bound in\n * force, and `spent` is what the call had reached when it was refused. What `spent` measures depends on `option`:\n *\n * - `'budget.maxRequests'`: the requests the call needs, which raising the option to it lets through. For a plan, it\n * is the planned reads (with the reads already taken, when a run plans again); an enumeration that\n * stops at the bound reports `limit + 1`, a lower bound.\n * - `'maxBufferedBytes'`: a **lower bound** on the bytes the call needs resident: what it held plus what it asked\n * for at the moment it was refused. Raising the limit to `spent` can be refused again, further on, because the\n * call had not finished growing. The one figure that lets an output through is the per-output refusal's, which\n * the message gives as \"raise maxBufferedBytes to at least N\". Otherwise raise the limit with room to spare, or\n * split the outputs across calls.\n * - `'maxScanSegments'`: `limit + 1`, a lower bound: the scan stops at the first row past the bound (for the retention\n * sweep's due-index scan, the first due-index pointer, unread, which may be stale), so it never learns the fleet's\n * size.\n *\n * The message states the same limit.\n */\nexport class BudgetExceededError extends CloudRoaringError {\n /** The option to raise to let the call through. */\n readonly option: 'budget.maxRequests' | 'maxBufferedBytes' | 'maxScanSegments';\n /** The bound in force: requests, bytes or rows, by `option`. */\n readonly limit: number;\n /**\n * What the call had reached when refused. By `option`: the requests the call needs (`'budget.maxRequests'`), a\n * lower bound on the resident bytes it needs (`'maxBufferedBytes'`), or `limit + 1` (`'maxScanSegments'`).\n */\n readonly spent: number;\n /** Builds the error from its `message` and the `option`, `limit` and `spent` it reports. */\n constructor(\n message: string,\n details: {\n readonly option: 'budget.maxRequests' | 'maxBufferedBytes' | 'maxScanSegments';\n readonly limit: number;\n readonly spent: number;\n },\n ) {\n super(message);\n this.option = details.option;\n this.limit = details.limit;\n this.spent = details.spent;\n }\n}\n\n/**\n * An encrypted segment's data key (DEK) cannot be unwrapped because the keystore holds none of the\n * key-encryption-keys (KEKs) its wrappings reference \u2014 the KEK was never configured, rotated away without\n * keeping the old key, or lost. Deterministic (never retried): without a KEK the ciphertext is unreadable by\n * design. The flip side of crypto-shred \u2014 when this is *intended* (a destroyed segment) the registry row is\n * already a `destroyed` tombstone; when it's *not*, restore the missing KEK (or its recovery KEK). Carries no\n * key material.\n */\nexport class KeyUnavailableError extends CloudRoaringError {}\n\n/**\n * A **transient** infrastructure fault \u2014 throttling, a 5xx, a dropped connection, a client-side request\n * timeout. Retrying a read that failed this way is safe; a write that failed this way may still have landed, so\n * its caller re-runs the call rather than replaying the request. Drivers classify their backend's retryable faults and raise this (the\n * SDK-specific knowledge stays in the SDK-specific driver); the retry layer (`core/retry`) retries **only**\n * this class, never a deterministic error like {@link ValidationError}, {@link IntegrityError},\n * {@link NotFoundError}, or {@link WriteConflictError} (retrying those is pointless or wrong). The original\n * error is preserved in `cause` so callers can still inspect it.\n *\n * Note for logging hygiene: `cause` is the **raw SDK error**, which may carry operational\n * metadata (endpoint host, request IDs, `$metadata`). The library's own `message` is identifier-only and safe\n * to log; if you serialize the whole error *chain*, be aware you're including that metadata.\n */\nexport class TransientError extends CloudRoaringError {\n /** A second brand so a transient fault is classifiable cross-bundle. */\n readonly [TRANSIENT_BRAND] = true as const;\n /** Builds the error from `message`; `options.cause`, when given, is kept as `cause`. */\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n if (options && 'cause' in options) this.cause = options.cause;\n }\n}\n\n// The names, registered once the classes exist. A class added above and left out here is named by the minifier.\nNAMES.set(CloudRoaringError, 'CloudRoaringError');\nNAMES.set(ValidationError, 'ValidationError');\nNAMES.set(WriteConflictError, 'WriteConflictError');\nNAMES.set(IntegrityError, 'IntegrityError');\nNAMES.set(NotFoundError, 'NotFoundError');\nNAMES.set(LeaseExpiredError, 'LeaseExpiredError');\nNAMES.set(LeaseLimitError, 'LeaseLimitError');\nNAMES.set(StaleOperandError, 'StaleOperandError');\nNAMES.set(UnsupportedError, 'UnsupportedError');\nNAMES.set(CapabilityError, 'CapabilityError');\nNAMES.set(BudgetExceededError, 'BudgetExceededError');\nNAMES.set(KeyUnavailableError, 'KeyUnavailableError');\nNAMES.set(TransientError, 'TransientError');\n\n/**\n * Bundle-safe error predicates. Core's own modules use these, not `instanceof`, wherever an error may cross the\n * core\u2194driver package boundary. They match the {@link ERROR_BRAND} registry brand + the runtime `name`, both of\n * which survive separate bundling. No entry exports them: callers outside core use {@link errorKind}.\n */\nfunction hasBrand(err: unknown, brand: symbol): boolean {\n return (\n typeof err === 'object' && err !== null && (err as Record<symbol, unknown>)[brand] === true\n );\n}\n\n/** Any error thrown by CloudRoaring (any tier, any bundle). */\nexport function isCloudRoaringError(err: unknown): err is CloudRoaringError {\n return hasBrand(err, ERROR_BRAND);\n}\n\n/** An OCC conditional write/delete lost the race \u2014 retry the read-modify-write, don't fail. */\nexport function isWriteConflictError(err: unknown): err is WriteConflictError {\n return isCloudRoaringError(err) && err.name === 'WriteConflictError';\n}\n\n/**\n * The mark {@link unsettledConflict} puts on a conflict: a registry write that may have landed before it met it.\n * Registered, like the other brands, so a publish built from another copy of the package reads a driver's mark.\n */\nconst UNSETTLED_BRAND: unique symbol = Symbol.for('cloudbitmaps.error.unsettled-conflict');\n\n/**\n * A {@link WriteConflictError} for a registry `create` or `compareAndSwap` that may have landed before it met the\n * conflict, so the conflict does not prove the write was refused. Throw it for every conflict of a write your backend's\n * client may have sent more than once and that you cannot prove did not land: the read-back finds another writer's\n * write over the row (a row is overwritten, so that writer may have swapped in over this write after it landed), or\n * finds the row gone, or the compare-and-swap itself is answered that the row is gone. Throw a plain\n * `WriteConflictError` for a conflict that does prove it: a write sent once, or a check your driver made before sending\n * anything. A registry that wraps another rethrows the conflict it was given, not a new one, which would lose the mark.\n *\n * It is a `WriteConflictError` in every other way: `errorKind` names it `'WriteConflictError'`, `instanceof` holds on\n * the same copy of the package, and every caller that handles a conflict handles it. A load's publish reads the row\n * again, as after any conflict, and takes the write as its own when the row shows it there. Otherwise the write is\n * reported to the load, as a write with no answer is, so a load refused after it carries `unanswered: true` on its\n * `segment.load-refused` audit event. The mark is a registered `Symbol.for` brand, read\n * across copies of the package. It is lost when the error is cloned or copied into a new one, and a conflict raised\n * anywhere but a registry write is read as the plain conflict it also is.\n */\nexport function unsettledConflict(message: string): WriteConflictError {\n const err = new WriteConflictError(message);\n Object.defineProperty(err, UNSETTLED_BRAND, { value: true });\n return err;\n}\n\n/**\n * Whether `err` is a conflict a driver raised with {@link unsettledConflict}: a {@link WriteConflictError}, by brand\n * and name as {@link isWriteConflictError} reads it, that carries the unsettled mark. It reads the registered brand,\n * so it holds for an error from another copy of the package. Like the other predicates, no entry exports it.\n */\nexport function isUnsettledConflict(err: unknown): boolean {\n return isWriteConflictError(err) && hasBrand(err, UNSETTLED_BRAND);\n}\n\n/** A retryable transient infrastructure fault. The retry layer keys on this. */\nexport function isTransientError(err: unknown): err is TransientError {\n return hasBrand(err, TRANSIENT_BRAND);\n}\n\n/** A read came after its pin's lease ended. */\nexport function isLeaseExpiredError(err: unknown): err is LeaseExpiredError {\n return isCloudRoaringError(err) && err.name === 'LeaseExpiredError';\n}\n\n/** An operand a call relied on changed while it ran. */\nexport function isStaleOperandError(err: unknown): err is StaleOperandError {\n return isCloudRoaringError(err) && err.name === 'StaleOperandError';\n}\n\n/** A segment has no room for another live lease. */\nexport function isLeaseLimitError(err: unknown): err is LeaseLimitError {\n return isCloudRoaringError(err) && err.name === 'LeaseLimitError';\n}\n\n/** A requested object/row does not exist. */\nexport function isNotFoundError(err: unknown): err is NotFoundError {\n return isCloudRoaringError(err) && err.name === 'NotFoundError';\n}\n\n/** Corrupt/oversized/failed-checksum bytes from a tier. */\nexport function isIntegrityError(err: unknown): err is IntegrityError {\n return isCloudRoaringError(err) && err.name === 'IntegrityError';\n}\n\n/**\n * Invalid caller input; also the error a cloud driver raises for a bucket or container it finds does not exist.\n */\nexport function isValidationError(err: unknown): err is ValidationError {\n return isCloudRoaringError(err) && err.name === 'ValidationError';\n}\n\n/** This build or this store's wiring cannot do what was asked, though nothing is malformed. */\nexport function isUnsupportedError(err: unknown): err is UnsupportedError {\n return isCloudRoaringError(err) && err.name === 'UnsupportedError';\n}\n\n/** A driver lacks a capability the store's wiring needs. */\nexport function isCapabilityError(err: unknown): err is CapabilityError {\n return isCloudRoaringError(err) && err.name === 'CapabilityError';\n}\n\n/** A call would pass its per-op request budget, so it was refused before fanning out. */\nexport function isBudgetExceededError(err: unknown): err is BudgetExceededError {\n return isCloudRoaringError(err) && err.name === 'BudgetExceededError';\n}\n\n/** No key the keystore holds can unwrap an encrypted segment's data key. */\nexport function isKeyUnavailableError(err: unknown): err is KeyUnavailableError {\n return isCloudRoaringError(err) && err.name === 'KeyUnavailableError';\n}\n\n/** The name of one of the library's error classes, as `errorKind` returns it. */\nexport type ErrorKind =\n | 'CloudRoaringError'\n | 'ValidationError'\n | 'WriteConflictError'\n | 'IntegrityError'\n | 'NotFoundError'\n | 'UnsupportedError'\n | 'CapabilityError'\n | 'TransientError'\n | 'KeyUnavailableError'\n | 'BudgetExceededError'\n | 'LeaseExpiredError'\n | 'LeaseLimitError'\n | 'StaleOperandError';\n\n/**\n * Every {@link ErrorKind}, as a record so that a kind added to the type and left out here fails to compile. Not\n * exported: a declaration that named it would put it in the public surface.\n */\nconst KIND_NAMES: Record<ErrorKind, true> = {\n CloudRoaringError: true,\n ValidationError: true,\n WriteConflictError: true,\n IntegrityError: true,\n NotFoundError: true,\n UnsupportedError: true,\n CapabilityError: true,\n TransientError: true,\n KeyUnavailableError: true,\n BudgetExceededError: true,\n LeaseExpiredError: true,\n LeaseLimitError: true,\n StaleOperandError: true,\n};\n\n/**\n * Which of the library's error classes `err` is, or `undefined` when it is none of them. Works on every copy of\n * the package, every bundle and every realm, where `instanceof` can silently stop matching: it reads the\n * `Symbol.for` brands and the error's `name`. An application's own subclass of one class returns\n * `'CloudRoaringError'`, except a subclass of `TransientError`, which returns `'TransientError'`; an error\n * cloned out of a worker (the brand is gone) returns `undefined`.\n */\nexport function errorKind(err: unknown): ErrorKind | undefined {\n if (hasBrand(err, TRANSIENT_BRAND)) return 'TransientError';\n if (!hasBrand(err, ERROR_BRAND)) return undefined;\n const name = (err as { name?: unknown }).name;\n return typeof name === 'string' && Object.hasOwn(KIND_NAMES, name)\n ? (name as ErrorKind)\n : 'CloudRoaringError';\n}\n", "/**\n * Number checks shared by every option and argument the core validates, so a bad number is refused by one rule and\n * worded one way: `<what> must be <a range>; got <the value>`. Each throws `ValidationError` and returns the value it\n * accepted, so a call can wrap the expression that produced it. Pure: no I/O, time or globals.\n *\n * A `note` is a short clause set after the range (`must be an integer of at least 0 (required); got undefined`), for\n * what the range alone does not say.\n *\n * ```\n * requireInteger(1.5, { min: 1, max: 8, what: 'concurrency' })\n * -> ValidationError: concurrency must be an integer from 1 to 8; got 1.5\n * requirePositiveInteger('3', 'limit')\n * -> ValidationError: limit must be an integer of at least 1; got \"3\"\n * requireFiniteNumber(Infinity, { min: 0, what: 'tombstoneGraceMs' })\n * -> ValidationError: tombstoneGraceMs must be a finite number of at least 0; got Infinity\n * ```\n *\n * Integers are safe integers: 2^53 and above are refused, whatever the bounds say.\n */\nimport { ValidationError } from './errors';\n\n/**\n * A value as a message shows it: a number or boolean as itself, a bigint with an `n` (so `5n` is not mistaken for\n * `5`), a string quoted (so `'200'` is not mistaken for `200`), and anything else by its type.\n */\nexport function shown(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value);\n if (typeof value === 'bigint') return `${value}n`;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return value === null ? 'null' : typeof value;\n}\n\n/**\n * `from <min> to <max>`, `of at least <min>` or `of at most <max>`, or nothing when neither bound is set, then the\n * `note` in parentheses when there is one.\n */\nfunction rangeOf(\n min: number | undefined,\n max: number | undefined,\n note: string | undefined,\n): string {\n let range = '';\n if (min !== undefined && max !== undefined) range = ` from ${min} to ${max}`;\n else if (min !== undefined) range = ` of at least ${min}`;\n else if (max !== undefined) range = ` of at most ${max}`;\n return note === undefined ? range : `${range} (${note})`;\n}\n\n/**\n * `value` if it is a safe integer from `min` to `max` (inclusive; `max` defaults to the largest safe integer), else a\n * `ValidationError` naming `what`: `<what> must be an integer from <min> to <max>; got <value>`.\n */\nexport function requireInteger(\n value: unknown,\n bounds: {\n readonly min: number;\n readonly max?: number;\n readonly what: string;\n readonly note?: string;\n },\n): number {\n const { min, max, what, note } = bounds;\n if (\n typeof value !== 'number' ||\n !Number.isSafeInteger(value) ||\n value < min ||\n (max !== undefined && value > max)\n ) {\n throw new ValidationError(\n `${what} must be an integer${rangeOf(min, max, note)}; got ${shown(value)}`,\n );\n }\n return value;\n}\n\n/**\n * Refuse a `requireEncryption` that is present and not exactly a boolean. Every site that acts on the flag compares it\n * with `=== true`, so a truthy string would be taken for `true` by one and for `false` by another.\n */\nexport function checkRequireEncryption(value: unknown): void {\n if (value !== undefined && typeof value !== 'boolean') {\n throw new ValidationError(`requireEncryption must be a boolean; got ${shown(value)}`);\n }\n}\n\n/** `value` if it is a safe integer of 1 or more, else a `ValidationError` naming `what`. */\nexport function requirePositiveInteger(value: unknown, what: string): number {\n return requireInteger(value, { min: 1, what });\n}\n\n/**\n * `value` if it is a finite number within the optional `min` and `max` (inclusive), else a `ValidationError` naming\n * `what`: `<what> must be a finite number from <min> to <max>; got <value>`. `NaN` and the infinities are refused.\n */\nexport function requireFiniteNumber(\n value: unknown,\n bounds: {\n readonly min?: number;\n readonly max?: number;\n readonly what: string;\n readonly note?: string;\n },\n): number {\n const { min, max, what, note } = bounds;\n if (\n typeof value !== 'number' ||\n !Number.isFinite(value) ||\n (min !== undefined && value < min) ||\n (max !== undefined && value > max)\n ) {\n throw new ValidationError(\n `${what} must be a finite number${rangeOf(min, max, note)}; got ${shown(value)}`,\n );\n }\n return value;\n}\n\n/**\n * Refuse an options bag that is not an object, or that holds a key not in `keys`, naming each such key and the keys it\n * takes. `hint`, when given, ends the message, to point at where a likely mistake belongs (`an S3 client goes in\n * \\`client\\``). Only the bag's own enumerable string keys are read, so a key inherited through a prototype is not\n * checked.\n */\nexport function refuseUnknownOptions(\n name: string,\n options: unknown,\n keys: readonly string[],\n hint?: string,\n): void {\n if (options === null || typeof options !== 'object') {\n throw new ValidationError(\n `${name} needs an options object \u2014 got ${options === null ? 'null' : typeof options}`,\n );\n }\n const unknown = Object.keys(options).filter((k) => !keys.includes(k));\n if (unknown.length > 0) {\n const list = (ks: readonly string[]): string => ks.map((k) => `\\`${k}\\``).join(', ');\n throw new ValidationError(\n `${name} does not take ${list(unknown)}. It takes ${list(keys)}${hint === undefined ? '' : `; ${hint}`}.`,\n );\n }\n}\n\n/**\n * The option `name`'s `value`, refused with `ValidationError` unless it is absent or a boolean: a truthy string or a\n * `1` is not taken for `true`, and `null` is not taken for absent. An absent value comes back `undefined`, for the\n * caller's default.\n */\nexport function requireBool(name: string, value: unknown): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') {\n throw new ValidationError(`${name} must be a boolean; got ${shown(value)}`);\n }\n return value;\n}\n\n/**\n * The option `name`'s `value`, refused with `ValidationError` unless it is absent or a string with something in it\n * (one that is empty or only whitespace is refused, as is `null`). An absent value comes back `undefined`.\n */\nexport function requireNonEmptyString(name: string, value: unknown): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new ValidationError(\n `${name} must be a non-empty string; got ${typeof value === 'string' ? 'an empty string' : shown(value)}`,\n );\n }\n return value;\n}\n", "/**\n * BitRouteSplitter \u2014 maps a 32-bit id to its chunk (top 16 bits) and remainder\n * (bottom 16 bits), per the data model.\n */\nimport { ValidationError } from './errors';\n\nexport const U32_MAX = 0xffff_ffff;\nexport const CHUNK_COUNT = 0x1_0000; // 65,536 possible chunk keys\nconst LOW_16 = 0xffff;\n\ninterface BitRoute {\n /** Top 16 bits \u2014 the chunk key (0..65535). */\n readonly chunkKey: number;\n /** Bottom 16 bits \u2014 the value within the chunk (0..65535). */\n readonly remainder: number;\n}\n\n/** Errors `splitId` threw, so a caller that adds the id's position can tell them from another ValidationError. */\nconst idErrors = new WeakSet<ValidationError>();\n\n/** Was `err` thrown by {@link splitId} for an id outside the u32 range? */\nexport function isBadIdError(err: unknown): err is ValidationError {\n return err instanceof ValidationError && idErrors.has(err);\n}\n\n/** The error for an id that is not a u32. It names what is wrong with the id and never repeats its value. */\nfunction badId(id: unknown): ValidationError {\n let got: string;\n if (id === null) got = 'null';\n else if (id === undefined) got = 'undefined';\n else if (typeof id === 'object') got = 'an object';\n else if (typeof id !== 'number') got = `${/^[aeiou]/.test(typeof id) ? 'an' : 'a'} ${typeof id}`;\n else if (!Number.isFinite(id)) got = 'NaN or an infinity';\n else if (id < 0) got = 'a negative number';\n else if (!Number.isInteger(id)) got = 'a number with a fraction';\n else got = `a number above ${U32_MAX} (ids are 32-bit)`;\n const err = new ValidationError(`an id must be an integer from 0 to ${U32_MAX}; got ${got}`);\n idErrors.add(err);\n return err;\n}\n\n/** The refusal {@link splitId} throws for a value that is not a u32 id, for a caller that checks the range itself. */\nexport function refusalOfId(id: unknown): ValidationError {\n return badId(id);\n}\n\n/** Split a u32 id into `{ chunkKey, remainder }`. Throws `ValidationError` for non-u32 input. */\nexport function splitId(id: number): BitRoute {\n if (!Number.isInteger(id) || id < 0 || id > U32_MAX) {\n throw badId(id);\n }\n return { chunkKey: id >>> 16, remainder: id & LOW_16 };\n}\n\n/**\n * Largest legal value inside a chunk payload. A chunk covers `CHUNK_COUNT` ids, so remainders run\n * `[0, CHUNK_COUNT - 1]`. Exported so the engine can assert it on untrusted tier bytes.\n */\nexport const MAX_REMAINDER = CHUNK_COUNT - 1;\n\n/**\n * Recombine a chunk key + remainder back into the u32 id. Precondition: `chunkKey` is a validated\n * 16-bit value (tier-derived keys are validated upstream in the engine before reaching here, per\n * invariant 5); `remainder` is masked to 16 bits.\n */\nexport function joinId(chunkKey: number, remainder: number): number {\n return (((chunkKey & LOW_16) << 16) >>> 0) + (remainder & LOW_16);\n}\n", "/**\n * Name \u2192 physical-key encoding. The library validates *length*, and encodes everything else.\n *\n * Lives in `core/` rather than beside the drivers because it is pure string logic \u2014 no I/O, no SDK, no\n * `node:` builtin \u2014 and because `validate.ts` needs it to measure a name against the key budget. Core may\n * not import a driver (invariant 7), and a driver may import core, so this is the only layer both can see.\n *\n * A name is **any non-empty string**, and each physical boundary escapes what *it* cannot take literally. An\n * allowlist of characters would reject names for the storage layer's convenience, and the storage layer's\n * convenience is the library's job, not the caller's. It would also let through the names that are actually\n * dangerous: `con`, `nul` and `com1` are Windows device names made only of letters and digits, which pass any\n * allowlist and fail only on a user's machine. A grammar can be both too narrow and too permissive at once,\n * which is the argument against having one.\n *\n * Percent-encoding, because it is the one escape everybody already reads. `%` escapes itself as `%25` and is\n * encoded **first**, which is what makes the transform injective: every `%` in an encoded string starts an\n * escape, so decoding is unambiguous and two distinct names can never collide on one key.\n *\n * There are two alphabets, because the boundaries differ:\n *\n * - **Object keys** (S3, GCS, Azure Blob) take almost anything. They need `/` escaped so a name cannot\n * invent hierarchy or break a key parser that splits on it, and control characters because they are not\n * legal in the XML an S3 LIST returns. Every other character outside `[A-Za-z0-9._:-]` is escaped as well.\n * - **Filesystem paths** need all of that plus `:` (an NTFS alternate-data-stream separator, where a write can\n * *succeed* while `readdir` never lists the result), plus three hazards that are about the component as a\n * whole rather than its characters \u2014 see {@link encodeNameForPath}.\n *\n * **The key alphabet is fixed for good.** Adding a character to it would change what `encodeNameForKey` emits\n * for every name containing that character, silently moving those segments to keys nothing looks up. A test pins\n * it, one printable ASCII character at a time.\n *\n * **A plain name encodes to itself on the OBJECT-KEY alphabet** \u2014 one made only of `[A-Za-z0-9._:-]` that\n * starts with a letter or digit \u2014 so S3, GCS and Azure keys read as the names that made them. That is the\n * property to preserve if this file is ever edited, and a property test asserts it over every plain name.\n *\n * The **path** alphabet escapes more. Besides `:`, two classes of plain name are escaped on a path: a Windows\n * device-name stem (`con`, `nul`, `com1`, `con.backup`) and a trailing dot (`a.`), since both silently alias\n * or fail on Windows.\n */\n\n/** Characters safe in an object key, left literal so a plain name reads as itself in the bucket. */\nconst KEY_SAFE = /[A-Za-z0-9._:-]/;\n/** Characters safe in a path component. As {@link KEY_SAFE} minus `:`. */\nconst PATH_SAFE = /[A-Za-z0-9._-]/;\n\nconst UTF8 = new TextEncoder();\nconst UTF8_LENIENT = new TextDecoder('utf-8', { fatal: false, ignoreBOM: true });\n\n/**\n * Percent-encode one character's UTF-8 bytes: `\u00E9` \u2192 `%C3%A9`.\n *\n * Only ever called with a WELL-FORMED code point. `TextEncoder` maps an unpaired surrogate to U+FFFD, which\n * would make every surrogate \u2014 and U+FFFD itself \u2014 encode identically and silently break injectivity, so\n * `validate.ts` refuses a name that is not well-formed UTF-16 before any of this runs.\n */\nfunction escapeChar(ch: string): string {\n let out = '';\n for (const byte of UTF8.encode(ch)) {\n out += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;\n }\n return out;\n}\n\nfunction encodeWith(name: string, safe: RegExp): string {\n let out = '';\n // Iterate by code POINT, not code unit: a surrogate pair is one character and must encode as one UTF-8\n // sequence. Indexing by `charAt` would split an emoji into two unpaired halves and produce garbage bytes.\n for (const ch of name) {\n out += ch !== '%' && safe.test(ch) ? ch : escapeChar(ch);\n }\n // A LEADING underscore is escaped, which is what keeps the reserved namespaces reachable only by us.\n //\n // `_default` is the physical stand-in for an absent namespace. Unescaped, it would hand any caller a way to\n // name a namespace `_default` and have it resolve to everyone else's un-namespaced data. Escaping the first\n // `_` makes the sentinel unreachable by construction rather than by a blocklist that has to be maintained.\n return out.startsWith('_') ? `%5F${out.slice(1)}` : out;\n}\n\nfunction decodePercent(encoded: string): string {\n const bytes: number[] = [];\n for (let i = 0; i < encoded.length;) {\n if (encoded[i] === '%' && i + 2 <= encoded.length) {\n const hex = encoded.slice(i + 1, i + 3);\n if (!/^[0-9A-Fa-f]{2}$/.test(hex)) return encoded; // not an escape we wrote\n bytes.push(parseInt(hex, 16));\n i += 3;\n } else {\n for (const b of UTF8.encode(encoded[i]!)) bytes.push(b);\n i += 1;\n }\n }\n // `ignoreBOM: true` is load-bearing, not a tidy-up. Without it `TextDecoder` STRIPS a leading U+FEFF, so\n // `%EF%BB%BForders` decodes to `orders` \u2014 a different, probably existing, segment. That is a collision in\n // the one direction everything else here rests on, and it is reachable: `validatePart` accepts U+FEFF, and\n // a BOM-prefixed name is what any spreadsheet export or CSV read without BOM stripping hands you.\n //\n // The visible symptom was worse than a failed round-trip. Each parser (`parseRegistryRow`,\n // `parseNamespaceDir`, `parseRegistryKey`) re-encodes what it decoded and refuses a spelling it cannot\n // reproduce, so a BOM-prefixed row could be WRITTEN and then silently skipped by `list()`,\n // `checkConsistency`, `exportSegments`, the retention sweep and subject erasure \u2014 present in the bucket and\n // invisible to every sweep over it.\n //\n // Decode-only, so nothing that works today changes: `encode` is untouched, no stored key moves, and the\n // only names whose decoding changes are ones that are currently rejected by that round-trip guard anyway.\n return UTF8_LENIENT.decode(new Uint8Array(bytes));\n}\n\n/**\n * Encode a name for use inside an **object key** (S3, GCS, Azure Blob).\n *\n * Leaves `[A-Za-z0-9._:-]` literal, except a leading `_` and a name that is only `.` or `..`, so a plain name\n * reads as itself, and escapes everything else \u2014 including `/` (which would invent hierarchy and break a parser\n * that splits on it) and control characters (not legal in S3's XML responses).\n */\nexport function encodeNameForKey(name: string): string {\n return defuseDotComponent(encodeWith(name, KEY_SAFE));\n}\n\n/**\n * Escape a component that is exactly `.` or `..`.\n *\n * Applied to **both** alphabets. It is obviously needed for a filesystem path, and it is needed for an object\n * key too: the library's own S3/GCS/Azure calls treat the key space as flat, but the moment those keys touch\n * something hierarchical the component resolves. `aws s3 sync`, `gsutil -m cp -r` and `azcopy` all write\n * `dest/tenant/../segments/\u2026`, which lands *outside* `tenant/`; s3fs and gcsfuse mounts do the same; and on\n * ADLS Gen2, where the namespace really is hierarchical, `prefix/../x` and `x` are the same object. Those are\n * the DR-restore and eject paths this library documents.\n *\n * `normalizeObjectPrefix` refuses `.`/`..` segments in a **prefix**, which is trusted config; the name, the input an\n * attacker can influence, is escaped here instead.\n *\n * Every dot is escaped rather than just the first, so the result cannot end in one either.\n */\nfunction defuseDotComponent(encoded: string): string {\n return encoded === '.' || encoded === '..' ? encoded.replaceAll('.', '%2E') : encoded;\n}\n\n/** Inverse of {@link encodeNameForKey}. */\nexport function decodeNameFromKey(encoded: string): string {\n return decodePercent(encoded);\n}\n\n/**\n * Encode a name for use as a **filesystem path component**.\n *\n * Everything {@link encodeNameForKey} escapes, plus `:`, plus three hazards that are properties of the whole\n * component rather than of any character in it. All three are silent corruption rather than errors, which is\n * why they are handled here instead of being left to the OS:\n *\n * 1. **`.` and `..`** are traversal. `join(root, '..')` leaves the storage root.\n * 2. **Windows reserved device names** \u2014 `CON`, `PRN`, `AUX`, `NUL`, `COM1`\u2013`COM9`, `LPT1`\u2013`LPT9`, case\n * insensitive and *with or without an extension*, so `con.0.crbm` is reserved too. Opening one addresses a\n * device rather than a file, so `store.segment('con')` would break only on a user's Windows box.\n * 3. **A trailing `.` or space**, which Windows silently strips \u2014 so `a.` and `a` would become the same\n * directory, quietly merging two segments.\n *\n * Each is fixed by escaping the one character that defuses it, which keeps the encoding injective: a name that\n * needed defusing produces a `%XX` no other name produces.\n */\nexport function encodeNameForPath(name: string): string {\n let encoded = encodeWith(name, PATH_SAFE);\n\n // The traversal case may return on its own only because `defuseDotComponent` escapes EVERY dot. Escaping just\n // the first would turn `..` into `%2E.`, which ends in a dot: hazard 3, reintroduced by the fix for hazard 1.\n const dotted = defuseDotComponent(encoded);\n if (dotted !== encoded) return dotted;\n\n // A Windows device name is reserved with OR without an extension, so the test is on the stem.\n const stem = encoded.split('.')[0] ?? '';\n if (/^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(stem)) {\n encoded = escapeChar(encoded[0] as string) + encoded.slice(1);\n }\n\n // Windows strips a trailing dot, which would alias two distinct names onto one path. A trailing SPACE is the\n // same hazard but needs no arm here: space is not in `PATH_SAFE`, so the charset already escaped it to `%20`.\n if (encoded.endsWith('.')) encoded = `${encoded.slice(0, -1)}%2E`;\n\n return encoded;\n}\n\n/** Inverse of {@link encodeNameForPath}. */\nexport function decodeNameFromPath(encoded: string): string {\n return decodePercent(encoded);\n}\n", "/**\n * Boundary validation for segment / namespace names.\n *\n * **A name is any non-empty string.** There is no character allowlist, because an allowlist rejects names for\n * the storage layer's convenience \u2014 and the storage layer's convenience is this library's problem, not the\n * caller's. Every physical boundary escapes what *it* cannot take literally (`core/name-codec.ts`),\n * so `dedup:2026-08-01`, `user@example.com`, `orders/2026`, `\u65E5\u672C\u8A9E` and `100%` are all ordinary names.\n *\n * A grammar would fail in both directions. It would reject names that are merely unfamiliar, and it would pass\n * names that are genuinely broken \u2014 `con`, `nul` and `com1` are Windows device names made only of letters and\n * digits, so `store.segment('con')` would validate cleanly and fail only on a user's machine. Encoding handles\n * both: it accepts what is merely unfamiliar, and defuses what is actually dangerous.\n *\n * What remains is **size** and **representability**, both real constraints rather than tastes.\n *\n * Size: S3 caps an object key at 1024 bytes and a name is only one part of it. The cap is applied to the\n * **encoded** length \u2014 and to the longer of the two encodings, since a path escapes `:` three-for-one where a\n * key leaves it literal \u2014 because a limit measured on the input would let a key exceed the backend's.\n *\n * Representability: a name must be well-formed UTF-16, because an unpaired surrogate has no UTF-8 encoding at\n * all. Letting one through would not merely store oddly; every lone surrogate encodes to the same replacement\n * bytes, so four distinct names would claim one key.\n */\nimport { ValidationError } from './errors';\nimport { encodeNameForKey, encodeNameForPath } from './name-codec';\nimport type { ChunkRef, SegmentRef } from './ports';\n\nconst CHUNK_KEY_MAX = 0xffff;\n\n/**\n * The most an encoded name may occupy in a physical key.\n *\n * S3's limit is 1024 bytes for the WHOLE key, which also carries the caller's prefix, the namespace, a fixed\n * infix (`/segments/`) and the `.<generation>.crbm` suffix. 256 leaves generous room for all of that with both\n * a namespace and a segment at the ceiling.\n */\nexport const MAX_NAME_LENGTH = 256;\n\n/**\n * A high surrogate not followed by a low one, or a low surrogate not preceded by a high one.\n *\n * Deliberately NOT `/u` and not `String.prototype.isWellFormed()`: the flag would make the engine read\n * code points, which is the very distinction being tested, and the method needs an ES2024 lib target\n * this package does not set. Matching on code units is what sees a half of a pair.\n */\nconst LONE_SURROGATE = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/** Whether `value` is well-formed UTF-16: no unpaired surrogate, so it survives a round trip through UTF-8. */\nexport function isWellFormedString(value: string): boolean {\n return !LONE_SURROGATE.test(value);\n}\n\n/**\n * How long a name is once storage has it \u2014 the longer of the two encodings.\n *\n * Exported because anything that composes a name out of other names (the due index does) has to measure it the\n * same way, and a second copy of that rule is how the two drifted apart before.\n */\nexport function encodedNameLength(value: string): number {\n return Math.max(encodeNameForKey(value).length, encodeNameForPath(value).length);\n}\n\nfunction validatePart(value: string, field: string): void {\n if (typeof value !== 'string') {\n throw new ValidationError(`${field} must be a string; got ${typeof value}`);\n }\n if (value.length === 0) {\n throw new ValidationError(`${field} must not be empty`);\n }\n // Cheap bound BEFORE encoding. Encoding never shrinks a string, so a name already over the cap in raw units\n // is over it encoded \u2014 and rejecting first means an attacker-supplied name cannot make us build a 60 MB\n // string to find out. (Measured: a 10-million-unit name cost 4.2 s of blocking CPU without this.)\n if (value.length > MAX_NAME_LENGTH) {\n throw new ValidationError(\n `${field} is too long: ${value.length} characters (limit ${MAX_NAME_LENGTH} once encoded for a storage key)`,\n );\n }\n // A name has to survive the round trip to UTF-8 and back. An unpaired surrogate does not: `TextEncoder`\n // replaces it with U+FFFD, so every lone surrogate AND U+FFFD itself would encode to the same bytes \u2014 four\n // distinct names collapsing onto one key, which is the one property everything else here rests on. There is\n // no UTF-8 for a lone surrogate, so this is a limit of the medium rather than a rule we chose.\n if (LONE_SURROGATE.test(value)) {\n throw new ValidationError(\n `${field} contains an unpaired surrogate, so it has no UTF-8 encoding and cannot be stored. This is ` +\n `usually a string sliced through an astral character (an emoji, say) \u2014 slice by code point instead.`,\n );\n }\n // Measured on the ENCODED form, because that is what a bucket has to hold \u2014 and on the LONGER of the two\n // encodings. A path escapes `:` three-for-one where a key leaves it literal, so measuring the key form alone\n // let `'a' + ':'.repeat(255)` pass the boundary and then fail inside the driver with a raw ENAMETOOLONG\n // rather than a typed error at the edge.\n const encoded = encodedNameLength(value);\n if (encoded > MAX_NAME_LENGTH) {\n throw new ValidationError(\n `${field} is too long: ${encoded} characters once encoded for storage (limit ${MAX_NAME_LENGTH}). The name ` +\n `itself is ${value.length} characters \u2014 encoding expands anything outside [A-Za-z0-9._-], so a name of ` +\n `mostly non-ASCII text, or one full of colons, reaches the limit sooner than its length suggests.`,\n );\n }\n}\n\n/**\n * The keys a segment ref takes: its address, and the two a `segments()` row also carries so a listing row can be\n * passed straight back. `discover.ts` holds this list to `SegmentInfo` at compile time, so a field added there is a\n * type error until it is listed here.\n */\nexport const REF_KEYS = ['segment', 'namespace', 'currentGen', 'status'] as const;\n\n/** A ref is an object: a string, null or undefined is the common slip, and says what a ref looks like. */\nfunction requireRefObject(ref: unknown, hint = ''): void {\n if (typeof ref !== 'object' || ref === null) {\n throw new ValidationError(`a segment ref is an object such as { segment: 'name' }${hint}`);\n }\n}\n\n/**\n * Throws `ValidationError` unless `ref` is an object whose `segment` and, when given, `namespace` are valid names, and\n * which holds no other key: a misspelt `namespace` would otherwise address the segment of that name in the default\n * namespace. The keys it takes are a port's: `segment`, `namespace`, a `GenKey`'s `generation`, a `ChunkRef`'s\n * `chunkKey`, and a registry row's own fields and a `segments()` row's, so a row a driver listed can be passed back.\n * It does not refuse a reserved namespace, which a driver must be able to store.\n */\nexport function validateSegmentRef(ref: SegmentRef): void {\n requireRefObject(ref);\n refuseUnknownKeys(ref);\n validatePart(ref.segment, 'segment');\n if (ref.namespace !== undefined) validatePart(ref.namespace, 'namespace');\n}\n\n/**\n * The namespace prefix the library keeps for its own bookkeeping: the due index stores one pointer row per\n * expiring segment in `cbm.due.<bucket>` (see `due-index.ts`). **One constant, read by both sides** \u2014 the\n * application-facing checks below refuse it in a name an application passes in, and the due index writes and\n * recognises its rows by it \u2014 so the two cannot drift.\n *\n * Only this exact prefix is reserved, not `cbm.` as a whole: `cbm.dueX`, `cbm.due` and `cbmdue.eu` are ordinary\n * namespaces. Every fleet-wide enumeration skips the rows of a reserved namespace as bookkeeping, so a segment\n * there would be invisible to an erasure, a consistency check, an export and a retention sweep.\n *\n * Internal: not exported from any entry. The flavor keeps a copy for its own facade checks, and a test pins the\n * two together.\n */\nexport const RESERVED_NAMESPACE_PREFIX = 'cbm.due.';\n\n/** Does this namespace start with {@link RESERVED_NAMESPACE_PREFIX}? `undefined` (no namespace) never does. */\nexport function isReservedNamespace(namespace: string | undefined): boolean {\n return namespace !== undefined && namespace.startsWith(RESERVED_NAMESPACE_PREFIX);\n}\n\n/**\n * Validate a namespace an application names, as a segment ref's namespace or as a `namespace` option that scopes\n * a scan: the name rules, and **not** in the reserved namespace. Internal; the public `validateSegmentRef` of\n * `@cloudbitmaps/core/driver-kit` is the name rules only, which is what a driver needs, since the due index's own\n * rows live in the reserved namespace and go through the drivers.\n */\nexport function validateUserNamespace(namespace: string): void {\n validatePart(namespace, 'namespace');\n if (isReservedNamespace(namespace)) {\n throw new ValidationError(\n `namespace \"${namespace}\" is reserved: names starting with \"${RESERVED_NAMESPACE_PREFIX}\" hold the ` +\n `library's own bookkeeping rows, which every fleet-wide scan skips, so a segment there would be ` +\n `invisible to an erasure, a consistency check, an export and a retention sweep. Choose another namespace.`,\n );\n }\n}\n\n/**\n * The keys a driver port takes beyond a ref's own. The store hands its ports a generation key (a ref and a\n * `generation`) or a chunk ref (a ref and a `chunkKey`) wherever they name a segment, and an operator repairing a\n * registry hands them a row from `registry.list()` or `get()`, whose fields are fixed and listed here. A test holds\n * the row fields to `RegistryRecord`'s.\n */\nexport const PORT_KEYS: readonly string[] = [\n 'generation',\n 'chunkKey',\n 'wrappedDeks',\n 'keyId',\n 'retention',\n 'residency',\n 'summary',\n 'knownGens',\n 'leases',\n 'createdAt',\n 'updatedAt',\n 'token',\n 'pointerId',\n];\n\n/** The mark the flavor's `Segment` handle carries on its prototype; a handle is not a ref. */\nconst SEGMENT_HANDLE_MARK: unique symbol = Symbol.for('cloudbitmaps.roaring.segment/1');\n\n/** The own enumerable string keys of `ref` that neither a ref nor `extraKeys` names. */\nfunction unknownKeysOf(ref: object, extraKeys: readonly string[]): string[] {\n return Object.keys(ref).filter(\n (k) => !(REF_KEYS as readonly string[]).includes(k) && !extraKeys.includes(k),\n );\n}\n\n/** Refuse a ref holding a key a driver port does not take, naming each such key and the keys it does take. */\nfunction refuseUnknownKeys(ref: object): void {\n const unknown = unknownKeysOf(ref, PORT_KEYS);\n if (unknown.length === 0) return;\n const list = unknown.map((k) => `\"${k}\"`).join(', ');\n throw new ValidationError(\n `a driver port: unknown ${unknown.length === 1 ? 'key' : 'keys'} ${list} in the segment ref; it takes ` +\n `{ segment, namespace } and a generation key's \\`generation\\`, a chunk ref's \\`chunkKey\\`, a \\`segments()\\` ` +\n `row's \\`currentGen\\` and \\`status\\`, or a registry row's own fields (a segment addressed without its ` +\n `namespace is a different segment)`,\n );\n}\n\n/**\n * Refuse a segment ref that holds a key it does not take, naming each such key, and a value that is a segment\n * handle or an array rather than a ref. A misspelt `namespace` would otherwise address the segment of that name in\n * the default namespace, and a drop, a rollback or a crypto-shred would act on the wrong segment. Only the ref's own\n * enumerable string keys are read, one whose value is `undefined` included. `verb` names the call in the message.\n */\nexport function refuseUnknownRefKeys(\n ref: object,\n verb: string,\n extraKeys: readonly string[] = [],\n): void {\n if ((ref as Record<symbol, unknown>)[SEGMENT_HANDLE_MARK] === true) {\n throw new ValidationError(\n `${verb}: a segment handle is not a ref; pass { segment, namespace }`,\n );\n }\n if (Array.isArray(ref)) {\n throw new ValidationError(\n `${verb}: a segment ref is an object such as { segment: 'name' }, not an array`,\n );\n }\n const unknown = unknownKeysOf(ref, extraKeys);\n if (unknown.length === 0) return;\n const list = unknown.map((k) => `\"${k}\"`).join(', ');\n throw new ValidationError(\n `${verb}: unknown ${unknown.length === 1 ? 'key' : 'keys'} ${list} in the segment ref; a ref takes ` +\n `{ segment, namespace } (and a \\`segments()\\` row's \\`currentGen\\` and \\`status\\`, which are read for ` +\n `nothing); a segment addressed without its namespace is a different segment`,\n );\n}\n\n/**\n * Validate a segment ref an application hands in: the name rules, and a namespace outside the reserved prefix. With\n * `verb`, the call a caller made, it also refuses a key a ref does not take, beyond `extraKeys`; leave `verb` out only\n * for an internal key that extends a ref with keys of its own.\n */\nexport function validateUserRef(\n ref: SegmentRef,\n verb?: string,\n extraKeys: readonly string[] = [],\n): void {\n requireRefObject(ref, '; store.segment() takes the bare name');\n if (verb !== undefined) refuseUnknownRefKeys(ref, verb, extraKeys);\n validatePart(ref.segment, 'segment');\n if (ref.namespace !== undefined) validateUserNamespace(ref.namespace);\n}\n\n/**\n * Validate the keys of a `getChunks` stream: in ascending order, a key may repeat. Checked before anything is\n * resolved or read, so a caller's mistake costs no request.\n */\nexport function validateChunkKeyOrder(keys: readonly number[]): void {\n for (let i = 1; i < keys.length; i++) {\n if (!(keys[i]! >= keys[i - 1]!))\n throw new ValidationError('chunk keys must be in ascending order');\n }\n}\n\n/** Validate a chunk ref: the segment/namespace rules plus `chunkKey` \u2208 `[0, 65535]` (a u16). A driver-boundary check. */\nexport function validateChunkRef(ref: ChunkRef): void {\n validateSegmentRef(ref);\n validateChunkKey(ref.chunkKey);\n}\n\n/** The chunk-key half of {@link validateChunkRef}, for a caller that has already validated the segment: an integer in `[0, 65535]`. */\nexport function validateChunkKey(chunkKey: number): void {\n if (!(\n typeof chunkKey === 'number' &&\n chunkKey >= 0 &&\n chunkKey <= CHUNK_KEY_MAX &&\n (chunkKey | 0) === chunkKey\n )) {\n throw new ValidationError(`chunkKey must be an integer in [0, ${CHUNK_KEY_MAX}]`);\n }\n}\n", "/**\n * Storage-driver contracts the engine depends on.\n *\n * Two tiers and one pointer. **Storage** is immutable object storage holding `.crbm` generations (`IStorageDriver`,\n * read by the engine through the per-chunk `StorageChunkSource` view the `.crbm` reader implements); the\n * **registry** is the authoritative per-segment record \u2014 which generation is current, the wrapped DEKs, the\n * governance metadata \u2014 under optimistic concurrency (`IRegistryDriver`). Drivers move opaque bytes and OCC\n * tokens; they never understand roaring or the `.crbm` layout.\n */\n\nimport { UnsupportedError, ValidationError } from './errors';\nimport type { BlobSink } from './blob';\nimport type { WrappedDek } from './crypto';\nimport type { IMetricsSink } from './metrics';\n\n/**\n * Opaque optimistic-concurrency token \u2014 unique per write with overwhelming probability, since it carries random parts\n * (see {@link RegistryRecord.token}), and compared by equality only.\n */\nexport type Token = string;\n\n/**\n * The address of one segment: a `namespace` and a `segment` name, both any non-empty string of at most 256\n * characters once encoded for storage. Omitting the namespace addresses a different segment from one that names it.\n *\n * **A namespace starting with `cbm.due.` is reserved**, and every call of the store, and of the free functions\n * behind it, that takes a ref or a `namespace` option throws `ValidationError` for one. The library keeps the due\n * index there (one pointer row per expiring segment), and every fleet-wide scan skips those rows as bookkeeping, so a\n * segment in such a namespace would be invisible to an erasure, a consistency check, an export and a retention sweep.\n * A driver takes the prefix, since the due index's own rows go through it. Only that exact prefix is reserved:\n * `cbm.dueX` and `cbmdue.eu` are ordinary namespaces, and a segment name is never restricted.\n *\n * **A key other than `segment` and `namespace` throws `ValidationError`**, in every call of the store and of the free\n * functions behind it that takes a ref, and at a driver port (which also takes a `generation`, a `chunkKey` and a\n * registry row's own fields): a misspelt `namespace` would otherwise address the segment of that name in the default\n * namespace. A `segments()` row is the one exception at the store: its `currentGen` and `status` are taken and read for\n * nothing. A segment handle, a registry row from `registry.get()` or `list()` (a driver port takes one, a store call does\n * not), and a result row such as a consistency issue, a ledger entry, an export manifest entry or an audit event, is not\n * a ref at the store: pass `{ segment, namespace }`.\n */\nexport interface SegmentRef {\n /** The segment's namespace, or `undefined` for the default one. */\n readonly namespace?: string;\n /** The segment's name. */\n readonly segment: string;\n}\n\n/** One chunk of a segment: the segment, and the chunk's key. */\nexport interface ChunkRef extends SegmentRef {\n /** The chunk's key: an integer from 0 to 65,535, the high 16 bits of the ids the chunk holds. */\n readonly chunkKey: number;\n}\n\n/** Identifies one immutable `.crbm` object \u2014 a single generation of a segment. */\nexport interface GenKey extends SegmentRef {\n /** The generation number of the object. */\n readonly generation: number;\n}\n\n/**\n * A segment's on-disk footprint \u2014 the current generation's Storage object bytes, read cheaply from the `.crbm`\n * footer/index (no payload reads). It is the `sizeBytes` a segment's `stat()` reports, and what bounds the bytes a combine\n * holds for an operand's stream.\n */\nexport interface SegmentSize {\n /** The size of the current generation's object, in bytes. */\n readonly sizeBytes: number;\n}\n\n/**\n * One chunk of a {@link StorageChunkSource.getChunks} stream: the key asked for, its bytes (`null` where the generation\n * holds none), and the version of the generation the bytes were read from, or `null` when the segment has no\n * generation. The version is what {@link StorageChunkSource.currentVersion} reports for that generation, so a caller\n * can key what it keeps by the generation the bytes came from rather than the one it resolved earlier.\n */\nexport interface ChunkRead {\n /** The chunk key that was asked for. */\n readonly key: number;\n /** The chunk's bytes, or `null` where the generation holds none. */\n readonly bytes: Uint8Array | null;\n /** The version of the generation the bytes were read from, or `null` when the segment has no generation. */\n readonly version: string | null;\n}\n\n/** Options of {@link StorageChunkSource.getChunks}. */\nexport interface ReadChunksOptions {\n /**\n * Runs one storage request, and may run it again if it fails. A source passes each request it makes through\n * this, so a caller that retries transient faults repeats the one request that failed, not the ones that landed.\n * Absent, each request runs once.\n */\n readonly retry?: <T>(request: () => Promise<T>) => Promise<T>;\n /**\n * How many range requests the stream holds ahead of its consumer, in flight or landed and not yet taken: a positive\n * integer, 32 by default. It bounds the requests in flight, and the memory the stream holds, at this many times the\n * largest range (1 MiB, 1 MiB + 28 B for one encrypted chunk).\n */\n readonly concurrency?: number;\n /**\n * Open the window 1, 2, 4 \u2026 ranges wide up to `concurrency` instead of at full width, so a reader that stops early\n * has asked for little; a number starts it that wide instead of at 1 (a positive integer), and it doubles from there.\n */\n readonly ramp?: boolean | number;\n /**\n * Called once for every range request the stream sends, when it settles: a request the consumer took, one that was\n * still in flight when the consumer stopped, and one that failed. `bytes` is what the request moved, the gaps between\n * the chunks it carried included (0 when it failed), and `ms` how long it took, retries included (0 when the source\n * has no clock). It is how a caller counts what it is billed for, since several chunks can share a request and\n * a stopped stream leaves some in flight. A throw from it is ignored.\n */\n readonly onRequest?: (request: { readonly bytes: number; readonly ms: number }) => void;\n}\n\n/** Per-chunk read view of the immutable Storage tier (implemented by the `.crbm` reader). */\nexport interface StorageChunkSource {\n /** Read-only bytes for the chunk, or `null` if absent. Callers must not mutate the buffer. */\n getChunk(ref: ChunkRef): Promise<Uint8Array | null>;\n /** The chunk keys the segment's current generation holds, or an empty list when it has none. */\n listChunkKeys(ref: SegmentRef): Promise<number[]>;\n /**\n * Optional: several chunks of one segment as a stream, read **from one generation** with fewer storage requests than\n * one per chunk where the chunks sit near each other in the object. `keys` are chunk keys in ascending order (a key\n * may repeat; any other order is a `ValidationError`). The stream yields one {@link ChunkRead} per position of\n * `keys`, in that order, as the requests that carry them land; a key the generation does not hold yields `null`\n * bytes, as {@link StorageChunkSource.getChunk} answers. Each chunk is checked as a read of it alone is.\n *\n * **Nothing is resolved or read until the first chunk is asked for**, and the source holds at most\n * {@link ReadChunksOptions.concurrency} ranges at a time (in flight, or landed and not yet taken), however many keys\n * there are: a consumer that is slow holds the stream back, and one that stops early (`break`, or `return()`) stops\n * the reads, so the requests it had already started (at most that many) finish and are dropped, and are not retried.\n * A stream that fails raises at once and sends nothing further, and the requests it left in flight finish in the\n * background and never raise. A plain chunk may be a view into a buffer of up to 1 MiB that it shares with its\n * neighbours (and the same view at two positions for a key asked twice), so do not write to it, and copy a chunk to\n * keep it.\n *\n * One stream reads one generation. If that generation is swept, or its object replaced, while the stream runs, a\n * source may re-resolve the segment and continue with the keys not yet yielded from the generation that is current\n * then; each chunk says which version it came from, and each is whole and verified either way. Before it does, it\n * waits for the requests the failed stream left in flight, so a heal never opens a second window beside them: a\n * request that never answers delays a heal, as it would hang a read of one chunk, until the driver's read timeout (if\n * it has one) ends it, and never delays an error. A source that reads a pinned generation never heals.\n *\n * A source that cannot read a range of an object omits this, and a caller reads chunk by chunk; the `.crbm`\n * source, which is what the stores the library ships read through, implements it.\n */\n getChunks?(\n ref: SegmentRef,\n keys: readonly number[],\n options?: ReadChunksOptions,\n ): AsyncIterable<ChunkRead>;\n /**\n * Optional: the current generation's size, cheaply (from the already-parsed `.crbm` index \u2014 no payload reads), or\n * `null` if the segment has no Storage generation.\n */\n sizeOf?(ref: SegmentRef): Promise<SegmentSize | null>;\n /**\n * Optional: the current generation's **per-chunk cardinality** (`chunkKey \u2192 count`), read from the\n * already-parsed `.crbm` index with **no payload reads**, or `null` if the segment has no Storage generation.\n * Powers the free `count()` of a source with no {@link StorageChunkSource.summary} \u2014 the engine sums the index\n * instead of fetching a single chunk. A source with no\n * index (e.g. the in-memory source) omits this, and `count()` falls back to fetching every chunk. A count of a\n * combine also asks for it, and takes its keys to be the ones `listChunkKeys` names for the same generation (an emptied\n * chunk is named by both or by neither), listing again when they differ and refusing a source that keeps disagreeing.\n */\n cardinalities?(ref: SegmentRef): Promise<ReadonlyMap<number, number> | null>;\n /**\n * Optional: the current generation's number, id count and metadata, or `null` if the segment has no Storage\n * generation. The `.crbm` source answers from the registry row's summary when it can use it, which is one\n * registry read and no read of the object, and from the opened generation when it cannot. A source with no\n * summary omits this, and `count()` keeps its other paths.\n */\n summary?(ref: SegmentRef): Promise<GenerationSummary | null>;\n /**\n * Optional: what {@link summary} answers, with the size of the generation's object, both from **one** resolution of\n * the segment, so the size is the size of the generation described; `null` if the segment has no Storage\n * generation. The `.crbm` source answers from the registry row's summary when it can use it, whose fingerprint\n * carries the object's size: one registry read and no read of the object. When it cannot, it opens the generation\n * (one tail read of the object when it is not open already, and a range read for an index longer than the tail) and\n * answers from its footer and index, with no payload read. For a source that omits it, `stat()` asks\n * {@link summary} and {@link sizeOf}, two resolutions that can straddle a publish, and reports no size when\n * there is no `sizeOf` either.\n */\n stat?(ref: SegmentRef): Promise<(GenerationSummary & SegmentSize) | null>;\n /**\n * Optional: the segment's **current generation number** as this source resolves it right now (registry\n * `currentGen`, or the highest storage generation), or `null` if the segment has no Storage generation. The engine\n * keys its chunk cache by this so a generation bump (a load's publish) is observed \u2014 a new generation\n * misses the cache instead of serving a stale decoded chunk, and an erased id can't resurrect from a cached\n * superseded chunk. Cheap: served from the source's own (short-TTL-refreshed) snapshot, **not** a fresh\n * backend read per call. A source that only ever serves one immutable generation may omit this \u2014 the engine\n * then keys the cache without a generation.\n */\n currentGeneration?(ref: SegmentRef): Promise<number | null>;\n /**\n * Optional: forget everything this source has derived from `ref` \u2014 its resolved snapshot, its open reader,\n * and any key material that reader captured \u2014 so the next read resolves from the registry again.\n *\n * The TTL refresh and the generation-keyed chunk cache are both built for **a publish that advances\n * `currentGen`**. Neither covers an event that *destroys* what the cache was derived from: an erasure that\n * deletes the generation holding the bit, a `dropSegment`, a crypto-shred, a retirement. After one of those\n * a source that had already resolved the segment keeps answering from memory \u2014 with no backend read at all,\n * so no storage-side control can close the window \u2014 until its TTL lapses, and with no bound at all if it has\n * no registry, no clock or `cache.genTtlMs: 0`.\n *\n * Callers that destroy or retire a segment must call this. It is synchronous and best-effort: dropping\n * memoized state cannot fail, and a source that memoizes nothing may omit the method entirely.\n */\n invalidate?(ref: SegmentRef): void;\n /**\n * Optional: does this segment **exist as a registered name**, as distinct from resolving to no generation?\n *\n * `currentGeneration` collapses two very different states into `null`: a name nobody ever created, and a\n * segment that exists and is legitimately empty. For a *read* that distinction does not matter \u2014 both answer\n * empty. For an **operand of a combine** it is the difference between a suppression list with nobody on it\n * yet and a suppression list you misspelled, and those must not look alike: the first correctly suppresses\n * nothing, the second silently suppresses nothing while you believe it is working.\n *\n * Consulted **only** when an operand resolved to no chunks at all, so a normal combine never calls it.\n */\n exists?(ref: SegmentRef): Promise<boolean>;\n /**\n * Optional: an opaque token identifying **which bytes** a read of this segment will see right now \u2014\n * the generation *and* the incarnation of the name it belongs to.\n *\n * {@link StorageChunkSource.currentGeneration} is not enough to key a decoded-chunk cache, and the gap is not\n * theoretical: a load numbers its generation from the row's pointer and what is in the bucket, so the number\n * **restarts at 0** once a registry row is purged and the bucket emptied. A retired, re-created name therefore\n * serves different data at the same `currentGen`, and a cache keyed on `(segment, chunk, generation)` hands back\n * the previous incarnation's ids \u2014 an erased id reappearing, with no read to intercept.\n *\n * Note that putting the incarnation in the *object key* would not fix this: the new incarnation still starts\n * at generation 0, so the cache key collides either way. The identity has to reach the cache.\n *\n * Within one incarnation a number can be taken again once its object is deleted, so two objects must never share\n * a version either, however long after its pointer read a source opens the object: the `.crbm` source's version\n * ends with the fingerprint of the object it opened.\n *\n * Returns `null` when the segment resolves to no generation. A source that only ever serves one immutable\n * generation may omit this, and the engine falls back to the generation alone.\n */\n currentVersion?(ref: SegmentRef): Promise<string | null>;\n}\n\n/**\n * What a source that reads pinned generations also offers the engine, apart from {@link StorageChunkSource}: a lookup of\n * the object a pin holds. Not part of the port a source implements; the engine asks for it when it is there.\n */\nexport interface HeldObjectLookup {\n /**\n * Resolves when the segment is not pinned here, or when the object its pin holds is still under its key; rejects with\n * the pin's `NotFoundError` when it is gone or is another object, and with the fault itself when the footer cannot be\n * read or is not a generation object's (a transient fault is for the caller's retries). One footer read for a pinned\n * segment, none for any other.\n */\n verifyPinned(ref: SegmentRef): Promise<void>;\n}\n\n/** Capabilities a Storage driver advertises; validated at wiring time, fail-fast. */\nexport interface StorageCaps {\n /** REQUIRED \u2014 the format relies on byte-range reads. */\n readonly rangeRead: true;\n /** Largest single object the backend accepts (informs single-object-vs-shard \u2014 future). */\n readonly maxObjectBytes: number;\n /** Optional: enables the pure-object `LATEST`-pointer registry variant (S3 conditional put). */\n readonly conditionalPut?: boolean;\n /**\n * Optional: `true` when `delete` applies {@link StorageDeleteOptions.ifVersion}. The driver then removes an object\n * only while it is still the one that version names, by a check the backend applies in the same step as the removal\n * (a precondition on the request, or a check and a removal with nothing between them), refuses another object under\n * the key with {@link WriteConflictError}, and reports a `version` on every {@link IStorageDriver.getTail} of an\n * object. `false` or absent: `delete` ignores `ifVersion` and removes whatever is under the key, and a caller that\n * decided to delete one object can remove another stored under the key since.\n *\n * A driver that learns this from its client may report `false` until its first delete given `ifVersion`; what the\n * delete does is what it states. The S3 driver does: it reads where the client sends its requests, and whether the\n * SDK sends the header, on its first such delete, and reports `false` for good when that cannot be found out.\n */\n readonly conditionalDelete?: boolean;\n}\n\n/** What {@link IStorageDriver.getTail} read. */\nexport interface TailRead {\n /** The last `min(maxBytes, size)` bytes of the object. */\n readonly bytes: Uint8Array;\n /** The object's true total size, not the number of bytes returned. */\n readonly size: number;\n /**\n * Optional: which object the read saw, as the backend names it (an S3 or Azure Blob ETag, a GCS object generation),\n * taken from the response that carried `bytes`, or from the metadata read when no bytes were asked for. Opaque, and\n * compared by equality only, by the driver that reported it. It names the object, not the key: two objects stored\n * one after the other under one key carry different versions, except where the backend's version is computed from\n * the bytes (an S3 ETag of an object stored without SSE-KMS or SSE-C is), where two objects with the same bytes, each\n * stored whole in one request, or each in parts of the same sizes, share one. A driver that reports\n * `conditionalDelete: true` reports it on every read; another may omit it.\n */\n readonly version?: string;\n}\n\n/** Options of {@link IStorageDriver.delete}. */\nexport interface StorageDeleteOptions {\n /**\n * Delete the object only while it is the one this version names: the `version` a {@link IStorageDriver.getTail} of\n * it reported. Pass the one read when the decision to delete was made, never one read after it, or the condition\n * names whatever is under the key by then. Applied only by a driver that reports\n * {@link StorageCaps.conditionalDelete}; ignored by any other, and absent, the delete is unconditional.\n */\n readonly ifVersion?: string;\n}\n\n/**\n * Immutable object storage for `.crbm` generations. A \"dumb byte mover\": it\n * understands neither roaring nor the `.crbm` layout, only opaque bytes addressed by a {@link GenKey}.\n * The core never reuses a key, so puts are write-once.\n *\n * **What a driver must do** \u2014 callers rely on each of these, and the storage conformance suite holds every\n * shipped driver to them:\n *\n * - **`putImmutable` is write-once and reports a collision as {@link WriteConflictError}.** It never overwrites a\n * stored object, two concurrent writes of one key included: exactly one lands. `load` reads that error as a lost\n * race for the generation number (`superseded`), so a driver that threw anything else for an existing key would\n * surface as a failed load. A write whose writer fails stores nothing, and the key can be written after.\n * - **Keys keep every name apart.** One segment in two namespaces, two names an encoding could fold into one (`a/b`\n * and `a_b`), and a name that extends another (`s` and `s.1`) are separate objects, each listed and deleted alone;\n * generations are listed and deleted by number, never by a prefix of one.\n * - **A bucket or container that does not exist is not a missing object**: it fails with an error that is neither\n * {@link NotFoundError}, which would read as an empty segment, nor a {@link TransientError}, which a retry cannot fix.\n * - **A missing object makes `getRange` and `getTail` throw {@link NotFoundError}** \u2014 never an empty or short\n * result. Heal-forward (a read whose generation a sweep collected re-resolves), the erasure's holder probe and\n * its verify of the rewrite, and a pin's replaced-object check all branch on that one error. (A zero-length\n * `getRange` may answer empty without reaching the backend, so it proves neither that the object exists nor\n * that the offset lies inside it: the cloud drivers answer it empty, the memory and local-filesystem drivers\n * throw for a missing object or an offset past the end.)\n * - **A deleted object is missing to the next read**: once `delete(key)` has resolved, `getTail` and a non-empty `getRange`\n * of that key throw {@link NotFoundError} (a zero-length `getRange` is the exemption above), with no stale answer from a\n * cache or a replica. A rollback reads its target's footer once\n * after moving the pointer, in place of listing the bucket, and takes a read that succeeds as proof that the object is\n * there.\n * - **An out-of-range read throws {@link ValidationError}**: a range that runs past the end of the object, or a\n * negative or non-integer offset or length. Never a clamped, short or adjacent read. A pin whose object\n * was purged and loaded again as a smaller one asks for a range past its end, and this error is what sends it\n * to check that the object is still the one it pinned.\n * - **`getTail` reports the object's true total size**, not the number of bytes it returned, and, where the driver has\n * one, the object's `version` ({@link TailRead.version}) from the same response as the bytes. Its length is a safe\n * integer, zero or less for an empty tail; any other length throws {@link ValidationError} before anything is read.\n * - **`delete` is idempotent.** Deleting an absent key is a no-op, not an error: collection passes race each\n * other and retry. That holds with `ifVersion` too: an absent object is a no-op whatever version is given.\n * - **`delete` with `ifVersion` does what {@link StorageCaps.conditionalDelete} says.** A driver that reports `true`\n * removes the object only while it is the one the version names, by a check the backend applies in the same step as\n * the removal (S3 `If-Match`, GCS `ifGenerationMatch`, Azure Blob `ifMatch`; in memory, the check and the removal with\n * no await between them), and for another object under the key throws {@link WriteConflictError} and leaves it. A\n * check made by reading the object first and deleting after is not one step, and does not qualify. Where the service\n * answers a failed precondition for a key with no object, the driver looks again before it reports a conflict, so an\n * absent object stays a no-op. A driver that reports `false`, or omits it, ignores `ifVersion` and deletes whatever is\n * under the key. A number can be taken again once its object is deleted, so this is what keeps a delete decided from\n * one read, and delayed, from removing an object stored under the number since: the erasure's delete of a holder\n * above the pointer passes the version it read when it searched that object, and a refused load's delete of an\n * object whose footer, read once, matched what it wrote passes the version of that read.\n * - **A driver that wraps another forwards `ifVersion` and the `version` of a tail read, or reports\n * `conditionalDelete: false`.** A wrapper that hands `delete` the key alone, and reports the inner driver's\n * capability, makes every conditional delete through it unconditional without a word.\n * - **A conditional delete may be sent again**, by the backend client's retry, after a lost response: a copy that meets\n * its own landed delete finds the object absent, which is its success, and one that meets an object stored since is\n * refused. It can remove nothing the first copy could not.\n * - **`list` is strongly consistent, read-after-delete.** Once `delete` has resolved, `list` no longer yields\n * that generation, and once `putImmutable` has resolved it does. The erasure's re-check for a generation still\n * holding the id, `dropSegment`'s `generationsRemaining`, the retention sweep's check that a tombstone's storage\n * is gone, and rollback's post-move check prove a deletion or a presence by listing, so a listing that lags\n * reports an erasure as incomplete or a stale object as gone.\n * - **`list` yields every generation, however many pages the service splits it into.** One that stops after its\n * first page drops generations from every collection and every check above.\n * - **Never replay a conditional write without telling the replay apart.** A `putImmutable` that lands and then\n * loses its response, sent again, finds its own object and would report a collision. Either send each write\n * once, with the backend client's retry off for that request, or recognise your own write when the\n * precondition fails by reading an id you stored with it back, and treat a match as success. The first is\n * what the registry writes of every shipped driver do; the second is what the Azure Blob driver and the\n * resumable GCS upload do, and what the S3 driver and the single-request GCS upload do when they send an object\n * again after a throttle, which is the one replay a driver may make on purpose.\n * - **Raise a transient fault as {@link TransientError}** (throttling, a 5xx, a dropped connection), so the read\n * retry can ride it out and a write's caller can tell it from a deterministic failure.\n */\nexport interface IStorageDriver {\n /** What this driver can do. Range reads and `maxObjectBytes` are required; the other capabilities are optional. */\n capabilities(): StorageCaps;\n /**\n * Stream a new immutable generation. The driver opens a destination, hands `write` a {@link BlobSink},\n * then atomically commits (and computes the content hash). Throws {@link WriteConflictError} if the key\n * already exists (write-once). Call `write` once: the object committed is the bytes that one call wrote, because\n * the caller records the write identity of that call's object (its footer) for every later proof; a driver that\n * runs `write` again after a failed attempt must commit only the last run's bytes.\n *\n * What a second run of `write` does depends on what is written. A load of ids, of a bitmap or of a combine's chunks\n * holds its chunks in memory, so each run writes the whole object again, under a write identity of its own, and the\n * load records the run that was committed. A write that streams its chunks, a load with `sorted: true` and an\n * erasure's rewrite, reads them once, so its second run throws {@link IntegrityError} before writing a byte: commit\n * nothing then, and the call throws that error, with the first run's error as its `cause`.\n */\n putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }>;\n /**\n * Range read; the caller bounds-checks. Out-of-range throws {@link ValidationError}, never a short/adjacent\n * read, and a missing object throws {@link NotFoundError}.\n */\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;\n /**\n * Speculative tail read: the last `min(maxBytes, size)` bytes + the object's **true total size**, and its `version`\n * where the driver has one ({@link TailRead}). `maxBytes` must be a safe integer: zero or less answers an empty tail\n * with the size, and one past the size the whole object. Any other `maxBytes` (`NaN`, a fraction, a negative one\n * included, an infinity of either sign, a whole number past the safe range (2^53 or more, or -2^53 or less)) throws\n * {@link ValidationError} before anything is read. A missing object throws {@link NotFoundError}.\n */\n getTail(key: GenKey, maxBytes: number): Promise<TailRead>;\n /**\n * Idempotent: deleting an absent key is a no-op, not an error. With `options.ifVersion`, on a driver that reports\n * {@link StorageCaps.conditionalDelete}, the object is removed only while it is the one that version names, and\n * another object under the key is left and the delete throws {@link WriteConflictError}; any other driver ignores it.\n */\n delete(key: GenKey, options?: StorageDeleteOptions): Promise<void>;\n /**\n * Enumerate the generations present for a segment (orphan sweep / latest-gen resolution). Strongly\n * consistent, read-after-delete and read-after-put.\n */\n list(ref: SegmentRef): AsyncIterable<GenKey>;\n}\n\n/**\n * Lifecycle status of a segment. `active` is the steady state; `destroyed` is the tombstone left by a crypto-shred, a\n * cleartext destroy or a drop (the row is kept for audit but the segment is logically gone: no read resolves a\n * generation through it).\n */\nexport type RegistryStatus = 'active' | 'destroyed';\n\n/**\n * Free-form, JSON-serializable governance metadata \u2014 a **plain object** (both registry boundaries reject `null`,\n * an array or a primitive, because a reader that tests `'key' in meta` would throw an untyped `TypeError`).\n *\n * `retention` has one **reserved key with defined semantics**: `expiresAt`, an absolute epoch-ms after which a\n * retention sweep may retire the segment \u2014 written by `setSegmentRetention`, parsed by `readRetentionPolicy`. Any\n * other key is yours (a legal hold, a note, an owner) and is preserved across policy writes. `residency` is still\n * shape-later: stored and round-tripped, no semantics attached.\n */\nexport type GovernanceMeta = Record<string, unknown>;\n\n/**\n * A cached description of one generation, carried on the registry row: how many ids it holds, the metadata it was\n * loaded with, and the fingerprint of its object (its size and footer checksum). The generation's `.crbm` object stays\n * the truth; this is a copy, written by the same write that moves the pointer, and it names the generation it describes\n * so a copy left behind by a writer that did not carry it can never be taken for another generation's. The fingerprint\n * names the object too: a reader checks every object it opens for the row's generation against it, and refuses one\n * that is another object under that number.\n *\n * Two shapes. On a cleartext segment the values are in the clear. On an encrypted segment (a row with\n * `wrappedDeks`) they are sealed under the segment's data key, as the generation's index is, so the row reveals\n * neither the count nor the metadata. A shipped registry refuses a write whose summary disagrees with the row's\n * keys. It still reads a stored row that disagrees, so that one such row cannot stop every listing: a reader must not\n * use that row's summary.\n */\nexport type RegistrySummary = ClearRegistrySummary | SealedRegistrySummary;\n\n/**\n * A generation's metadata: string keys, string or finite-number values, no nesting, at most 1 KiB as canonical JSON.\n * The rules are in `core/metadata.ts`.\n */\nexport type GenerationMetadata = Readonly<Record<string, string | number>>;\n\n/** What a generation is, as one read answers it: its number, its id count and the metadata it was written with. */\nexport interface GenerationSummary {\n /** The generation's number. */\n readonly generation: number;\n /** The number of ids the generation holds. */\n readonly cardinality: number;\n /** Absent when the generation has none. */\n readonly metadata?: GenerationMetadata;\n}\n\n/** {@link RegistrySummary} on a cleartext segment. */\nexport interface ClearRegistrySummary {\n /** The generation this describes. A non-negative safe integer. */\n readonly generation: number;\n /** How many ids the generation holds: an integer from 0 to 2^32. */\n readonly cardinality: number;\n /**\n * The fingerprint of the generation's object, `<size>:<footer checksum>` in decimal, as a pin's `pinnedAt.fingerprint`\n * spells it: the object's size in bytes, which `stat()` reports, and the CRC32C its footer stores.\n */\n readonly fingerprint: string;\n /**\n * The bytes from the end of the last chunk payload to the end of the object: the extension block, if any, the index and\n * the footer. A cold open reads this many bytes from the object's end to open it in one request. An integer from 104,\n * the footer's size, to the object's size less its 8-byte preamble, and at most 8,392,820.\n */\n readonly tailBytes: number;\n /** The generation's metadata, when it has any. Never the empty object. */\n readonly metadata?: GenerationMetadata;\n}\n\n/** {@link RegistrySummary} on an encrypted segment. */\nexport interface SealedRegistrySummary {\n /** The generation this describes. A non-negative safe integer. */\n readonly generation: number;\n /**\n * Base64 of `nonce(12) \u2016 ciphertext \u2016 tag(16)`, sealing the cardinality as a little-endian u64, the object's size as a\n * little-endian u64 and its footer checksum as a little-endian u32 (its fingerprint), its `tailBytes` as a\n * little-endian u32, then the metadata's canonical JSON, if any. The numbers are fixed-width, so the length reveals only\n * the metadata's size.\n */\n readonly sealed: string;\n}\n\n/**\n * A generation a row knows it published: its number, and the checksum its object's footer stores. A rollback moves only\n * onto a generation the row knows, and an object whose footer carries another checksum is another object under that\n * number. The footer's checksum covers the index's checksum, which covers each chunk's, so it commits to the object's ids\n * and shape; for a cleartext object it does not cover the extension block's bytes.\n */\nexport interface KnownGeneration {\n /** A non-negative safe integer. */\n readonly generation: number;\n /** The object's footer CRC32C (the second half of its fingerprint `<size>:<crc>`), an integer from 0 to 2^32 - 1. */\n readonly footerCrc: number;\n}\n\n/**\n * One lease on a generation. It names no fingerprint: a collector spares a generation by number and cannot compare an\n * object without reading it, and a purge and re-create drops the whole list with the row. A pin's own fingerprint,\n * which its reads check, stops a number retaken after a rollback being read as the leased object; the entry then spares a\n * different object from collection until it ends, at most the longest lease.\n */\nexport interface LeaseEntry {\n /** 16 lowercase hex digits drawn once per pin call; names the holder, so a retried write is idempotent. */\n readonly holder: string;\n /** The generation held. */\n readonly generation: number;\n /** Epoch-ms the lease runs to on the holder's clock; a collector holds it for the skew margin longer. */\n readonly until: number;\n}\n\n/**\n * One registry row \u2014 the authoritative per-segment record. Exactly one per segment.\n */\nexport interface RegistryRecord extends SegmentRef {\n /**\n * **The** authoritative LATEST pointer: which immutable Storage generation is current \u2014 or **`null` for a segment\n * that has no Storage generation yet.**\n *\n * `null` is not \"unknown\", it is a positive statement: *this segment exists and has no Storage data.* It is what\n * lets a segment have a registry row **before its first load** \u2014 `setSegmentRetention` mints one so a policy\n * can be recorded ahead of the data, and so the segment is reachable by `registry.list()` and therefore by\n * retention sweeps, `checkConsistency` and every other fleet-wide operation. The alternative \u2014 a row with\n * `currentGen: 0` and no object behind it \u2014 is the forbidden `missing-storage-generation` state, which fails per\n * read with `NotFoundError`. Generation resolution maps `null` onto the same path a segment with **no row**\n * takes: every read answers empty, and the first publish advances the pointer.\n */\n readonly currentGen: number | null;\n /**\n * Per-segment data-key (DEK) wrappings for encryption-at-rest: the DEK envelope-wrapped under one or more KEKs\n * (active + optional recovery). Reading unwraps with any held KEK; **crypto-shred deletes this whole list** from\n * the current row, so the segment's at-rest bytes are unrecoverable once no retained copy of the row (a noncurrent\n * version, a backup) still holds it, or every KEK that wrapped it is destroyed. Absent \u21D2 the segment is cleartext.\n */\n readonly wrappedDeks?: readonly WrappedDek[];\n /**\n * Optional **external** key reference (reserved) \u2014 e.g. a KMS key ARN for a future KMS keystore adapter that\n * keeps wrapped material in the KMS rather than in-band {@link wrappedDeks}. Unused by the in-process BYOK\n * keystore. Clearable on crypto-shred.\n */\n readonly keyId?: string;\n /**\n * `'active'`, or `'destroyed'` for the tombstone of a segment that was crypto-shredded, destroyed in the clear or\n * dropped.\n */\n readonly status: RegistryStatus;\n /**\n * Governance policy. `retention.expiresAt` drives the retention sweep (see {@link GovernanceMeta}); `residency`\n * is stored and round-tripped with no semantics yet. Both must be plain objects, and both must survive a\n * `list()` projection \u2014 a fleet sweep reads the policy from the enumeration rather than per-segment.\n */\n readonly retention?: GovernanceMeta;\n /** Residency metadata, a plain object. It is stored and returned as given; nothing reads it yet. */\n readonly residency?: GovernanceMeta;\n /**\n * A cached description of the current generation (see {@link RegistrySummary}). Optional: a row without one is\n * correct, and a reader then opens the generation instead. Trusted only for the generation it names.\n */\n readonly summary?: RegistrySummary;\n /**\n * The generations this row knows and has not decided to delete, the current one included, with each object's footer\n * checksum: the ones it made current, in the order they were made current, oldest first and the current one last, and,\n * when a publish over a row with no usable ledger seeds one, the ones a count by `keep` keeps in the bucket, which can\n * include an object no load published (an orphan or a stray). An entry says the library knows the generation and its\n * footer checksum, not that a load published it. A generation appears once,\n * at its most recent time current (a rollback onto it moves it to the end). The entries before the last are the kept\n * window, the generations a live lease holds, and what a rollback left; those numbered above `currentGen` are what a\n * rollback left. In the clear on every\n * row, an encrypted one included: a footer checksum of an encrypted object covers a random nonce and says nothing about\n * its count, size or content, but the entries above the pointer show anyone who reads the registry that a rollback\n * happened, and from which generation.\n *\n * Optional: absent means the row does not know, and a load then lists the bucket to collect. A shipped registry stores\n * the list in the order given, at most 192 entries written and 384 read, and refuses a list that repeats a\n * generation, one whose last entry is not the row's `currentGen`, and one whose current entry's checksum disagrees with\n * a clear `summary`'s fingerprint. A stored list that disagrees with its row is read and not used. A patch that moves\n * `currentGen` without naming it drops it.\n */\n readonly knownGens?: readonly KnownGeneration[];\n /**\n * The leases on this segment's generations: each keeps one generation out of a load's collection until it ends.\n * Optional; absent means none. Unlike {@link knownGens} it does not follow the pointer: a patch that moves\n * `currentGen` leaves it as it was, and only a patch that names it, or the row going away, changes it. Entries\n * past their end are ignored by every collector and pruned by the next write that names the list. A row's identity\n * is its token, so a purged and re-created segment starts with none.\n */\n readonly leases?: readonly LeaseEntry[];\n /** Epoch-ms of creation / last mutation (from the driver's injected clock). */\n readonly createdAt: number;\n /** Epoch-ms of the row's last write, from the driver's clock. */\n readonly updatedAt: number;\n /**\n * Opaque OCC token \u2014 compare-by-equality, ABA-safe. A shipped registry gives no two writes under one name the same\n * token: not two writes of this row, not a write of an earlier row under the name, and not a write after this row is\n * restored from a backup. It holds with overwhelming probability rather than by construction, since the token carries random parts: a\n * 128-bit incarnation id drawn when the row is created, and a 64-bit part drawn for each write. Two incarnations of one\n * name meet with probability 2^-128 for any pair (about n^2 / 2^129 among n of them), and two writes at one counter,\n * after a restore, with probability 2^-64.\n */\n readonly token: Token;\n /**\n * The token of the most recent write that named a field a read resolves through: the row's create, or a compare-and-swap\n * whose patch named `currentGen`, `status`, `wrappedDeks`, `keyId` or `summary` (the resolved fields), at any value,\n * the one the field already had included. A write that names only `leases`, `retention`, `residency` or `knownGens`\n * leaves it. The registry sets it; a caller never does. Compared by equality only, and never reused under one name,\n * since a token is not: a reader keys what it caches on a generation with it, so a lease or a policy write leaves a\n * warm reader's cache standing, and a write that changes the resolution never does.\n */\n readonly pointerId: Token;\n}\n\n/**\n * The caller-settable fields at {@link IRegistryDriver.create} (audit, `token` and `pointerId` are driver-managed: the new\n * row's `pointerId` is the token the create returns).\n */\nexport interface NewRegistryRecord {\n /** `null` \u21D2 the segment has no Storage generation yet \u2014 see {@link RegistryRecord.currentGen}. */\n readonly currentGen: number | null;\n /** The segment's wrapped data keys, which make it an encrypted segment. Absent for a cleartext one. */\n readonly wrappedDeks?: readonly WrappedDek[];\n /** An external key reference. Reserved: the in-process keystore does not use it. */\n readonly keyId?: string;\n /** Defaults to `'active'`. */\n readonly status?: RegistryStatus;\n /** The retention policy, a plain object; its `expiresAt` is what the retention sweep reads. */\n readonly retention?: GovernanceMeta;\n /** Residency metadata, a plain object. It is stored and returned as given; nothing reads it yet. */\n readonly residency?: GovernanceMeta;\n /** Must name `currentGen` when given. */\n readonly summary?: RegistrySummary;\n /** In the order made current, the last entry the new row's `currentGen`; see {@link RegistryRecord.knownGens}. */\n readonly knownGens?: readonly KnownGeneration[];\n}\n\n/**\n * Fields a {@link IRegistryDriver.compareAndSwap} may mutate (identity, audit, `token` and `pointerId` are\n * off-limits).\n *\n * Presence-based: a field the patch does not mention is left as it was. `summary` is the one exception, because it\n * describes the current generation: a patch that moves `currentGen` and does not mention `summary` drops the old\n * one rather than keep a description of another generation. A `summary` the patch gives must name the\n * `currentGen` the row will have. `knownGens` follows the pointer the same way: a patch that moves `currentGen` and does\n * not mention it drops it, and one that gives it must end with the `currentGen` the row will have.\n * \"Moves\" means changes value: a patch that names `currentGen` at the value it has keeps both.\n *\n * A patch that names a resolved field (`currentGen`, `status`, `wrappedDeks`, `keyId`, `summary`), by presence and at any\n * value, sets the row's {@link RegistryRecord.pointerId} to the token the write returns; any other patch leaves it.\n */\nexport type RegistryPatch = Partial<\n Pick<\n RegistryRecord,\n | 'currentGen'\n | 'wrappedDeks'\n | 'keyId'\n | 'status'\n | 'retention'\n | 'residency'\n | 'summary'\n | 'knownGens'\n | 'leases'\n >\n>;\n\n/**\n * What a caller passes {@link IRegistryDriver.create} or {@link IRegistryDriver.compareAndSwap} besides the write itself.\n */\nexport interface RegistryWriteOptions {\n /**\n * The row the caller read, and is writing against: the record a {@link IRegistryDriver.get} of this registry returned\n * to it, or `null` when that read found no row. A driver that would read the row to learn the version its conditional\n * write is fenced on can use the one it observed then, and send the write at once.\n *\n * It is a hint, and never the fence: the write is still conditioned on the store's own version of the row, so a row\n * that has changed since makes it fail as a lost race does, with {@link WriteConflictError}. A driver reads the row\n * as it does without a hint when it does not recognise the record (one it did not return, or one that is not of\n * this row), or when `held` and the `expected` token of a `compareAndSwap` disagree. A write that gets no answer is\n * settled by reading the row, never by this record. A driver that ignores the option reads the row.\n */\n readonly held?: RegistryRecord | null;\n /**\n * Called with the token this write carries, before the write is sent. A write sent again with a new token reports\n * it; one that repeats the same body repeats the token already reported. The token is the one the write records:\n * when the write lands, the row's {@link RegistryRecord.token} is it, and so is its {@link RegistryRecord.pointerId}\n * when the write names a resolved field. A write that does not land leaves no row carrying it. A call refused before\n * it has a token to send, on a conflict its own read finds, reports none.\n *\n * A publish relies on the report coming first, both ways. A write that faults after its report may have landed, and\n * is settled by reading the row. A `TransientError` before any report is taken for a fault before sending, such as\n * the driver's own read of the row: the publish throws it at once, with no read of the row and no fresh write. So\n * nothing that can land is sent before the report, a client's own resend included.\n *\n * The token is unique to that write attempt, also against another writer racing the same version: two writers that\n * send a write against the same row version never carry the same token, so a version counter alone is not enough.\n * Otherwise a loser's write would pass for the winner's.\n *\n * It tells a writer which row writes are its own, whatever became of its request: a write that failed, or got no\n * answer, may still have landed, and the row's `pointerId` names its writer when no later write has renewed it: it is\n * then one of the tokens the writer was told. Only a registry that reports {@link IRegistryDriver.reportsWriteTokens}\n * calls it; one that does not ignores it, and a writer then settles such a write by reading the object it published.\n * A registry that wraps or extends another and overrides `create` or `compareAndSwap` passes this option through to\n * the write it forwards, or sets the flag to `false`.\n */\n readonly onToken?: (token: Token) => void;\n}\n\n/** Capabilities a registry driver advertises; validated fail-fast at wiring time. */\nexport interface RegCaps {\n /** REQUIRED \u2014 `currentGen` feeds read correctness + the publish CAS, so reads must be strongly consistent. */\n readonly strongRead: true;\n /**\n * `false` when this registry cannot write a row in this runtime, though it reads: a shipped registry draws random\n * bytes for every token it issues, and on a runtime with no Web Crypto it has none to draw. A write path that\n * writes an object before its row (a load, an erasure rewrite) checks it first and refuses with `UnsupportedError`\n * before it writes anything, rather than leave an object no row names. Absent means the registry can write.\n */\n readonly canWrite?: false;\n /**\n * `true` when this registry's `delete` removes a row from its backend for good, so that no later `list` reads it, and\n * removes it only while it is still the exact version the delete read: by a delete the backend applies under a\n * precondition (an S3 or Azure Blob ETag, a GCS object generation), or under a lock no other writer of the backend\n * can take.\n *\n * `false` or absent: every `delete` leaves a tombstone, which every later full `list` still reads. A shipped registry\n * says which it is.\n */\n readonly conditionalDelete?: boolean;\n}\n\n/**\n * Refuse, with `UnsupportedError`, a write that would write an object before its row when the registry reports it\n * cannot write a row (see {@link RegCaps.canWrite}). Called before the write's first request.\n */\nexport function assertRegistryCanWrite(registry: IRegistryDriver, what: string): void {\n if (registry.capabilities().canWrite === false) {\n throw new UnsupportedError(\n `${what}: the registry reports it cannot write a row in this runtime (capabilities().canWrite is false), ` +\n 'so nothing is written',\n );\n }\n}\n\n/**\n * Brand for {@link StorageBackend}.\n *\n * `Symbol.for` rather than a class check, for the same reason the error brands are: a class object is only\n * shared while one copy of core is loaded, so a backend built from one copy and checked by another \u2014 after a\n * version skew, or behind a duplicating bundler \u2014 would fail an `instanceof`. A registered symbol is\n * identity-stable across all of them, and across realms.\n *\n * A brand string is part of that identity contract, so once a release carries one it never changes: a changed\n * string would stop matching the copies already installed.\n */\nconst STORAGE_BACKEND_BRAND: unique symbol = Symbol.for('cloudbitmaps.storage-backend');\n\n/**\n * Where a store keeps everything: the generations, and the pointer saying which one is current.\n *\n * **Branded on purpose.** The two fields alone are not enough to qualify, and that is the whole point. This\n * same two fields are the heart of the deps core's standalone functions take, so without the brand any `{ storage, registry }`\n * object literal would satisfy it \u2014 including one assembling halves from two *unrelated* stores, which the store\n * accepted and then answered **empty** for a segment that holds data, because it read a pointer from a place\n * nothing had ever been written. That is the exact silent-empty failure one-class-per-backend exists to\n * remove, and it was reachable in five lines.\n *\n * So a backend comes from `MemoryStorage`, `LocalFsStorage`, `S3Storage`, `GcsStorage` or\n * `AzureBlobStorage` \u2014 each deriving both halves from one bucket and one prefix. A driver author composing halves\n * of their own says so on purpose, with {@link brandAsBackend}. The halves stay readable as `.storage` /\n * `.registry`, because the free functions genuinely need them.\n *\n * **What this stops is the accident, not a determined caller.** The brand is a registered symbol, so it can\n * be written by hand; nothing here is a security boundary. It stops the two spellings people reach for\n * without deciding to \u2014 an object literal, and a spread of a real backend.\n */\nexport interface StorageBackend {\n /** Cross-bundle brand. Set by the backend classes; not part of the public surface. */\n readonly [STORAGE_BACKEND_BRAND]: true;\n /** Where the immutable `.crbm` generations live. */\n readonly storage: IStorageDriver;\n /** Where the `currentGen` pointer, the discovery index and the wrapped DEKs live. */\n readonly registry: IRegistryDriver;\n /**\n * Optional. A store with a metrics sink calls this once, as it is built, with that sink (already safe to call: it\n * never throws back). A backend that has something to say about its own setup, such as a pool it can read and finds\n * small, keeps the sink and emits an `advisory` event to it later. A backend without it is simply never told. One backend\n * may be handed to several stores, and is called once by each, with each store's own sink. It must not throw: an\n * exception propagates from the store's constructor, so a backend's bug fails fast rather than going unseen.\n */\n attachMetrics?(sink: IMetricsSink): void;\n /**\n * Optional. Reads the setup the backend cannot change but can be broken by, and says whether it will delete or\n * archive what the store keeps: today, the bucket's lifecycle rules over the generation objects and the\n * `<prefix>registry/` rows. It is meant for a check run by hand or at deploy time, not for the read or write path, and\n * costs one request, plus the SDK's own retries. It never rejects: a check that could not be made resolves to `unchecked` with the\n * reason in `detail`. A backend without it, a third-party one or a {@link brandAsBackend} wrapper that does not\n * forward it, offers no lifecycle check, and `store.preflight()` reads that as `unchecked`.\n *\n * The cloud rules stay in the driver. A `detail` is for a person, carries no credential, and never changes what a\n * caller does: act on `status`.\n */\n checkLifecycle?(): Promise<LifecycleVerdict>;\n}\n\n/**\n * What {@link StorageBackend.checkLifecycle} found.\n *\n * - `ok`: no rule that could delete or archive the store's objects. `detail` may still carry advice, such as a missing\n * rule that cleans up abandoned multipart uploads, which is never a `problem` by itself.\n * - `problem`: a rule that deletes or archives the store's current objects, or one that cannot be told apart from it.\n * Where a rule is unclear, the check reports a `problem`: a condition it does not interpret, or a value it does not\n * recognise (a storage class, an action).\n * - `unchecked`: the check could not be made (no permission to read the configuration, an error, or a backend whose\n * rules are out of the data plane's reach). `detail` says what to grant or how to check by hand.\n */\nexport interface LifecycleVerdict {\n /**\n * `'ok'` when no rule would delete or archive the store's objects, `'problem'` when one would or may, `'unchecked'`\n * when the check could not be made.\n */\n readonly status: 'ok' | 'problem' | 'unchecked';\n /** A sentence or two for a person. Never a credential. */\n readonly detail: string;\n}\n\n/**\n * The brand key, for the type-only `declare` field a backend class carries.\n *\n * Exported from `@cloudbitmaps/core/driver-kit` and part of the driver contract: a third-party storage\n * package needs it to declare the field that {@link brandAsBackend} then stamps at runtime.\n */\nexport const STORAGE_BACKEND: typeof STORAGE_BACKEND_BRAND = STORAGE_BACKEND_BRAND;\n\n/**\n * Stamp the brand on a backend, **non-enumerably**, after checking both halves are drivers. Returns `target`.\n *\n * This is the driver author's door, and it works on a backend class (`brandAsBackend(this)` as the last line of\n * its constructor) and on a plain `{ storage, registry }` object alike \u2014 the latter is how a backend of your\n * own halves is built: a driver wrapped for auditing, metrics, tenant scoping or client-side encryption, or\n * paired with a registry in a database you already run. An application does not need it: it gets both halves\n * from one backend class, which derives them from one bucket and one prefix so they cannot disagree.\n *\n * It throws {@link ValidationError} when `storage` has no `putImmutable` or `registry` has no `compareAndSwap`,\n * so a half that is not a driver is refused here rather than at its first write, and when `target` is frozen or\n * non-extensible, since the brand is stamped on it in place.\n *\n * It cannot check that the halves agree: `IStorageDriver` and `IRegistryDriver` do not expose a location, so\n * nothing here can compare one. Branding two unrelated halves is you taking that on \u2014 the plain\n * `{ storage, registry }` literal is refused by the store precisely because it let the two halves come from\n * unrelated places by accident, and answer **empty** rather than fail.\n *\n * Non-enumerable is load-bearing, not tidiness. A class field (`readonly [BRAND] = true`) emits an\n * *enumerable* own property, and spread and `Object.assign` copy exactly those \u2014 so\n * `{ ...backend, registry: other.registry }` carried the brand and was accepted, reproducing the silent-empty\n * bug the brand exists to close. This does not make the brand unforgeable \u2014 the symbol is registered, so anyone\n * who wants it can write `Symbol.for('cloudbitmaps.storage-backend')`. That is deliberate effort equivalent to\n * calling this function, and it is not what the check is for. The check is for the accident.\n */\nexport function brandAsBackend<T extends { storage: IStorageDriver; registry: IRegistryDriver }>(\n target: T,\n): T & StorageBackend {\n if (target === null || typeof target !== 'object') {\n throw new ValidationError('brandAsBackend needs `{ storage, registry }`');\n }\n const { storage, registry } = target;\n if (\n storage === null ||\n typeof storage !== 'object' ||\n typeof storage.putImmutable !== 'function'\n ) {\n throw new ValidationError(\n 'brandAsBackend: `storage` must be an IStorageDriver (it has no `putImmutable`)',\n );\n }\n if (\n registry === null ||\n typeof registry !== 'object' ||\n typeof registry.compareAndSwap !== 'function'\n ) {\n throw new ValidationError(\n 'brandAsBackend: `registry` must be an IRegistryDriver (it has no `compareAndSwap`)',\n );\n }\n try {\n Object.defineProperty(target, STORAGE_BACKEND_BRAND, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n } catch {\n // A frozen, sealed or non-extensible object cannot take the brand, and the brand is stamped in place.\n throw new ValidationError(\n 'brandAsBackend: cannot brand a frozen or non-extensible object \u2014 pass a plain object or a class instance',\n );\n }\n return target as T & StorageBackend;\n}\n\n/**\n * Is this a branded backend \u2014 from a backend class or from {@link brandAsBackend}?\n *\n * Checks the brand, not the shape \u2014 see {@link StorageBackend} for why the shape alone is not enough.\n */\nexport function isStorageBackend(value: unknown): value is StorageBackend {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[STORAGE_BACKEND_BRAND] === true\n );\n}\n\n/**\n * Per-segment registry \u2014 the authoritative source of `currentGen`, the discovery index, and the wrapped-DEK\n * holder. One row per segment under OCC: an equality-compared {@link Token} that is never reused, with overwhelming\n * probability (ABA-safe across delete\u2192recreate).\n *\n * **What a driver must do** \u2014 callers rely on each of these, and the registry conformance suite holds every\n * shipped driver to them, except the rule on `unsettledConflict`, which the suite does not test:\n *\n * - **`create` and `compareAndSwap` are atomic conditional writes.** A `create` over a live row, and a\n * `compareAndSwap` whose token is not the stored one, throw {@link WriteConflictError} and change nothing.\n * Two racing writers have exactly one winner.\n * - **A token is not reused, not even across `delete` then `create`**, short of a collision of probability 2^-128 for\n * any two incarnations of one name: a recreated row carries a token no earlier incarnation held, so a stale holder\n * cannot swap into it. The shipped drivers draw a random 128-bit incarnation id into the token of every row they\n * create and a random 64-bit part into the token of every write, beside a counter a tombstone (or a global counter)\n * keeps going; where nothing of the earlier row is left, or the row is restored from a backup to an older counter, the\n * random parts alone keep the tokens apart: with probability 1 - 2^-128 per pair of incarnations, and 1 - 2^-64 per\n * pair of writes at one counter.\n * - **Every row carries its `pointerId`** ({@link RegistryRecord.pointerId}): `create` sets it to the token it returns,\n * a `compareAndSwap` whose patch names a resolved field (`renewsPointer` in `@cloudbitmaps/core/driver-kit`) sets it\n * to the token that write returns, and every other write leaves it. `get` and `list` return it. A caller's write\n * never sets it. A row returned without one fails every read of the segment with {@link UnsupportedError}.\n * - **`delete` is idempotent** without an `expected` token: deleting an absent row is a no-op, not an error.\n * **With `expected` it is fenced**: it lands only while the row still carries that token, and otherwise throws\n * {@link WriteConflictError} and leaves the row.\n * - **Reads are strongly consistent** (`RegCaps.strongRead`), and `list` yields every existing row,\n * `destroyed` tombstones included, with every field (see {@link IRegistryDriver.list}), however many pages the\n * service splits the listing into.\n * - **A bucket or container that does not exist is not an absent row**: a read, a listing and a write fail with an\n * error that is neither {@link NotFoundError} nor a {@link TransientError}, and a read never answers `null`, which would\n * read as a segment with no generation.\n * - **Never replay a conditional write without telling the replay apart.** A `create` or `compareAndSwap`\n * that lands and then loses its response, sent again, finds its own write and would report a conflict.\n * Either send each write once, with the backend client's retry off for that request, or recognise your own\n * write when the precondition fails by reading an id you stored with it back. The shipped registries do\n * one or the other.\n * - **Raise a conflict that may follow your own write's landing with `unsettledConflict`** (from the driver kit). A\n * driver whose client may have sent the write more than once cannot say, after a conflict, that this write did not\n * land first: a row is overwritten, so another writer's write found on the read-back may have gone over this one, and\n * a row that is gone may have been removed after it landed. Raise every conflict it cannot rule that out for (another\n * writer's write on the read-back, a compare-and-swap that finds the row gone, a read-back that finds nothing) as\n * `unsettledConflict`, so a load refused after it reports `unanswered: true`. A conflict that proves the write did\n * not land (a write sent once, a check made before sending anything) is a plain {@link WriteConflictError}. A\n * registry that wraps another rethrows the conflict it was given, unchanged: the check that reads the mark is\n * internal, so a conflict built anew loses it.\n * - **Raise a transient fault as {@link TransientError}.**\n */\nexport interface IRegistryDriver {\n /** What this registry can do. Strongly consistent reads are required; the other capabilities are optional. */\n capabilities(): RegCaps;\n /**\n * `true` when every `create` and `compareAndSwap` of this registry reports the token its write carries to\n * {@link RegistryWriteOptions.onToken} before sending it, a resend included. A load, an erasure's rewrite and every\n * other publish then knows whether a write that conflicted or got no answer landed by whether the row's `pointerId`\n * is a token it was told, which names the writer and not only the bytes. Absent or `false`: the registry reports\n * none, and such a write is settled by reading the object the publish wrote. A shipped registry says which it is.\n *\n * The flag may be a getter or a field. A registry that wraps or extends another and overrides `create` or\n * `compareAndSwap` either passes `options` through to the write it forwards, or sets `reportsWriteTokens` to\n * `false`. One that does neither reads a write of its own that landed and then met a conflict as not its own\n * (`superseded`), and takes every `TransientError` of its writes, a throttle and a lost answer alike, for a fault\n * before sending: the publish throws it at once, with no read of the row and no fresh write. Either way it deletes\n * nothing.\n *\n * A publish relies on the report coming first, both ways. A write that faults after its report may have landed, and\n * is settled by reading the row. A `TransientError` before any report is taken for a fault before sending, such as\n * the driver's own read of the row: the publish throws it at once, with no read of the row and no fresh write. So\n * nothing that can land is sent before the report, a client's own resend included.\n */\n readonly reportsWriteTokens?: boolean;\n /**\n * The segment's record, or `null` if it doesn't exist (or was deleted). Throw {@link TransientError} for a fault\n * worth riding out (throttling, a 5xx, a dropped connection): a reader whose pointer refresh meets one keeps\n * serving what it holds and asks again shortly, while any other error reaches the read that met it.\n */\n get(ref: SegmentRef): Promise<RegistryRecord | null>;\n /**\n * Create the row; throws {@link WriteConflictError} if it already exists (use CAS to mutate). With\n * `options.held` of `null`, the caller found no row: a driver may send the create-only write without reading first,\n * and one that then loses it reads the row, as it does without the hint.\n */\n create(\n ref: SegmentRef,\n record: NewRegistryRecord,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }>;\n /**\n * Server-side compare-and-set: apply `patch` iff the stored token equals `expected`, else `WriteConflictError`.\n * `options.held` is the row the caller read, which a driver may use to skip its own read; see\n * {@link RegistryWriteOptions}.\n */\n compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }>;\n /**\n * Discovery: every **existing** record, optionally scoped to one namespace. Order is unspecified.\n *\n * \"Existing\" means not `delete`d. A **`destroyed` tombstone is still a record and must be yielded** \u2014 a driver\n * that filters by `status` breaks callers silently, and two already depend on seeing them: `runConsistencyCheck`\n * skips them itself, and the retention sweep can only clean up a tombstone row it can see (filtering it makes\n * the cleanup a permanent no-op, indistinguishable from having nothing to do, while dead rows accumulate). Same\n * rule for every other field: a row with **`currentGen: null`** must be yielded like any other, and `retention`\n * must survive the projection \u2014 a fleet sweep reads the policy straight out of this enumeration rather than\n * paying a `get()` per segment, so a `list()` that drops the field means nothing ever expires, silently.\n */\n list(namespace?: string): AsyncIterable<RegistryRecord>;\n /**\n * Remove the row. A registry whose {@link RegCaps.conditionalDelete} is `true` removes it from its backend; any other\n * tombstones it. Either way a later `create` gets a token no\n * earlier incarnation of the name held, but for a collision of probability 2^-128 per pair of incarnations.\n *\n * Without `expected`, idempotent: deleting an absent row is a no-op.\n *\n * With `expected`, the delete is **fenced like a {@link IRegistryDriver.compareAndSwap}**: it lands only while\n * the row still carries exactly that token, and otherwise \u2014 the token differs, or the row is absent or already\n * deleted \u2014 throws {@link WriteConflictError} and leaves the row. Pass the token of the row you read when you\n * decided to delete it, so a delete that is delayed, replayed, or racing a re-create cannot tombstone a row\n * created after the decision. A third-party driver that ignores `expected` keeps the unfenced behaviour.\n */\n delete(ref: SegmentRef, expected?: Token): Promise<void>;\n}\n", "/**\n * The registry token's incarnation: the part of a token that says which incarnation of a name a row is.\n *\n * A shipped registry gives a row it creates a token `<incarnation>.<counter>.<write>`: 32 lowercase hex digits drawn\n * from injected entropy when the row is created, a decimal counter, and 16 hex digits drawn for each write. Every write\n * of the row keeps the incarnation, and a name created again draws a new one, so two incarnations are told apart by it\n * even when their rows were created in the same millisecond or one is gone. A registry of someone else's issues tokens\n * in any form, and one whose tokens carry no incarnation id is told apart only by the row's creation stamp.\n *\n * This lives in `core/` so the publish can read it, and the registry drivers, which build the tokens, import it from\n * here: the form has one definition.\n */\nimport type { Token } from './ports';\n\n/** An incarnation-form token: the incarnation id, the counter and a write part, `.`-separated, in lowercase hex. */\nexport const INCARNATION_TOKEN = /^([0-9a-f]{32})\\.(0|[1-9]\\d*)\\.([0-9a-f]{16})$/;\n\n/**\n * The incarnation id in a token, or `undefined` for one that has none: a token a registry of someone else's issues in\n * another form. Two tokens with the same incarnation are writes of one incarnation of a row.\n */\nexport function incarnationOf(token: Token): string | undefined {\n return INCARNATION_TOKEN.exec(token)?.[1];\n}\n\n/** An audit event's `incarnation`, from the token of the row it is about: absent for a token that carries none. */\nexport function incarnationField(token: Token | undefined): { readonly incarnation?: string } {\n const incarnation = token === undefined ? undefined : incarnationOf(token);\n return incarnation === undefined ? {} : { incarnation };\n}\n\n/** What tells one incarnation of a name's row from another: its token and its creation stamp. */\nexport interface Incarnation {\n readonly token: Token;\n readonly createdAt: number;\n}\n\n/**\n * Whether two reads of one name's row are one incarnation of it.\n *\n * - Both tokens carry an incarnation id: the ids decide, and the clock stamps do not enter.\n * - Only one does: different incarnations. A registry gives its rows one form of token, so a row without an id never\n * becomes a row with one, nor the reverse.\n * - Neither does (a registry of someone else's whose tokens carry none): there is no id to compare, and the creation\n * stamp is the only signal left. It is a clock reading, so `landedHere` also checks the object under the number by\n * its footer, and `onlyLeasesDiffer` also requires every field but the leases to match.\n */\nexport function sameIncarnation(a: Incarnation, b: Incarnation): boolean {\n const ia = incarnationOf(a.token);\n const ib = incarnationOf(b.token);\n if (ia !== undefined || ib !== undefined) return ia === ib;\n return a.createdAt === b.createdAt;\n}\n", "/**\n * A registry row's `pointerId`: which write last named a field a read resolves through.\n *\n * A read resolves a segment through five fields of its row: `currentGen` (the generation), `status` (a destroyed row\n * reads empty), `wrappedDeks` and `keyId` (the key), and `summary` (a count answered from the row). `pointerId` is the\n * token of the most recent write that named one of them: the row's create, or a compare-and-swap whose patch names any\n * of the five, at any value, the one it already has included. A write of the leases, the retention or residency policy\n * or the kept window leaves it as it was. So a reader that keys what it caches on a generation with the row's\n * `pointerId` keeps its cache across a lease or a policy write, and never keeps it across a write that changes what the\n * row resolves to.\n *\n * The registry sets it, never a caller: it is the token the registry gives that write, which the writer gets back, so a\n * writer knows its own new value without reading the row. It is compared by equality only, like the token, and is\n * never reused under one name, since a token is not. The shipped registries apply the rule in their shared record\n * builders; a third-party registry applies it through {@link renewsPointer}. Pure: no I/O.\n */\nimport { UnsupportedError } from './errors';\nimport type { RegistryPatch, RegistryRecord, Token } from './ports';\nimport { sameIncarnation } from './token';\n\n/** The fields a read resolves through: a patch that names any of them renews the row's `pointerId`. */\nexport const RESOLVED_FIELDS = [\n 'currentGen',\n 'status',\n 'wrappedDeks',\n 'keyId',\n 'summary',\n] as const satisfies readonly (keyof RegistryPatch)[];\n\n/**\n * Whether a compare-and-swap of `patch` renews the row's `pointerId`: whether it names a resolved field, by presence\n * (`'field' in patch`), whatever the value, as every patch rule reads a patch.\n */\nexport function renewsPointer(patch: RegistryPatch): boolean {\n return RESOLVED_FIELDS.some((field) => field in patch);\n}\n\n/**\n * The patch that renews a row's `pointerId` and changes nothing a read resolves: the pointer, named at the value it\n * has. A same-value pointer keeps the summary and the kept window, which follow the pointer only when it changes value.\n */\nexport function renewPointer(row: Pick<RegistryRecord, 'currentGen'>): RegistryPatch {\n return { currentGen: row.currentGen };\n}\n\n/**\n * The row's `pointerId`, refusing a row that has none with {@link UnsupportedError}: a registry written against an\n * earlier port contract returns rows without it, and a reader that cannot tell which write set the row's resolution\n * cannot key a cache on it. A TypeScript registry fails to compile instead; this catches one in JavaScript.\n */\nexport function pointerIdOf(row: RegistryRecord): Token {\n const pointerId = (row as { readonly pointerId?: unknown }).pointerId;\n if (typeof pointerId !== 'string' || pointerId.length === 0) {\n throw new UnsupportedError(\n `the registry returned the row of \"${row.segment}\" with no pointerId: a registry must set it on every row ` +\n '(the token of the write that last named currentGen, status, wrappedDeks, keyId or summary; see ' +\n 'renewsPointer in @cloudbitmaps/core/driver-kit)',\n );\n }\n return pointerId;\n}\n\n/**\n * Whether `now` shows a write this call sent as the one that put the pointer where it is: an active row of the same\n * incarnation as `before` (a `create` has none to compare), whose pointer names `generation` and whose `pointerId` is\n * the token of one of the writes in `sent`, which a registry that reports its writes' tokens gave before sending each.\n * The token decides and nothing else is asked, so another writer's write of the same pointer is not taken for this\n * call's. A write that renews the `pointerId` over this call's own landed write (an erasure's renewal, or a write of\n * the pointer back onto the same generation) reads as not this call's: the two cannot be told apart. Pure: no I/O.\n */\nexport function pointerSetBy(\n now: RegistryRecord | null,\n before: RegistryRecord | null,\n generation: number,\n sent: ReadonlySet<Token>,\n): boolean {\n if (now === null || now.status === 'destroyed' || now.currentGen !== generation) return false;\n if (before !== null && !sameIncarnation(before, now)) return false;\n return sent.has(now.pointerId);\n}\n", "/**\n * Encryption seams \u2014 the **pure** interfaces `core/` depends on so the codec can encrypt/decrypt without\n * importing `node:crypto` (lint-banned here, like `Clock`/`Rng`/drivers). Concrete AES-256-GCM lives outside\n * `core/` (`src/drivers/crypto.ts`) and is injected. The envelope scheme: a per-segment DEK wrapped under an\n * operator-held KEK, so discarding the DEK crypto-shreds the segment. Per-chunk AEAD over the `.crbm` payloads + index; a per-segment **DEK** wrapped (envelope\n * encryption) under one or more **KEK**s by an {@link IKeystore}; the wrapped DEK(s) live in the registry, so\n * crypto-shred = delete them.\n */\n\n/** One AEAD result: a fresh per-message nonce, the ciphertext, and the authentication tag. */\nexport interface AeadSealed {\n /** The fresh per-message nonce. */\n readonly nonce: Uint8Array;\n /** The encrypted bytes. */\n readonly ciphertext: Uint8Array;\n /** The authentication tag. */\n readonly tag: Uint8Array;\n}\n\n/**\n * Authenticated encryption bound to a single key (a segment's DEK). `aad` (associated data) is authenticated\n * but not encrypted \u2014 the codec passes each chunk's `(namespace, segment, generation, chunkKey)` identity\n * (the library derives it; an `Aead` implementation receives it), so a chunk's ciphertext can't be silently\n * relocated to another segment/generation/chunk or\n * the index, even by someone who can rewrite Storage objects. The seam is symmetric and self-framing-agnostic:\n * the caller decides where the nonce/tag go (inline with a chunk, or in the footer for the index).\n */\nexport interface Aead {\n /** Encrypt `plaintext`, authenticating `aad`. Returns a fresh nonce + ciphertext + tag. */\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed;\n /**\n * Decrypt + verify. Throws {@link IntegrityError} on **any** mismatch (wrong key, tampered ciphertext/tag,\n * or `aad` that doesn't match what was sealed) \u2014 never returns wrong-but-plausible plaintext.\n */\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array;\n}\n\n/**\n * A DEK wrapped under one KEK. A segment stores a **list** of these (one per KEK it was wrapped under \u2014 e.g.\n * an active KEK plus an offline recovery KEK), so losing one KEK isn't fatal and KEK rotation needs no\n * data re-encryption. `keyId` names which KEK; `wrapped` is the opaque wrapped-key blob (base64). Carries no\n * plaintext key material \u2014 safe to store in the registry next to the (encrypted) data.\n */\nexport interface WrappedDek {\n /** The id of the key-encryption key (KEK) this wrapping is under. */\n readonly keyId: string;\n /** The wrapped data key, an opaque base64 string. */\n readonly wrapped: string;\n}\n\n/**\n * Envelope key management \u2014 the injected seam between the codec and however the operator holds key material\n * (in-process BYOK by default; KMS/Vault as optional adapters later). Async so a remote keystore (KMS) fits\n * the same interface. Never exposes raw key bytes to `core/`: it returns an {@link Aead} bound to the DEK.\n */\nexport interface IKeystore {\n /**\n * Mint a fresh per-segment DEK, wrapped under the active KEK (and any recovery KEK). Returns the wrapping(s)\n * to persist in the registry plus an {@link Aead} to encrypt this segment's chunks with.\n */\n createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }>;\n /**\n * Reconstruct the {@link Aead} from a segment's stored wrappings by unwrapping with any KEK currently held.\n * Throws {@link KeyUnavailableError} if it holds none of the referenced KEKs (lost key, or a shredded\n * segment whose wrappings were deleted). Throw {@link TransientError} for a fault worth riding out (a throttle, a 5xx,\n * a dropped connection, a request timeout): a rollback below a segment's pointer goes ahead without the key on that\n * error, as on `KeyUnavailableError`, an `IntegrityError` or an `Error` named `TimeoutError`, and is stopped by any\n * other error the keystore throws.\n */\n openDek(wrapped: readonly WrappedDek[]): Promise<Aead>;\n}\n\n/**\n * What the encrypting codec needs: the {@link Aead} for this segment's DEK plus a way to build the AAD for a\n * given scope (a chunkKey, `'index'`, or `'metadata'` for the generation's metadata section). Built per\n * (segment, generation) by the storage-source bridge so the codec itself stays segment-agnostic.\n */\nexport interface CrbmCrypto {\n readonly aead: Aead;\n aadFor(scope: number | 'index' | 'metadata'): Uint8Array;\n}\n\nconst UTF8 = new TextEncoder();\nconst AAD_VERSION = 1;\nconst SCOPE_CHUNK = 0;\nconst SCOPE_INDEX = 1;\nconst SCOPE_METADATA = 2;\nconst SCOPE_SUMMARY = 3;\n\n/**\n * Build the AEAD associated-data binding a chunk, the index, the metadata section or a registry row's sealed summary\n * to its exact location:\n * `v1 \u2016 len(namespace) \u2016 namespace \u2016 len(segment) \u2016 segment \u2016 generation \u2016 scope \u2016 chunkKey`, where scope is\n * `0` for a chunk, `1` for the index, `2` for the metadata and `3` for the row's summary, and chunkKey is `0` for\n * the last three.\n * Length-prefixed so distinct `(namespace, segment)` pairs can never collide. Pure (no crypto) \u2014 just the\n * authenticated label.\n */\nexport function aadFor(\n ref: { readonly namespace?: string; readonly segment: string },\n generation: number,\n scope: number | 'index' | 'metadata' | 'summary',\n): Uint8Array {\n const ns = UTF8.encode(ref.namespace ?? '');\n const seg = UTF8.encode(ref.segment);\n const out = new Uint8Array(1 + 2 + ns.length + 2 + seg.length + 8 + 1 + 4);\n const view = new DataView(out.buffer);\n let o = 0;\n out[o] = AAD_VERSION;\n o += 1;\n view.setUint16(o, ns.length, true);\n o += 2;\n out.set(ns, o);\n o += ns.length;\n view.setUint16(o, seg.length, true);\n o += 2;\n out.set(seg, o);\n o += seg.length;\n view.setBigUint64(o, BigInt(generation), true);\n o += 8;\n out[o] =\n scope === 'index'\n ? SCOPE_INDEX\n : scope === 'metadata'\n ? SCOPE_METADATA\n : scope === 'summary'\n ? SCOPE_SUMMARY\n : SCOPE_CHUNK;\n o += 1;\n view.setUint32(o, typeof scope === 'number' ? scope : 0, true);\n return out;\n}\n\n/** Whether two rows carry the same wrapped keys. */\nexport const sameKeys = (a: readonly WrappedDek[] | undefined, b: readonly WrappedDek[]): boolean =>\n a !== undefined && JSON.stringify(a) === JSON.stringify(b);\n", "/**\n * `withRetry` \u2014 the one retry/backoff primitive.\n *\n * A pure, storage-agnostic helper: it knows nothing about HTTP, AWS, or any SDK. It retries an operation\n * while the operation keeps failing with a **retryable** error (by default {@link TransientError}), waiting\n * a bounded, jittered, exponentially-growing delay between attempts. Time and randomness are **injected**\n * (the determinism seam) \u2014 production wires a `setTimeout`-backed clock + a real RNG; the\n * tests wire virtual ones \u2014 so a backoff schedule is replayable from a seed and unit tests run with no\n * real sleeping.\n *\n * It deliberately does **not** retry deterministic failures ({@link WriteConflictError},\n * {@link ValidationError}, {@link IntegrityError}, {@link NotFoundError}, \u2026): retrying those either can't\n * help or would be incorrect. A pointer conflict is retried by a *separate* loop inside\n * the publish, because each attempt must re-read the row and re-decide \u2014 a blind replay of the same\n * compare-and-swap would either fail again on a stale token or, worse, advance a pointer whose state has\n * changed underneath it. A write-once object collision is never replayed at all: the generation number is\n * taken, so the caller has to pick a new one.\n */\nimport { requireFiniteNumber, requireInteger } from './check';\nimport type { Clock, Rng } from './determinism';\nimport { isTransientError, ValidationError } from './errors';\n\n/**\n * How the store retries a transient read: attempts, exponential backoff with a cap, and jitter. By default 4 attempts,\n * a 50 ms base delay, \u00D72, a 2 s cap and full jitter; the store's `retry` option overrides them a field at a time.\n */\nexport interface RetryPolicy {\n /** Total attempts including the first (so `maxAttempts: 4` = 1 try + 3 retries). Must be \u2265 1. */\n readonly maxAttempts: number;\n /** Delay before the first retry, in ms. Grows by `backoffFactor` each subsequent retry. */\n readonly baseDelayMs: number;\n /** Upper bound on a single (pre-jitter) delay, in ms \u2014 caps the exponential growth. */\n readonly maxDelayMs: number;\n /** Exponential growth factor between retries (e.g. 2 \u21D2 base, 2\u00B7base, 4\u00B7base, \u2026). */\n readonly backoffFactor: number;\n /**\n * `'full'` \u21D2 the actual wait is uniform in `[0, computed]` (AWS-recommended full jitter: decorrelates\n * concurrent retriers so they don't reconverge into a thundering herd). `'none'` \u21D2 wait exactly `computed`.\n */\n readonly jitter: 'full' | 'none';\n}\n\n/**\n * Conservative defaults: 4 attempts, 50ms \u2192 100 \u2192 200 (\u00D72), capped at 2s, full jitter. Tuned for a cloud\n * backend's brief throttle/5xx blip \u2014 enough to ride out a transient fault without turning a hard outage\n * into a long hang. Override per store (`retry`) or per read source (`RetryingStorageChunkSource`) if your latency\n * budget differs.\n */\nexport const DEFAULT_RETRY_POLICY: RetryPolicy = {\n maxAttempts: 4,\n baseDelayMs: 50,\n maxDelayMs: 2_000,\n backoffFactor: 2,\n jitter: 'full',\n};\n\nexport interface RetryDeps {\n readonly clock: Clock;\n readonly rng: Rng;\n /** Override which errors are retryable. Default: any {@link TransientError}. */\n readonly isRetryable?: (err: unknown) => boolean;\n /**\n * Optional hook (observability) fired before each backoff wait. `attempt` is 1-based (the one that failed).\n * Best-effort: an error it throws is swallowed, so it can neither stop the retry nor change the error thrown.\n */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/**\n * Backoff delay (ms) for the retry that follows a given 1-based attempt, before jitter is applied. Exposed\n * for tests. `attempt` 1 \u21D2 `baseDelayMs`, 2 \u21D2 `base\u00B7factor`, \u2026 capped at `maxDelayMs`.\n */\nexport function backoffDelayMs(policy: RetryPolicy, attempt: number): number {\n const raw = policy.baseDelayMs * policy.backoffFactor ** (attempt - 1);\n return Math.min(policy.maxDelayMs, raw);\n}\n\n/** Apply the policy's jitter to a computed delay using the injected RNG. */\nexport function applyJitter(policy: RetryPolicy, delayMs: number, rng: Rng): number {\n if (policy.jitter === 'none') return delayMs;\n return rng.next() * delayMs; // full jitter: uniform in [0, delayMs)\n}\n\n/** A clock that can wait: the one member {@link jitteredWait} uses. */\nexport interface Sleeper {\n readonly sleep?: ((ms: number) => Promise<void>) | undefined;\n}\n\n/**\n * Wait a uniformly spread share of `boundMs`, whole milliseconds, by the clock's `sleep`. With no `rng` it waits the\n * whole bound; with no `sleep` it does not wait.\n */\nexport function jitteredWait(\n clock: Sleeper | undefined,\n rng: Rng | undefined,\n boundMs: number,\n): Promise<void> {\n const sleep = clock?.sleep;\n return sleep === undefined\n ? Promise.resolve()\n : sleep.call(clock, Math.floor((rng?.next() ?? 1) * boundMs));\n}\n\n/**\n * The store's read retry, as a write path takes it for the reads it makes along the way: a policy (the default when\n * absent) and what {@link withRetry} needs to run it.\n */\nexport type ReadRetry = RetryDeps & { readonly policy?: RetryPolicy };\n\n/**\n * Run a read under `retry`, or once when there is none. For the reads a write makes along the way (a load guard's\n * read of the current generation, an erasure's reads of the generations it rewrites and verifies): a read is safe\n * to repeat, so a transient fault on one is retried under the store's policy rather than failing the whole write.\n * The write itself is never passed here.\n */\nexport function retryRead<T>(op: () => Promise<T>, retry: ReadRetry | undefined): Promise<T> {\n return retry === undefined ? op() : withRetry(op, retry.policy ?? DEFAULT_RETRY_POLICY, retry);\n}\n\n/**\n * `policy`, checked when it is wired rather than at the first retry: a delay or factor that is not a finite number, a\n * negative delay, a factor below 1 or a jitter mode it does not know would make the backoff `NaN`, which a timer reads\n * as 1 ms, so bounded backoff silently became a hot retry loop. `maxAttempts` is a whole number, and `maxDelayMs` is not\n * below `baseDelayMs`, which it would otherwise cap every delay under.\n */\nexport function checkedRetryPolicy(policy: RetryPolicy): RetryPolicy {\n const { maxAttempts, baseDelayMs, maxDelayMs, backoffFactor, jitter } = policy;\n requireInteger(maxAttempts, { min: 1, what: 'retry.maxAttempts' });\n requireFiniteNumber(baseDelayMs, { min: 0, what: 'retry.baseDelayMs' });\n requireFiniteNumber(maxDelayMs, {\n min: baseDelayMs,\n what: 'retry.maxDelayMs',\n note: 'retry.baseDelayMs',\n });\n requireFiniteNumber(backoffFactor, { min: 1, what: 'retry.backoffFactor' });\n if (jitter !== 'full' && jitter !== 'none') {\n throw new ValidationError(`retry.jitter must be 'full' or 'none'`);\n }\n return policy;\n}\n\n/**\n * Run `op`, retrying transient failures per `policy`. Resolves with `op`'s result, or rejects with the last\n * error once attempts are exhausted (or immediately for a non-retryable error). The thrown error is always\n * the *operation's* error \u2014 never a wrapper \u2014 so callers keep their typed-error branching.\n */\nexport async function withRetry<T>(\n op: () => Promise<T>,\n policy: RetryPolicy,\n deps: RetryDeps,\n): Promise<T> {\n const retryable = deps.isRetryable ?? isTransientError;\n // A `NaN` count (`Number(process.env.X)` with the variable unset) would skip the loop, never call `op` and reject\n // with the literal `undefined`; a policy that bypassed `checkedRetryPolicy` is refused here instead.\n const attempts = requireInteger(policy.maxAttempts, { min: 1, what: 'retry.maxAttempts' });\n let lastErr: unknown;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await op();\n } catch (err) {\n lastErr = err;\n if (attempt >= attempts || !retryable(err)) throw err;\n const delayMs = applyJitter(policy, backoffDelayMs(policy, attempt), deps.rng);\n try {\n deps.onRetry?.({ attempt, delayMs, err });\n } catch {\n // Observability is best-effort, as for a metrics sink (`safeMetrics`): a throwing hook must neither abort\n // the retry nor replace the operation's error with its own. This module has no sink to report it to.\n }\n await deps.clock.sleep(delayMs);\n }\n }\n // Unreachable: the loop either returns or throws. Satisfies the type checker.\n throw lastErr;\n}\n", "/**\n * Leases: a bounded hold on one generation, recorded in the segment's registry row, that keeps the generation out of a\n * load's collection until the lease ends.\n *\n * The row holds a list of `{ holder, generation, until }`. A collector that honours leases reads the list from the row\n * it already has and spares a live entry; erasure, shred, drop and retention expiry never look at it. The entry names\n * no fingerprint: a collector spares a generation by number and cannot compare an object without reading it, a purge\n * and re-create drops the list with the row, and the row's token names the incarnation. The pin's own fingerprint,\n * which its reads check, is what stops a number retaken after a rollback and an erasure being read as the leased\n * object; the entry then spares a different object from collection until it ends, at most the longest lease.\n *\n * Clocks. The holder ends a lease at `until` by its own clock. A collector holds it for {@link LEASE_SKEW_MS} longer, by\n * its own. The hold is safe while the two clocks differ by at most that margin, whichever way: a reader behind by `r`\n * serves until `until + r` of real time and a collector ahead by `c` stops holding at `until + margin - c`, so the\n * generation is there for every read the reader makes iff `r + c <= margin`. Pure orchestration over the registry port\n * and the injected clock and rng: no I/O, time or randomness of its own.\n */\nimport {\n CONTENTION_NEXT_STEP,\n LeaseLimitError,\n NotFoundError,\n WriteConflictError,\n isTransientError,\n isWriteConflictError,\n} from './errors';\nimport type { Clock, Rng } from './determinism';\nimport { jitteredWait } from './retry';\nimport { sameIncarnation } from './token';\nimport type { IRegistryDriver, LeaseEntry, RegistryRecord, SegmentRef, Token } from './ports';\n\n/** The longest lease: a `leaseUntil` further than this from the clock is refused. */\nexport const MAX_LEASE_MS = 14 * 86_400_000;\n\n/**\n * How much longer than `until` a collector holds a lease, and the most a collector will believe a lease runs past\n * its own clock. It is the tolerated difference between the holder's clock and the collector's, in either direction.\n */\nexport const LEASE_SKEW_MS = 60_000;\n\n/** The most live leases a writer records on one segment; the next one is refused with {@link LeaseLimitError}. */\nexport const MAX_LEASES_PER_SEGMENT = 64;\n\n/** The most entries a stored row may hold: four times what a writer writes, so a release can raise the cap. */\nexport const MAX_STORED_LEASES = 256;\n\n/**\n * Read-modify-write attempts of one take or release before it reports contention. Takers of one row serialise: each\n * round exactly one write lands, so the slowest of `k` simultaneous takers needs `k` attempts. The bound is the cap\n * plus a few, so that the most a segment can hold, all arriving at once, can all land.\n */\nexport const LEASE_CAS_ATTEMPTS = MAX_LEASES_PER_SEGMENT + 8;\n\n/**\n * Fresh writes sent after one that got no answer and left the row as it was, by the lease writers, by an erasure's\n * renewal of the row and by a publish: four sends of the row write in all.\n */\nexport const UNANSWERED_RESENDS = 3;\n/** The upper bound of the first of those waits, in ms; each next one doubles it. */\nexport const UNANSWERED_BASE_MS = 500;\n/** The upper bound of the first wait after a lost race, in ms; each next doubles it, to the cap. */\nconst CONFLICT_BASE_MS = 25;\nconst CONFLICT_CAP_MS = 400;\n\n/**\n * Whether an entry holds its generation against a collector reading `now`: it has not ended (`until` plus the margin\n * is ahead), and it does not run further past `now` than any honest holder with a clock inside the margin could have\n * written (`until` at most the longest lease plus the margin ahead). The second clause bounds a corrupt or forged\n * `until` without refusing the row: an entry past it is read and not honoured.\n */\nexport function isLive(entry: LeaseEntry, now: number): boolean {\n return now < entry.until + LEASE_SKEW_MS && entry.until <= now + MAX_LEASE_MS + LEASE_SKEW_MS;\n}\n\n/** The generations a collector reading `now` must spare, from the row it holds. */\nexport function heldGenerations(record: RegistryRecord | null, now: number): ReadonlySet<number> {\n const out = new Set<number>();\n for (const e of record?.leases ?? []) if (isLive(e, now)) out.add(e.generation);\n return out;\n}\n\n/** The entries of a row that are live at `now`, in the row's order. */\nexport function liveLeases(record: RegistryRecord | null, now: number): readonly LeaseEntry[] {\n return (record?.leases ?? []).filter((e) => isLive(e, now));\n}\n\n/**\n * What a writer that fences on the row's token needs to wait out lease churn: a sleep, and the rng that spreads it.\n * Both are optional; without a sleep a retry follows at once.\n */\nexport interface ChurnDeps {\n /** The clock whose `sleep` waits out lease churn. Without a `sleep`, a retry follows at once. */\n readonly clock?: { readonly sleep?: (ms: number) => Promise<void> } | undefined;\n /** The source that spreads each wait over a share of its bound. Without one, each wait is its whole bound. */\n readonly rng?: Rng | undefined;\n}\n\n/**\n * How many times one writer retries after meeting a row that differs from the one it read only in its leases. Takers of\n * one row serialise: each round exactly one write lands, so a writer racing `k` holders needs up to `k + 1` rounds, and a\n * holder can take and release inside one job, so the bound covers a take and a release by every holder the row can\n * hold, with a few to spare: 2 * {@link MAX_LEASES_PER_SEGMENT} + 8. At waits of up to 25 ms growing to up to 400 ms it is a\n * minute at the very most before the writer reports the conflict it had, and a lease writer that goes on beyond\n * that has stopped being a lease writer and become a flood.\n */\nexport const LEASE_ONLY_RETRIES = 2 * MAX_LEASES_PER_SEGMENT + 8;\n\n/** The fields of a row that a lease write moves without changing what the row says, and the ones that name it. */\nconst BOOKKEEPING: ReadonlySet<string> = new Set(['token', 'updatedAt', 'leases']);\n\n/** A stable text of a value: object keys in order, `undefined` as absent, so two equal rows compare equal. */\nfunction stable(value: unknown): string {\n if (value === undefined) return 'u';\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;\n const o = value as Record<string, unknown>;\n const keys = Object.keys(o)\n .filter((k) => o[k] !== undefined)\n .sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${stable(o[k])}`).join(',')}}`;\n}\n\n/**\n * Whether `now` is `held` with nothing changed but its leases: the same incarnation, and every other field equal,\n * `updatedAt` and the token (which every write moves) aside. `alsoIgnore` names fields the caller's own earlier write\n * changed, so a writer comparing against a row it has itself written does not take its own change for another's.\n *\n * This is the one test that lets a writer fenced on the row's token go on after a lease write: a lease is written by\n * readers, in numbers no operator controls, and it says nothing about the content the writer derived, the pointer it\n * judged or the key it holds. Any other difference is another writer's, and the fence refuses as it always has.\n */\nexport function onlyLeasesDiffer(\n held: RegistryRecord,\n now: RegistryRecord,\n alsoIgnore: readonly (keyof RegistryRecord)[] = [],\n): boolean {\n if (!sameIncarnation(held, now)) return false;\n const skip = new Set<string>([...BOOKKEEPING, ...alsoIgnore]);\n const keys = new Set([...Object.keys(held), ...Object.keys(now)]);\n for (const k of keys) {\n if (skip.has(k)) continue;\n if (\n stable((held as unknown as Record<string, unknown>)[k]) !==\n stable((now as unknown as Record<string, unknown>)[k])\n ) {\n return false;\n }\n }\n return true;\n}\n\n/** A writer's count of the lease-only changes it has waited out, and the wait. One per call of the writer. */\ninterface LeaseChurn {\n /**\n * When `now` is `held` changed only in its leases and the bound is not spent: wait, then read the row again with\n * `reread`, and return what it found. The wait comes before the read, so the writer's next write is made against a row\n * as fresh as one round trip, not one as stale as the wait. The caller checks that row against `held` once more (a\n * write may have landed during the wait) and goes on against it, without redoing its work. `undefined` otherwise, and\n * the caller does what it always did.\n *\n * The wait is uniform in `[0, bound)`, the bound starting at 25 ms and doubling to 400 ms, taken on the injected\n * clock's `sleep` and spread by its `rng`. With no `sleep` there is no wait, and the retries follow one another at\n * once; with no `rng` the wait is exactly the bound, so contenders stay in step. The store always supplies both.\n */\n settle(\n held: RegistryRecord | null | undefined,\n now: RegistryRecord | null,\n reread: () => Promise<RegistryRecord | null>,\n alsoIgnore?: readonly (keyof RegistryRecord)[],\n ): Promise<{ readonly row: RegistryRecord | null } | undefined>;\n}\n\nexport function leaseChurn(deps: ChurnDeps): LeaseChurn {\n let used = 0;\n return {\n async settle(held, now, reread, alsoIgnore) {\n if (held === null || held === undefined || now === null) return undefined;\n if (used >= LEASE_ONLY_RETRIES || !onlyLeasesDiffer(held, now, alsoIgnore)) return undefined;\n const bound = Math.min(CONFLICT_BASE_MS * 2 ** Math.min(used, 4), CONFLICT_CAP_MS);\n used += 1;\n await jitteredWait(deps.clock, deps.rng, bound);\n return { row: await reread() };\n },\n };\n}\n\n/** A row's leases for a patch: the given entries, sorted by generation then holder, or `undefined` when none. */\nfunction listOf(entries: readonly LeaseEntry[]): readonly LeaseEntry[] | undefined {\n if (entries.length === 0) return undefined;\n return [...entries].sort((a, b) =>\n a.generation !== b.generation\n ? a.generation - b.generation\n : a.holder < b.holder\n ? -1\n : a.holder > b.holder\n ? 1\n : 0,\n );\n}\n\n/** What the lease writers need: the registry, the clock that judges liveness and waits, and the rng that spreads waits. */\nexport interface LeaseDeps {\n readonly registry: IRegistryDriver;\n readonly clock: Clock;\n readonly rng?: Rng;\n}\n\n/** What a take asks for. */\nexport interface LeaseTake {\n /** Drawn once per pin call, outside any retry, so a write that landed unseen is found again and never duplicated. */\n readonly holder: string;\n /** The generation to hold. */\n readonly generation: number;\n /** Epoch-ms, already checked against the caller's clock. */\n readonly until: number;\n /** The row the caller read; the first write is made against it, with no row read of its own. */\n readonly row: RegistryRecord;\n /** The generation must still be the row's pointer on every attempt: a pin of the current generation. */\n readonly current: boolean;\n}\n\n/** A lease that landed: the token its write returned, and the row that write was made against. */\nexport interface TakenLease {\n readonly token: Token;\n readonly row: RegistryRecord;\n}\n\nconst wait = (deps: LeaseDeps, bound: number): Promise<void> =>\n jitteredWait(deps.clock, deps.rng, bound);\n\nconst heldBy = (row: RegistryRecord | null, take: LeaseTake): boolean =>\n (row?.leases ?? []).some(\n (e) => e.holder === take.holder && e.generation === take.generation && e.until === take.until,\n );\n\n/**\n * Write a lease entry for `take.holder`, fenced on the row it was made against, so a lease that lands proves the row\n * was unchanged since the caller read it. Returns `'moved'` when `take.current` and the pointer is no longer at the\n * generation (the caller starts over from a fresh read). Throws {@link NotFoundError} for a row that is gone,\n * destroyed or has no such published generation, {@link LeaseLimitError} when the segment already has\n * {@link MAX_LEASES_PER_SEGMENT} live leases (nothing is written), `WriteConflictError` after\n * {@link LEASE_CAS_ATTEMPTS} lost races, and the registry's own `TransientError` for a write that stayed unanswered.\n *\n * Idempotent by holder: an entry for the holder is replaced, so a retry of a whole pin re-takes without duplicating,\n * and a write that got no answer is settled by reading the row for the holder's entry.\n */\nexport async function takeLease(\n ref: SegmentRef,\n deps: LeaseDeps,\n take: LeaseTake,\n): Promise<TakenLease | 'moved'> {\n let row: RegistryRecord | null = take.row;\n let held = true; // whether `row` is the row the caller read: only then is it passed as the write's hint\n let resends = 0;\n let unanswered: unknown;\n for (let attempt = 0; attempt < LEASE_CAS_ATTEMPTS; attempt++) {\n if (row === null) row = await deps.registry.get(ref);\n if (row === null || row.status === 'destroyed' || row.currentGen === null) {\n throw new NotFoundError(`segment \"${ref.segment}\" has no generation to lease`);\n }\n if (take.generation > row.currentGen) {\n throw new NotFoundError(\n `segment \"${ref.segment}\" generation ${take.generation} cannot be leased: it is not a published generation`,\n );\n }\n if (take.current && row.currentGen !== take.generation) return 'moved';\n if (heldBy(row, take)) return { token: row.token, row };\n const live = liveLeases(row, deps.clock.now()).filter((e) => e.holder !== take.holder);\n if (live.length >= MAX_LEASES_PER_SEGMENT) {\n throw new LeaseLimitError(\n `segment \"${ref.segment}\" already has ${live.length} live leases, the most one segment records`,\n );\n }\n const leases = listOf([\n ...live,\n { holder: take.holder, generation: take.generation, until: take.until },\n ]);\n const against: RegistryRecord = row;\n try {\n const { token } = await deps.registry.compareAndSwap(\n ref,\n against.token,\n { leases },\n held ? { held: against } : undefined,\n );\n return { token, row: against };\n } catch (err) {\n if (isWriteConflictError(err)) {\n row = null;\n held = false;\n await wait(deps, Math.min(CONFLICT_BASE_MS * 2 ** attempt, CONFLICT_CAP_MS));\n continue;\n }\n if (!isTransientError(err)) throw err;\n // No answer: the write may have landed, or may still land. The row says which.\n const now = await deps.registry.get(ref);\n if (heldBy(now, take)) return { token: (now as RegistryRecord).token, row: against };\n if (now !== null && now.token === against.token) {\n if (resends >= UNANSWERED_RESENDS) throw err;\n await wait(deps, UNANSWERED_BASE_MS * 2 ** resends);\n resends += 1;\n unanswered = err;\n }\n row = now;\n held = false;\n if (row === null)\n throw new NotFoundError(`segment \"${ref.segment}\" has no generation to lease`);\n }\n }\n if (unanswered !== undefined) throw unanswered;\n throw new WriteConflictError(\n `lease: contention taking a lease on segment \"${ref.segment}\"${CONTENTION_NEXT_STEP}`,\n );\n}\n\n/**\n * Remove `holder`'s entry, and every entry that has ended, in one write. Idempotent: a row that is gone, destroyed or\n * has no entry for the holder is already released. Throws `WriteConflictError` after {@link LEASE_CAS_ATTEMPTS} lost\n * races and the registry's `TransientError` for a write that stayed unanswered over an unchanged row.\n */\nexport async function releaseLease(\n ref: SegmentRef,\n deps: LeaseDeps,\n holder: string,\n): Promise<void> {\n let resends = 0;\n let unanswered: unknown;\n let row: RegistryRecord | null | undefined;\n for (let attempt = 0; attempt < LEASE_CAS_ATTEMPTS; attempt++) {\n if (row === undefined) row = await deps.registry.get(ref);\n if (row === null || row.status === 'destroyed') return;\n if (!(row.leases ?? []).some((e) => e.holder === holder)) return;\n const against: RegistryRecord = row;\n const keep = liveLeases(against, deps.clock.now()).filter((e) => e.holder !== holder);\n try {\n await deps.registry.compareAndSwap(ref, against.token, { leases: listOf(keep) });\n return;\n } catch (err) {\n if (isWriteConflictError(err)) {\n row = undefined;\n await wait(deps, Math.min(CONFLICT_BASE_MS * 2 ** attempt, CONFLICT_CAP_MS));\n continue;\n }\n if (!isTransientError(err)) throw err;\n const now = await deps.registry.get(ref);\n if (now === null || !(now.leases ?? []).some((e) => e.holder === holder)) return;\n if (now.token === against.token) {\n if (resends >= UNANSWERED_RESENDS) throw err;\n await wait(deps, UNANSWERED_BASE_MS * 2 ** resends);\n resends += 1;\n unanswered = err;\n }\n row = now;\n }\n }\n if (unanswered !== undefined) throw unanswered;\n throw new WriteConflictError(\n `lease: contention releasing a lease on segment \"${ref.segment}\"${CONTENTION_NEXT_STEP}`,\n );\n}\n", "/**\n * The two widths every `.crbm` v1 object is framed by: its front preamble and its footer. Frozen with the rest of the\n * layout in `format.ts`, which re-exports them. They live in a module of their own, with no imports, so that what needs\n * only the smallest size an object can have (the registry's check of a summary's fingerprint) does not bring the\n * format's other constants, or the reader, with it.\n */\n\n/** Front preamble: magic(4) + version_major(1) + version_minor(1) + reserved(2). */\nexport const PREAMBLE_BYTES = 8;\n\n/** Fixed footer size (v1.0). */\nexport const FOOTER_BYTES = 104;\n", "/**\n * Generation metadata: a small, flat record of strings and finite numbers attached to one generation.\n *\n * The rules live here once, for every boundary that meets a value: a caller's input, refused with\n * `ValidationError`, and bytes read back from a tier, refused with `IntegrityError`. The caller passes the error\n * to raise. Pure: no I/O.\n */\nimport type { GenerationMetadata } from './ports';\nimport { isWellFormedString } from './validate';\n\n/** Cap on the canonical JSON of one generation's metadata, in UTF-8 bytes (braces and quotes included). */\nexport const MAX_METADATA_BYTES = 1024;\n/** Cap on one metadata key, in UTF-8 bytes. */\nexport const MAX_METADATA_KEY_BYTES = 128;\n\nconst UTF8 = new TextEncoder();\nconst UTF8_STRICT = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });\nconst utf8Length = (s: string): number => UTF8.encode(s).length;\n\n/**\n * Validate `value` as generation metadata (`GenerationMetadata` in the ports) and return its canonical JSON: RFC 8785\n * (the JSON Canonicalization Scheme) for a flat object of strings and finite numbers. Keys are sorted by UTF-16 code\n * unit, strings are escaped as `JSON.stringify` escapes them, numbers are written as ECMAScript's\n * `Number.prototype.toString` writes them (so `-0` is `0`, and `1e21` is `1e+21`), and there is no whitespace. Key\n * order therefore never changes the bytes, and `tests/golden/metadata-canonical.json` holds vectors a port can check\n * itself against. Both caps are in UTF-8 bytes. The container is an object whose prototype is\n * `Object.prototype` or `null`, holding only enumerable data properties with string keys. `fail` raises the error the\n * boundary calls for. The empty object passes and returns `{}`: whether it may be stored is the caller's rule.\n */\nexport function canonicalMetadataJson(value: unknown, fail: (message: string) => never): string {\n if (value === null || typeof value !== 'object') {\n fail(`metadata must be a plain object (got ${value === null ? 'null' : typeof value})`);\n }\n const proto: unknown = Object.getPrototypeOf(value);\n if (\n Object.prototype.toString.call(value) !== '[object Object]' ||\n (proto !== Object.prototype && proto !== null)\n ) {\n fail('metadata must be a plain object, not an array, a Map, a boxed value or a class instance');\n }\n // Each key with the value the rules checked, so the bytes are serialised from that value and never from a second\n // read, which a proxy could answer differently.\n const entries: Array<[string, string | number]> = [];\n const keys = Reflect.ownKeys(value as object);\n for (const key of keys) {\n if (typeof key !== 'string') fail('metadata keys must be strings, not symbols');\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor === undefined || !('value' in descriptor) || descriptor.enumerable !== true) {\n fail(`metadata key ${JSON.stringify(key)} must be an enumerable data property`);\n }\n if (key.length === 0) fail('metadata keys must be non-empty');\n if (key === '__proto__') fail('metadata may not use the key \"__proto__\"');\n if (!isWellFormedString(key)) fail('metadata keys must be well-formed UTF-16');\n // A UTF-16 unit is at most 3 UTF-8 bytes, so a key that short is under the cap without encoding it.\n if (key.length * 3 > MAX_METADATA_KEY_BYTES) {\n const keyBytes = utf8Length(key);\n if (keyBytes > MAX_METADATA_KEY_BYTES) {\n fail(`metadata key is ${keyBytes}B, over the ${MAX_METADATA_KEY_BYTES}B cap`);\n }\n }\n const v: unknown = descriptor.value;\n if (typeof v === 'string') {\n if (!isWellFormedString(v)) {\n fail(`metadata value of ${JSON.stringify(key)} must be well-formed UTF-16`);\n }\n } else if (typeof v !== 'number' || !Number.isFinite(v)) {\n fail(`metadata value of ${JSON.stringify(key)} must be a string or a finite number`);\n }\n entries.push([key, v]);\n }\n // Keys are unique, so comparing them alone orders the entries by UTF-16 code unit.\n entries.sort(([a], [b]) => (a < b ? -1 : 1));\n const json = `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${JSON.stringify(v)}`).join(',')}}`;\n const bytes = utf8Length(json);\n if (bytes > MAX_METADATA_BYTES) {\n fail(`metadata is ${bytes}B as canonical JSON, over the ${MAX_METADATA_BYTES}B cap`);\n }\n return json;\n}\n\n/**\n * The bytes a generation stores for `value`: its canonical JSON in UTF-8, or `undefined` when it has none (`undefined`\n * or the empty object, which store nothing). Synchronous, so what is stored is what the caller passed at the call,\n * whatever it does with its object afterwards. `fail` raises the boundary's error.\n */\nexport function metadataBytes(\n value: unknown,\n fail: (message: string) => never,\n): Uint8Array | undefined {\n if (value === undefined) return undefined;\n const json = canonicalMetadataJson(value, fail);\n return json === '{}' ? undefined : UTF8.encode(json);\n}\n\n/**\n * A caller's metadata, checked against the rules and copied, so what is stored is what the caller passed at the call,\n * whatever it does with its object afterwards: the frozen record in canonical key order, or `undefined` when there is\n * none (`undefined`, or the empty object, which store nothing). Synchronous. `fail` raises the boundary's error.\n */\nexport function copiedMetadata(\n value: unknown,\n fail: (message: string) => never,\n): GenerationMetadata | undefined {\n const bytes = metadataBytes(value, fail);\n return bytes === undefined ? undefined : metadataFromBytes(bytes, fail);\n}\n\n/**\n * Read metadata back from bytes a tier holds, which are untrusted. They must be at most {@link MAX_METADATA_BYTES},\n * valid UTF-8, and exactly the canonical JSON of a non-empty record, so a stored copy has one spelling: whitespace, a\n * key out of order or listed twice, and a number or an escape `JSON.stringify` would write another way are all\n * refused. Returns a frozen record of its own. `fail` raises the boundary's error.\n */\nexport function metadataFromBytes(\n bytes: Uint8Array,\n fail: (message: string) => never,\n): GenerationMetadata {\n if (bytes.length > MAX_METADATA_BYTES) {\n fail(`metadata is ${bytes.length}B, over the ${MAX_METADATA_BYTES}B cap`);\n }\n let text: string;\n try {\n text = UTF8_STRICT.decode(bytes);\n } catch {\n fail('metadata is not valid UTF-8');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n fail('metadata is not JSON');\n }\n const json = canonicalMetadataJson(parsed, fail);\n if (json === '{}') fail('metadata is empty; a generation without metadata carries none');\n if (json !== text) fail('metadata is not in canonical form');\n return Object.freeze(parsed as GenerationMetadata);\n}\n", "/**\n * An object's fingerprint: its size and its footer's CRC, `<size>:<crc>` in decimal, which names one `.crbm` object. The\n * spelling and its parse are here, apart from the reader, so the registry can check a summary's fingerprint without\n * the reader. Pure: no I/O.\n */\nimport { IntegrityError } from '../errors';\nimport { FOOTER_BYTES, PREAMBLE_BYTES } from './frame';\n\n/** What names an object: its size, then its footer's CRC. One spelling, for an open reader and a footer read alone. */\nexport const sizePart = (size: number): string => `${size}:`;\n/** An object's fingerprint, from its size and its footer's CRC (see `CrbmReader.fingerprint`). */\nexport const fingerprintFor = (size: number, footerCrc: number): string =>\n `${sizePart(size)}${footerCrc}`;\n\n/** A fingerprint as {@link fingerprintFor} spells one: two canonical decimals. */\nconst FINGERPRINT = /^(0|[1-9]\\d*):(0|[1-9]\\d*)$/;\n\n/**\n * A fingerprint taken apart, or `undefined` for text that is not one an object can have: a size that is a safe integer\n * no smaller than a `.crbm` preamble and footer, and a footer CRC that fits in 32 bits. For a row's summary, which\n * names its object by it and reports the size from it.\n */\nexport function fingerprintParts(\n fingerprint: unknown,\n): { readonly size: number; readonly footerCrc: number } | undefined {\n const match = typeof fingerprint === 'string' ? FINGERPRINT.exec(fingerprint) : null;\n if (match === null) return undefined;\n const size = Number(match[1]);\n const footerCrc = Number(match[2]);\n if (!Number.isSafeInteger(size) || size < PREAMBLE_BYTES + FOOTER_BYTES) return undefined;\n if (footerCrc > 0xffff_ffff) return undefined;\n return { size, footerCrc };\n}\n\n/**\n * The footer CRC of a fingerprint a writer or a reader produced, which a row's ledger records beside the generation.\n * Throws {@link IntegrityError} for text that is not a fingerprint, which neither produces.\n */\nexport function footerCrcOf(fingerprint: string): number {\n const parts = fingerprintParts(fingerprint);\n if (parts === undefined) {\n throw new IntegrityError(`not an object's fingerprint: ${String(fingerprint).slice(0, 64)}`);\n }\n return parts.footerCrc;\n}\n\n/**\n * A fingerprint spelled short, for a key a read builds on every chunk: its size and its footer's CRC in base 36,\n * `<size>.<crc>`. Two compact spellings are equal exactly when the fingerprints are.\n */\nexport function compactFingerprint(fingerprint: string): string {\n const colon = fingerprint.indexOf(':');\n const size = Number(fingerprint.slice(0, colon));\n const crc = Number(fingerprint.slice(colon + 1));\n return `${size.toString(36)}.${crc.toString(36)}`;\n}\n", "/**\n * A generation's summary on its registry row: how a writer builds it, how a reader opens it, and how it is held\n * against the object it describes.\n *\n * The row carries a cached description of the current generation, `{ generation, cardinality, fingerprint, tailBytes,\n * metadata? }`, written by the same compare-and-swap that moves the pointer. The fingerprint names the generation's\n * object, by its size and footer checksum, as `CrbmReader.fingerprint` does, and `tailBytes` is how much of the object's\n * end one open reads. On a cleartext segment the values are in the clear. On an encrypted one the row holds\n * `{ generation, sealed }` instead: the cardinality as a fixed-width little-endian u64, the object's size as a u64 and\n * its footer checksum as a u32, then `tailBytes` as a u32, then the metadata's canonical JSON if there is any, sealed\n * under the segment's data key with the summary scope of the associated data, which binds it to its namespace, segment\n * and generation. The numbers are fixed-width so the ciphertext's length reveals only the metadata's size, never how\n * many digits the count or the size has, and `tailBytes`, which tracks the number of chunks, is sealed for the same\n * reason the size is. Pure: no I/O.\n *\n * The generation's `.crbm` object stays the truth, and the summary is a copy of it. {@link summaryAgrees} is the\n * comparison of one with the other, and the fingerprint is what a reader holds every object it opens against.\n */\nimport type { Aead } from './crypto';\nimport { aadFor } from './crypto';\nimport { U32_MAX } from './bit-route';\nimport { IntegrityError, isIntegrityError } from './errors';\nimport { fingerprintFor, fingerprintParts } from './crbm/fingerprint';\nimport { FOOTER_BYTES, PREAMBLE_BYTES } from './crbm/frame';\nimport {\n MAX_METADATA_BYTES,\n canonicalMetadataJson,\n metadataBytes,\n metadataFromBytes,\n} from './metadata';\nimport type {\n ClearRegistrySummary,\n GenerationMetadata,\n RegistryRecord,\n RegistrySummary,\n SealedRegistrySummary,\n SegmentRef,\n} from './ports';\n\n/** The 12-byte nonce and 16-byte tag AES-256-GCM frames a sealed blob with, which the `.crbm` format fixes too. */\nconst NONCE_BYTES = 12;\nconst TAG_BYTES = 16;\n/** The cardinality, sealed as a little-endian u64. */\nconst COUNT_BYTES = 8;\n/** The object's size, sealed as a little-endian u64, then its footer checksum and its `tailBytes`, each a little-endian u32. */\nconst SIZE_BYTES = 8;\nconst CRC_BYTES = 4;\nconst TAIL_BYTES = 4;\n/** The fixed part of a sealed summary's plaintext: the count, the fingerprint and `tailBytes`. */\nconst FIXED_BYTES = COUNT_BYTES + SIZE_BYTES + CRC_BYTES + TAIL_BYTES;\n/** A generation holds at most every 32-bit id. */\nexport const MAX_SUMMARY_CARDINALITY = U32_MAX + 1;\n\n/**\n * The most a summary's `tailBytes` can be: the reader's own default caps on what an open fetches, an index of at most\n * 8 MiB, an extension block of at most its cap and its trailer, and the footer. The library's writer cannot reach it. A\n * reader can report more for an object it did not write, since it accepts bytes between the index and the footer. A\n * literal, so the registry validators that use it do not import the format module; a test holds it to the sum of the\n * format's constants.\n */\nexport const MAX_TAIL_BYTES = 8_392_820;\n\n/** Whether `tailBytes` is one a summary of an object of `size` bytes can carry. */\nexport function tailBytesFit(tailBytes: unknown, size: number): boolean {\n return (\n typeof tailBytes === 'number' &&\n Number.isInteger(tailBytes) &&\n tailBytes >= FOOTER_BYTES &&\n tailBytes <= size - PREAMBLE_BYTES &&\n tailBytes <= MAX_TAIL_BYTES\n );\n}\n\n/**\n * What a summary says about a generation: its id count, and its metadata when it has any. `tailBytes`, when given, is\n * the bytes of the object's end one open reads.\n */\nexport interface GenerationDescription {\n readonly cardinality: number;\n readonly metadata?: GenerationMetadata | undefined;\n readonly tailBytes?: number | undefined;\n}\n\n/**\n * What a row's summary says: the generation's description, the fingerprint of the object it describes and the\n * bytes of that object's end one open reads.\n */\nexport interface SummaryDescription extends GenerationDescription {\n readonly fingerprint: string;\n readonly tailBytes: number;\n}\n\n/** The size of the object a fingerprint names, in bytes: what `stat()` reports from a row's summary. */\nexport function sizeOfFingerprint(fingerprint: string): number {\n const parts = fingerprintParts(fingerprint);\n if (parts === undefined)\n throw new IntegrityError('registry record summary: a malformed fingerprint');\n return parts.size;\n}\n\nconst BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/** Padded standard base64. */\nfunction toBase64(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i += 3) {\n const a = bytes[i]!;\n const b = bytes[i + 1];\n const c = bytes[i + 2];\n out += BASE64[a >> 2]! + BASE64[((a & 3) << 4) | ((b ?? 0) >> 4)]!;\n out += b === undefined ? '=' : BASE64[((b & 15) << 2) | ((c ?? 0) >> 6)]!;\n out += c === undefined ? '=' : BASE64[c & 63]!;\n }\n return out;\n}\n\n/** The bytes of padded standard base64, or `undefined` for text that is not. */\nfunction fromBase64(text: string): Uint8Array | undefined {\n if (text.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(text)) return undefined;\n const pad = text.endsWith('==') ? 2 : text.endsWith('=') ? 1 : 0;\n const out = new Uint8Array((text.length / 4) * 3 - pad);\n let o = 0;\n for (let i = 0; i < text.length; i += 4) {\n const n =\n (BASE64.indexOf(text[i]!) << 18) |\n (BASE64.indexOf(text[i + 1]!) << 12) |\n (Math.max(BASE64.indexOf(text[i + 2]!), 0) << 6) |\n Math.max(BASE64.indexOf(text[i + 3]!), 0);\n if (o < out.length) out[o++] = (n >> 16) & 255;\n if (o < out.length) out[o++] = (n >> 8) & 255;\n if (o < out.length) out[o++] = n & 255;\n }\n return out;\n}\n\n/**\n * The clear summary of a generation on a cleartext segment, naming its object by `fingerprint`. `metadata` is left off\n * when there is none.\n */\nexport function clearSummary(\n generation: number,\n cardinality: number,\n fingerprint: string,\n tailBytes: number,\n metadata?: GenerationMetadata,\n): ClearRegistrySummary {\n return metadata === undefined || Object.keys(metadata).length === 0\n ? { generation, cardinality, fingerprint, tailBytes }\n : { generation, cardinality, fingerprint, tailBytes, metadata };\n}\n\n/**\n * The sealed summary of a generation on an encrypted segment: the cardinality as a u64, the object's size as a u64,\n * its footer checksum as a u32 and its `tailBytes` as a u32, then the metadata's canonical JSON, sealed under `aead` and\n * bound to `ref` and `generation`.\n */\nexport function sealSummary(\n aead: Aead,\n ref: SegmentRef,\n generation: number,\n cardinality: number,\n fingerprint: string,\n tailBytes: number,\n metadata?: GenerationMetadata,\n): SealedRegistrySummary {\n const meta = metadataBytes(metadata, (message) => {\n throw new IntegrityError(`summary metadata: ${message}`);\n });\n const parts = fingerprintParts(fingerprint);\n if (parts === undefined) throw new IntegrityError('summary: a malformed fingerprint');\n const plain = new Uint8Array(FIXED_BYTES + (meta?.length ?? 0));\n const view = new DataView(plain.buffer);\n view.setBigUint64(0, BigInt(cardinality), true);\n view.setBigUint64(COUNT_BYTES, BigInt(parts.size), true);\n view.setUint32(COUNT_BYTES + SIZE_BYTES, parts.footerCrc, true);\n view.setUint32(COUNT_BYTES + SIZE_BYTES + CRC_BYTES, tailBytes, true);\n if (meta !== undefined) plain.set(meta, FIXED_BYTES);\n const { nonce, ciphertext, tag } = aead.seal(plain, aadFor(ref, generation, 'summary'));\n const framed = new Uint8Array(nonce.length + ciphertext.length + tag.length);\n framed.set(nonce, 0);\n framed.set(ciphertext, nonce.length);\n framed.set(tag, nonce.length + ciphertext.length);\n return { generation, sealed: toBase64(framed) };\n}\n\n/**\n * What a sealed summary says, opened with `aead` under the summary scope of `ref` and the summary's own generation.\n * The bytes are untrusted: a blob that is not base64, is the wrong size, fails its authentication (tampered, or moved\n * from another generation's row), or holds a count outside 0 to 2^32, a size no object can have, or metadata that\n * breaks the rules, is an {@link IntegrityError}.\n */\nexport function openSummary(\n aead: Aead,\n ref: SegmentRef,\n summary: SealedRegistrySummary,\n): SummaryDescription {\n const fail = (message: string): never => {\n throw new IntegrityError(`registry record summary: ${message}`);\n };\n const framed = fromBase64(summary.sealed);\n const framing = NONCE_BYTES + TAG_BYTES;\n if (\n framed === undefined ||\n framed.length < framing + FIXED_BYTES ||\n framed.length > framing + FIXED_BYTES + MAX_METADATA_BYTES\n ) {\n fail(\n 'the sealed summary is not a nonce, a count, a fingerprint, a tail size, up to 1 KiB of metadata and a tag',\n );\n }\n const bytes = framed as Uint8Array;\n let plain: Uint8Array;\n try {\n plain = aead.open(\n {\n nonce: bytes.subarray(0, NONCE_BYTES),\n ciphertext: bytes.subarray(NONCE_BYTES, bytes.length - TAG_BYTES),\n tag: bytes.subarray(bytes.length - TAG_BYTES),\n },\n aadFor(ref, summary.generation, 'summary'),\n );\n } catch (err) {\n if (!isIntegrityError(err)) throw err;\n return fail(\n 'the sealed summary does not open: tampered bytes, or a summary moved from another generation',\n );\n }\n if (plain.length < FIXED_BYTES)\n fail('the sealed summary is shorter than its count, fingerprint and tail size');\n const view = new DataView(plain.buffer, plain.byteOffset, plain.byteLength);\n const count = view.getBigUint64(0, true);\n if (count > BigInt(MAX_SUMMARY_CARDINALITY)) fail(`cardinality ${count} is outside 0 to 2^32`);\n const size = view.getBigUint64(COUNT_BYTES, true);\n const fingerprint = fingerprintFor(Number(size), view.getUint32(COUNT_BYTES + SIZE_BYTES, true));\n if (size > BigInt(Number.MAX_SAFE_INTEGER) || fingerprintParts(fingerprint) === undefined) {\n fail(`the object size ${size} is not one a .crbm object can have`);\n }\n const tailBytes = view.getUint32(COUNT_BYTES + SIZE_BYTES + CRC_BYTES, true);\n if (!tailBytesFit(tailBytes, Number(size))) {\n fail(`the tail size ${tailBytes} is not one a .crbm object of ${size} bytes can have`);\n }\n const metadata =\n plain.length === FIXED_BYTES ? undefined : metadataFromBytes(plain.subarray(FIXED_BYTES), fail);\n return { cardinality: Number(count), metadata, fingerprint, tailBytes };\n}\n\n/**\n * What a row's summary says of its current generation, or `undefined` when it says nothing a reader may use. It is\n * used only for the generation it names, on an active row, and in the shape the row's keys call for: clear on a row\n * with no wrapped keys, sealed on a row with them. A sealed one is opened with `aead`, and is unusable without it,\n * or when it does not open, so a summary a tamperer moved or rewrote is never believed; a clear one whose fingerprint\n * names no object is unusable too. Never throws for a bad summary: the row's copy is a cache, and a copy that cannot be\n * used is a copy that is not there.\n */\nexport function usableSummary(\n ref: SegmentRef,\n row: Pick<RegistryRecord, 'summary' | 'status' | 'currentGen' | 'wrappedDeks'>,\n aead: Aead | undefined,\n): SummaryDescription | undefined {\n const summary: RegistrySummary | undefined = row.summary;\n if (summary === undefined || row.status !== 'active' || summary.generation !== row.currentGen) {\n return undefined;\n }\n const keyed = row.wrappedDeks !== undefined && row.wrappedDeks.length > 0;\n if ('sealed' in summary) {\n if (!keyed || aead === undefined) return undefined;\n try {\n return openSummary(aead, ref, summary);\n } catch (err) {\n if (isIntegrityError(err)) return undefined;\n throw err;\n }\n }\n if (keyed) return undefined;\n // A shipped registry refuses a clear summary whose fingerprint names no object, or whose tail size no object of that\n // size can have, when it reads the row; a registry of your own may hand one over, and it is not used, so no read\n // compares it with an object's.\n const parts = fingerprintParts(summary.fingerprint);\n if (parts === undefined || !tailBytesFit(summary.tailBytes, parts.size)) return undefined;\n return {\n cardinality: summary.cardinality,\n metadata: summary.metadata,\n fingerprint: summary.fingerprint,\n tailBytes: summary.tailBytes,\n };\n}\n\n/**\n * The canonical form of a metadata record, or `undefined` for none. The empty record is none: a generation without\n * metadata carries none, and the two are never told apart.\n */\nfunction canonicalOrNone(metadata: GenerationMetadata | undefined): string | undefined {\n if (metadata === undefined) return undefined;\n const json = canonicalMetadataJson(metadata, (message) => {\n throw new IntegrityError(`metadata: ${message}`);\n });\n return json === '{}' ? undefined : json;\n}\n\n/**\n * Whether a summary's description of a generation is what its object holds: the same id count and the same metadata,\n * compared in canonical form, so key order never matters, and the same `tailBytes` when both say one (a cold open sizes\n * its tail read from the row's, so a number the object does not bear out is not believed again). A summary with\n * metadata over an object with none, and the reverse, disagree: whether an encrypted object's metadata block is present\n * is not authenticated (stripping it needs no key), so the row's sealed copy is what a missing block is held against.\n */\nexport function summaryAgrees(\n summary: GenerationDescription,\n object: GenerationDescription,\n): boolean {\n return (\n summary.cardinality === object.cardinality &&\n canonicalOrNone(summary.metadata) === canonicalOrNone(object.metadata) &&\n (summary.tailBytes === undefined ||\n object.tailBytes === undefined ||\n summary.tailBytes === object.tailBytes)\n );\n}\n\n/**\n * The metadata an erasure carries into its rewrite of a generation: the object's own, except that an object with none\n * whose row's authenticated summary of the same generation has some gets the row's. Whether an encrypted object has a\n * metadata block is not authenticated, so a block stripped from one reads as none, and the sealed summary on the row is\n * the one copy that says there was a block; carrying it keeps the rewrite from erasing the record of what it dropped.\n * Pass `authenticated` only for a summary that was opened (a clear one has no more authority than the block it sits\n * beside). Never refuses. The erasure reaches this with a stripped block only past a fingerprint forged to match the\n * row's, since stripping the block changes the object's size and the open is held to the row's fingerprint.\n */\nexport function metadataToCarry(\n object: GenerationMetadata | undefined,\n authenticated: GenerationDescription | undefined,\n): GenerationMetadata | undefined {\n const empty = (metadata: GenerationMetadata | undefined): boolean =>\n metadata === undefined || Object.keys(metadata).length === 0;\n return empty(object) && authenticated !== undefined && !empty(authenticated.metadata)\n ? authenticated.metadata\n : object;\n}\n\n/**\n * The summary of a generation of `ref`, describing the object `description.fingerprint` names, clear or sealed under\n * `aead` as the segment's keys call for. `undefined` when the object's `tailBytes` is above {@link MAX_TAIL_BYTES}: a\n * reader accepts bytes between an object's index and its footer, so an object this library did not write can report a\n * tail the row cannot record, and a row is legal without a summary (a read then opens the object with the default tail).\n * The description's size, footer checksum and `tailBytes` must all come from the one object.\n */\nexport function summaryOf(\n ref: SegmentRef,\n generation: number,\n description: SummaryDescription,\n aead: Aead | undefined,\n): RegistrySummary | undefined {\n const { cardinality, fingerprint, tailBytes, metadata } = description;\n if (tailBytes > MAX_TAIL_BYTES) return undefined;\n return aead === undefined\n ? clearSummary(generation, cardinality, fingerprint, tailBytes, metadata)\n : sealSummary(aead, ref, generation, cardinality, fingerprint, tailBytes, metadata);\n}\n\n/**\n * {@link summaryOf} for an object this library wrote, whose tail is within {@link MAX_TAIL_BYTES} by construction (its\n * index holds at most 65,536 entries and its extension block at most 4 KiB). Throws {@link IntegrityError} for a tail\n * that is not, which the writer cannot produce.\n */\nexport function ownSummary(\n ref: SegmentRef,\n generation: number,\n description: SummaryDescription,\n aead: Aead | undefined,\n): RegistrySummary {\n const summary = summaryOf(ref, generation, description, aead);\n if (summary === undefined) {\n throw new IntegrityError(\n `the object written for generation ${generation} of \"${ref.segment}\" has a tail of ${description.tailBytes} ` +\n `bytes, above the ${MAX_TAIL_BYTES} a summary records`,\n );\n }\n return summary;\n}\n", "/** The comparator that sorts numbers smallest first, which `Array.prototype.sort` does not do by default. */\nexport const ascending = (a: number, b: number): number => a - b;\n", "/**\n * The generations a segment's row knows it published: its known-generations ledger, `knownGens`. Each entry is a\n * generation's number and the footer checksum of its object, in the order the generations were made current, oldest\n * first and the current one last. The kept window a load collects by name is derived from it: each publish chooses\n * the most recently current of the entries numbered below its own generation, so a load deletes what its publish pushed\n * out of that window by name instead of listing the bucket.\n *\n * The record is a cache of what a listing would keep, never an inventory of the bucket: a generation can be named here\n * and gone from the bucket (a lifecycle rule took it, or a load with a smaller `keep` collected it), and the bucket\n * can hold one the row does not name. A row with no ledger is correct, and its load lists. A patch that moves the\n * pointer without naming the ledger drops it (see `applyRegistryPatch`), so a writer that forgets the ledger leaves a\n * row that lists, never one that vouches for a generation it should not. Pure: no I/O, time or randomness.\n */\nimport { ascending } from './order';\nimport { fingerprintParts } from './crbm/fingerprint';\nimport type { KnownGeneration, RegistryRecord } from './ports';\n\n/**\n * The most generations a load that collects by name records as its window. A `keep` above it collects by listing.\n */\nexport const MAX_KEPT_GENERATIONS = 64;\n\n/**\n * A writer keeps entries that nothing protects and no lease holds only while the ledger holds fewer than this many.\n */\nexport const KNOWN_FILL = 128;\n\n/** The most entries a writer writes, and the most the shared validator accepts at a write. */\nexport const MAX_KNOWN_GENERATIONS = 192;\n\n/** The most entries a stored row may hold: twice what a writer writes. */\nexport const MAX_STORED_KNOWN_GENERATIONS = 384;\n\n/**\n * The row's ledger when a collection or a rollback may rely on it: present and not empty, on an active row with a\n * pointer, its last entry the pointer, and, where the row's summary is in the clear and describes that generation, its\n * checksum the one the summary's fingerprint carries. A well-formed ledger that disagrees with its row is read but not\n * used (the row counts as one with no ledger), as a summary that names another generation is.\n */\nexport function usableKnownGens(\n record: RegistryRecord | null,\n): readonly KnownGeneration[] | undefined {\n const known = record?.knownGens;\n if (\n record === null ||\n known === undefined ||\n known.length === 0 ||\n record.status !== 'active' ||\n record.currentGen === null\n ) {\n return undefined;\n }\n const last = known[known.length - 1]!;\n if (last.generation !== record.currentGen) return undefined;\n const summary = record.summary;\n if (\n summary !== undefined &&\n summary.generation === record.currentGen &&\n 'fingerprint' in summary &&\n fingerprintParts(summary.fingerprint)?.footerCrc !== last.footerCrc\n ) {\n return undefined;\n }\n return known;\n}\n\n/**\n * The generations the row keeps as its window: the numbers of the usable ledger's entries below the pointer, in the order\n * they were made current, or `undefined` when the ledger is not usable. A collection compares against these. An entry\n * numbered above the pointer is one a rollback left; no collection can take it, so it is no part of the window.\n */\nexport function windowOf(record: RegistryRecord | null): readonly number[] | undefined {\n const known = usableKnownGens(record);\n if (known === undefined) return undefined;\n const pointer = record!.currentGen!;\n return known.filter((e) => e.generation < pointer).map((e) => e.generation);\n}\n\n/**\n * Whether the row's ledger is a window a load with a small `keep` can extend: usable, and naming no more than\n * {@link MAX_KEPT_GENERATIONS} generations below the pointer that no live lease holds. A ledger carried through\n * publishes with a larger `keep` (`*Into`, `materializeMany`) names up to 127, and a count by a small `keep` would keep\n * fewer than it names, so the next small-`keep` load collects by listing instead of by name, over the same ledger. A\n * generation held only for a lease is no part of the window and does not count toward the limit.\n */\nexport function carriesWindow(record: RegistryRecord | null, leased: ReadonlySet<number>): boolean {\n const below = windowOf(record);\n return below !== undefined && below.filter((g) => !leased.has(g)).length <= MAX_KEPT_GENERATIONS;\n}\n\n/**\n * How many generations below its own a publish vouches for at most: what the writer cap leaves beside the new\n * generation and the 64 generations live leases can hold.\n */\nexport const KNOWN_SPAN = 127;\n\n/** Which generations below a new pointer a grace window holds, and which it lets go: both ascending. */\ninterface KeptWindow {\n readonly kept: number[];\n readonly evict: number[];\n}\n\n/**\n * The generations below a new pointer that a grace window of `keep` holds, out of `below`, when no ledger says which\n * were made current most recently: the generation the publish superseded first, when it is among them, then the newest\n * of the rest by number. When it is not among them (no generation was current, or its object has gone from the bucket),\n * the newest `keep`.\n *\n * The superseded generation is the one reads were on until the publish, and, after a rollback, the one the operator\n * restored, which a pin taken since reads, and the one to roll back to if the new load is bad too. The generations a\n * rollback moved away from are newer by number, so a window by number alone would keep those and delete it. The window\n * a listing keeps over a row with no usable ledger comes from here, and so does a ledger's first window\n * (`ledger-seed.ts`); once the row has a ledger, its order says which were made current most recently.\n */\nexport function keptWindow(\n below: readonly number[],\n superseded: number | undefined,\n keep: number,\n): KeptWindow {\n const oldestFirst = [...below].sort(ascending);\n const first =\n keep > 0 && superseded !== undefined && oldestFirst.includes(superseded)\n ? superseded\n : undefined;\n const held = new Set<number>(first === undefined ? [] : [first]);\n // The rest of the window, newest first.\n for (let i = oldestFirst.length - 1, room = keep - held.size; i >= 0 && room > 0; i--) {\n if (oldestFirst[i] === first) continue;\n held.add(oldestFirst[i]!);\n room -= 1;\n }\n return {\n kept: oldestFirst.filter((g) => held.has(g)),\n evict: oldestFirst.filter((g) => !held.has(g)),\n };\n}\n\n/**\n * `known`, held to the cap, in the same order. It always keeps the entries numbered in `protect`, then the ones numbered\n * in `leased`, most recently current first, up to {@link MAX_KNOWN_GENERATIONS}, then the rest, most recently current\n * first, while the ledger holds fewer than {@link KNOWN_FILL}. So a protected or leased entry is never dropped for room,\n * and an unprotected one only when the ledger is full. \"Most recently current\" is the end of the list.\n */\nexport function capKnown(\n known: readonly KnownGeneration[],\n protect: ReadonlySet<number>,\n leased: ReadonlySet<number> = new Set(),\n): KnownGeneration[] {\n const keep = new Set<number>();\n for (const e of known) if (protect.has(e.generation)) keep.add(e.generation);\n for (let i = known.length - 1; i >= 0 && keep.size < MAX_KNOWN_GENERATIONS; i--) {\n if (leased.has(known[i]!.generation)) keep.add(known[i]!.generation);\n }\n for (let i = known.length - 1; i >= 0 && keep.size < KNOWN_FILL; i--)\n keep.add(known[i]!.generation);\n return known.filter((e) => keep.has(e.generation));\n}\n\n/**\n * `known`, held to the cap for a rollback's insert, in the same order. It keeps the entries numbered in `protect`, then the\n * most recently current others that no lease holds while fewer than {@link KNOWN_FILL} unleased entries are kept, then\n * the leased ones, most recently current first, up to {@link MAX_KNOWN_GENERATIONS}. A leased entry is an extra, as it is\n * for a publish: an insert drops what the fill leaves out of the unleased entries, one entry for one inserted, and never a\n * leased one while the cap has room.\n */\nfunction capInsert(\n known: readonly KnownGeneration[],\n protect: ReadonlySet<number>,\n leased: ReadonlySet<number>,\n): KnownGeneration[] {\n const keep = new Set<number>();\n let unleased = 0;\n for (const e of known) {\n if (!protect.has(e.generation)) continue;\n keep.add(e.generation);\n if (!leased.has(e.generation)) unleased += 1;\n }\n for (let i = known.length - 1; i >= 0 && unleased < KNOWN_FILL; i--) {\n const g = known[i]!.generation;\n if (keep.has(g) || leased.has(g)) continue;\n keep.add(g);\n unleased += 1;\n }\n for (let i = known.length - 1; i >= 0 && keep.size < MAX_KNOWN_GENERATIONS; i--) {\n if (leased.has(known[i]!.generation)) keep.add(known[i]!.generation);\n }\n return known.filter((e) => keep.has(e.generation));\n}\n\n/** `known` with `entry` made the most recent: any entry for its generation removed, and the entry added last. */\nexport function makeCurrent(\n known: readonly KnownGeneration[],\n entry: KnownGeneration,\n): KnownGeneration[] {\n return [...known.filter((e) => e.generation !== entry.generation), entry];\n}\n\n/** What a publish of a generation writes into the row, and which names it pushes out of the window. */\nexport interface KnownAfter {\n /** The ledger to write: the generation published is its last entry. */\n readonly known: readonly KnownGeneration[];\n /** The window as numbers to collect by name, or `undefined` to collect by listing. */\n readonly list: readonly number[] | undefined;\n /** The generations the window no longer keeps, ascending: the names to delete. */\n readonly evict: readonly number[];\n}\n\n/**\n * What a publish of `generation` (its object's footer checksum `footerCrc`) over `prev` writes into the row.\n *\n * The ledger is in the order the generations were made current, so the order says which were current most recently.\n * That ranks the window, and the window is drawn from the entries numbered below the new generation only: collection\n * can only take generations numbered below the pointer. The window is the `keep` most recently current of them (at most\n * {@link KNOWN_SPAN}), so the generation the publish superseded, the ledger's last entry, comes first, and after a\n * rollback the ones the operator restored outrank the ones the rollback moved away from.\n *\n * What it writes, in the order the entries were made current and the new generation last:\n *\n * - the window;\n * - the entries below the new generation that `leased` names (a generation a live lease holds stays known, so it stays a\n * rollback target while the lease lives), whatever `keep` says;\n * - the entries numbered above the new generation, which a rollback left and a load numbered under: they are carried and\n * never evicted, and take no slot of `keep`, while the ledger holds fewer than {@link KNOWN_FILL} entries (see\n * {@link capKnown});\n * - the new generation. An entry already numbered `generation` is a stale one (its object went outside the ledger) and\n * is replaced.\n *\n * `evict` is the entries below the new generation that it leaves out, ascending: never a name at or above the new\n * generation. With a `keep` of at most {@link MAX_KEPT_GENERATIONS} the publish collects by name, so `list` is the\n * generations of the ledger below the new one; above that, or with no `keep`, `list` is `undefined` and `evict` empty, and\n * a load lists. A row with a pointer and no usable ledger writes the new generation alone and lists, unless the caller\n * passes a `seed` (see `ledger-seed.ts`): the window a count keeps, read from the bucket, then the new generation, and\n * the publish collects by that count. A publish that clears leases is an erasure's rewrite, which deletes every older\n * generation, so its ledger is the new generation alone.\n */\nexport function nextKnown(\n prev: RegistryRecord | null,\n generation: number,\n footerCrc: number,\n keep: number | undefined,\n options: {\n readonly clearsLeases?: boolean;\n readonly seed?: readonly KnownGeneration[];\n readonly leased?: ReadonlySet<number>;\n } = {},\n): KnownAfter {\n const self: KnownGeneration = { generation, footerCrc };\n const clears = options.clearsLeases === true;\n const byName = keep !== undefined && keep <= MAX_KEPT_GENERATIONS;\n if (options.seed !== undefined && !clears) {\n // The window a count keeps, read from the bucket: the ledger names it, and the publish collects by that count.\n const seed = options.seed.filter((e) => e.generation !== generation);\n const protect = new Set([...seed.map((e) => e.generation), generation]);\n return {\n known: capKnown([...seed, self], protect, options.leased ?? new Set<number>()),\n list: undefined,\n evict: [],\n };\n }\n const found = usableKnownGens(prev);\n if (found === undefined && prev !== null && prev.currentGen !== null) {\n // A row that dropped its ledger, or one that disagrees with its row: nothing says what it kept, so a load lists.\n return { known: [self], list: undefined, evict: [] };\n }\n const all = found ?? [];\n const below = all.filter((e) => e.generation < generation);\n const above = clears ? [] : all.filter((e) => e.generation > generation);\n const span = clears ? 0 : Math.min(keep ?? Number.MAX_SAFE_INTEGER, KNOWN_SPAN);\n const vouch = new Set((span === 0 ? [] : below.slice(-span)).map((e) => e.generation));\n const leased = clears ? new Set<number>() : (options.leased ?? new Set<number>());\n const held = below.filter((e) => !vouch.has(e.generation) && leased.has(e.generation));\n const chosen = new Set([\n ...vouch,\n ...held.map((e) => e.generation),\n ...above.map((e) => e.generation),\n ]);\n const known = capKnown(\n [...all.filter((e) => chosen.has(e.generation)), self],\n new Set([...vouch, generation]),\n leased,\n );\n // Over a ledger too wide for a small `keep` to extend by name (a carried run of larger keeps), the publish still\n // writes the window it draws from the ledger's order, the leased entries and those above; the load lists to collect,\n // counting the ledger's names first and sparing every name the row knows.\n const wide = !clears && found !== undefined && !carriesWindow(prev, leased);\n if (!byName || wide) return { known, list: undefined, evict: [] };\n const named = new Set(known.map((e) => e.generation));\n return {\n known,\n list: known\n .filter((e) => e.generation < generation)\n .map((e) => e.generation)\n .sort(ascending),\n evict: below\n .filter((e) => !named.has(e.generation))\n .map((e) => e.generation)\n .sort(ascending),\n };\n}\n\n/**\n * The ledger a rollback onto `target` writes over `prev`: the ledger it found with the target moved to the end, as the\n * most recently current. A rollback never starts a ledger: over a row with no usable ledger it writes none, and the\n * next publish seeds one. A target the ledger did not name\n * is an insert, and the ledger it makes is held to the cap with the target and the generation the rollback leaves\n * protected; a known target's ledger is written as read, unless another build wrote one that is past the writer's cap.\n */\nexport function rollbackKnown(\n prev: RegistryRecord,\n target: KnownGeneration,\n): readonly KnownGeneration[] | undefined {\n const found = usableKnownGens(prev);\n if (found === undefined) return undefined;\n const moved = makeCurrent(found, target);\n const inserted = !found.some((e) => e.generation === target.generation);\n if (!inserted && moved.length <= MAX_KNOWN_GENERATIONS) return moved;\n return capInsert(moved, new Set([target.generation, prev.currentGen!]), leasedByRow(prev));\n}\n\n/** Whether two rows' ledgers (`knownGens`, or the absence of one) are the same entries in the same order. */\nexport function sameKnownGens(\n a: readonly KnownGeneration[] | undefined,\n b: readonly KnownGeneration[] | undefined,\n): boolean {\n if (a === undefined || b === undefined) return a === b;\n return (\n a.length === b.length &&\n a.every((e, i) => e.generation === b[i]!.generation && e.footerCrc === b[i]!.footerCrc)\n );\n}\n\n/**\n * The row's ledger with the entries numbered in `doomed` removed, which a write that is about to delete those\n * generations makes first: the entries left keep their order, and the current generation is never removed (the ledger\n * must end with it). Another build's ledger past the writer's cap is held to it, with the current generation protected\n * and the generations the row's leases name kept. `undefined` for a row with no usable ledger, which names nothing to\n * remove.\n */\nexport function pruneKnown(\n record: RegistryRecord,\n doomed: ReadonlySet<number>,\n): readonly KnownGeneration[] | undefined {\n const found = usableKnownGens(record);\n if (found === undefined) return undefined;\n const rest = found.filter((e) => e.generation === record.currentGen || !doomed.has(e.generation));\n if (rest.length <= MAX_KNOWN_GENERATIONS) return rest;\n return capKnown(rest, new Set([record.currentGen!]), leasedByRow(record));\n}\n\n/**\n * The ledger that puts a row back as it was, for the undo of a rollback: the row's own when it is usable (the\n * generation it left is its last entry), held to the writer's cap when another build wrote one past it, with the\n * generation the undo leaves and the one it moves from protected; `undefined` for a row that had none to put back.\n */\nexport function describingKnown(\n record: RegistryRecord,\n movedTo: number,\n): readonly KnownGeneration[] | undefined {\n const found = usableKnownGens(record);\n if (found === undefined || found.length <= MAX_KNOWN_GENERATIONS) return found;\n return capKnown(found, new Set([record.currentGen!, movedTo]), leasedByRow(record));\n}\n\n/**\n * Whether the ledger is full: it names at least {@link KNOWN_FILL} generations, which is when a writer may have let an\n * older one go (a publish vouches for at most {@link KNOWN_SPAN} below its own, and an inserting rollback drops an entry\n * once 128 that no lease holds are named). Leased entries do not switch it off: a lease on an entry inside the span\n * leaves the ledger as full as it was. Past the least recently current entry of a full ledger, a rollback can no longer\n * tell a generation the row forgot from one it never knew, so it judges a target numbered below that entry as it did\n * before the ledger existed.\n */\nexport function isFullLedger(known: readonly KnownGeneration[]): boolean {\n return known.length >= KNOWN_FILL;\n}\n\n/**\n * The number a target below the pointer is judged against on a full ledger: the least recently current entry that no\n * lease entry of the row names (live or ended: a rollback has no clock). A leased entry stays in the ledger for its lease,\n * however far the window has moved on since, so it does not mark where the ledger stopped remembering; the first entry no\n * lease holds does. A ledger whose every entry is leased is judged against its first entry.\n */\nexport function fallbackBound(record: RegistryRecord, known: readonly KnownGeneration[]): number {\n const leased = leasedByRow(record);\n return (known.find((e) => !leased.has(e.generation)) ?? known[0]!).generation;\n}\n\n/**\n * Every generation the row's lease entries name, live or ended: a rollback has no clock to tell them apart, and this build\n * writes at most 64 entries, so holding them all fits the writer's cap. An ended one leaves the ledger at the next publish.\n */\nfunction leasedByRow(record: RegistryRecord): ReadonlySet<number> {\n return new Set((record.leases ?? []).map((e) => e.generation));\n}\n", "/**\n * The shape of a row's known-generations ledger (`knownGens`), in one place. A registry holds a row to it when it writes\n * and when it reads back, and `checkConsistency` holds a row to it before it reads or walks a ledger a registry of your\n * own handed back, so the two cannot part on what a ledger is. Pure: no I/O, time or randomness.\n */\n\nconst ENTRY_KEYS: readonly string[] = ['generation', 'footerCrc'];\n\n/**\n * Why `value` is not a ledger, or `undefined` when it is one (an absent ledger, `undefined`, passes: whether a row\n * without one is usable is another rule). A ledger is an array of at most `max` entries, each exactly `{ generation,\n * footerCrc }`, the generation a non-negative safe integer and unique, the checksum an integer from 0 to 2^32 - 1. The\n * order is not checked: it is not derivable from the numbers. `show` renders a value for the description, which a\n * caller can truncate.\n */\nexport function knownGensShapeFault(\n value: unknown,\n max: number,\n show: (v: unknown) => string = String,\n): string | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) return 'must be an array';\n const list = value as unknown[];\n if (list.length > max) return `has ${list.length} entries, cap ${max}`;\n const seen = new Set<number>();\n for (const e of list) {\n if (typeof e !== 'object' || e === null || Array.isArray(e))\n return 'an entry must be an object';\n const entry = e as Record<string, unknown>;\n const extra = Object.keys(entry).filter((k) => !ENTRY_KEYS.includes(k));\n if (extra.length > 0) {\n return `an entry carries an undeclared field (${show(extra.join(', '))})`;\n }\n const { generation, footerCrc } = entry;\n if (!Number.isSafeInteger(generation) || (generation as number) < 0) {\n return `a generation must be a non-negative safe integer (got ${show(generation)})`;\n }\n if (\n !Number.isInteger(footerCrc) ||\n (footerCrc as number) < 0 ||\n (footerCrc as number) > 0xffff_ffff\n ) {\n return `a footerCrc must be an integer from 0 to 2^32 - 1 (got ${show(footerCrc)})`;\n }\n if (seen.has(generation as number)) return `generation ${String(generation)} is repeated`;\n seen.add(generation as number);\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["UTF8", "UTF8"]
|
|
7
|
+
}
|