@cloudbitmaps/roaring 0.11.0 → 0.11.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/bin/export-segments.ts", "../../src/index.ts", "../../src/open-charging-storage.ts", "../../src/reserved-namespace.ts", "../../src/roaring-codec.ts", "../../src/portable/layout.ts", "../../src/system-clock.ts", "../../src/option-keys.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n/**\n * `export-segments` \u2014 the standalone **eject / data-export** CLI (the exit path; see the README's \"Your data\n * stays yours\"). Dumps every registered segment's current generation to a portable file, so your data is\n * readable **without CloudRoaring**. A thin filesystem wrapper over `CloudRoaring.exportSegments`.\n *\n * Two formats:\n * - `roaring` (default) \u2014 one portable RoaringBitmap32 per segment (`<segment>.roaring`), loadable by any\n * roaring library (Java/Go/Python/Rust/C++/\u2026).\n * - `ndjson` \u2014 newline-delimited ids per segment (`<segment>.ndjson`), zero dependencies to read, streamed.\n *\n * Output layout: `<out>/<namespace|_default>/<segment>.<ext>` + a self-describing `<out>/manifest.json`. A\n * `:` in a name is percent-encoded as `%3A` in the path (a colon cannot go into a Windows filename), so the\n * manifest's names are authoritative and the directory is portable. Files\n * are written to a unique `.part` temp and atomically renamed on completion; the manifest is written last (also\n * atomically), so a directory with a `manifest.json` means the run **finished** (a crash leaves no manifest \u2192\n * re-run). A segment that couldn't be read is isolated into the manifest's `failed[]` and the CLI exits non-zero\n * \u2014 always check it, because \"manifest present\" is *the run finished*, not \"every segment succeeded\". Re-running\n * overwrites the segments it re-exports but does **not** prune files for segments that have since disappeared \u2014\n * **export to a fresh directory** for a clean dump. Artifacts are owner-only (decrypted **cleartext** \u2014 protect it).\n *\n * Ships the **local-filesystem** backend (zero-dependency, the dev/reference target). For a cloud store, wire a\n * short script that builds the backend for the storage you have and calls `store.exportSegments(sink,\n * { format })` with your own sink \u2014 the binary stays SDK-free:\n *\n * new CloudRoaring({ storage: new S3Storage({ bucket }) })\n *\n * One backend object, not a driver pair. Assembling `{ storage, registry }` by hand is refused with a\n * `ValidationError` that names the backend classes.\n *\n * Config is read from the environment (12-factor-friendly):\n * CR_EXPORT_ROOT (required) \u2014 the local-filesystem root holding storage/ registry/\n * CR_EXPORT_OUT (required) \u2014 the output directory for the dump\n * CR_EXPORT_FORMAT roaring | ndjson (default: roaring)\n * CR_EXPORT_NAMESPACE scope the export to one namespace\n */\nimport { randomUUID } from 'node:crypto';\nimport { realpathSync } from 'node:fs';\nimport { mkdir, open, rename, rm, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { encodeNameForPath, namespacePathPart } from '@cloudbitmaps/core/driver-kit';\nimport { CloudRoaring, LocalFsStorage } from '../index';\nimport type { ExportFormat, ExportManifest, ExportSink, SegmentRef } from '../index';\n\nexport interface ExportConfig {\n readonly root: string;\n readonly out: string;\n readonly format: ExportFormat;\n readonly namespace?: string;\n}\n\n/** Parse + validate config from an environment map. Throws a clear `Error` on misconfiguration. */\nexport function parseConfig(env: Record<string, string | undefined>): ExportConfig {\n const root = env.CR_EXPORT_ROOT;\n if (root === undefined || root === '') {\n throw new Error('CR_EXPORT_ROOT is required (the local-filesystem storage root)');\n }\n const out = env.CR_EXPORT_OUT;\n if (out === undefined || out === '') {\n throw new Error('CR_EXPORT_OUT is required (the output directory for the dump)');\n }\n const format = env.CR_EXPORT_FORMAT ?? 'roaring';\n if (format !== 'roaring' && format !== 'ndjson') {\n throw new Error(`CR_EXPORT_FORMAT must be \"roaring\" or \"ndjson\"; got ${format}`);\n }\n const namespace = env.CR_EXPORT_NAMESPACE || undefined; // treat '' (an unset shell var) as \"no filter\"\n return { root, out, format, namespace };\n}\n\n/**\n * A filesystem {@link ExportSink}. Writes each segment to a **unique** `<segment><ext>.<uuid>.part` temp\n * (`O_EXCL` create, mode `0o600`) and atomically renames it into `<out>/<namespace>/<segment><ext>` on `close()`,\n * so a half-written file never masquerades as complete and concurrent exports to the same dir can't clobber one\n * another. Uses a `FileHandle` (not `createWriteStream`) so an I/O fault **rejects the write** rather than\n * emitting an unhandled `'error'` event that would crash the process, and loops on short writes so a partial\n * `write()` never truncates the output. Artifacts are **owner-only** (dir `0o700`, files `0o600`) \u2014 cleartext.\n */\nexport function fsSink(out: string): ExportSink {\n return {\n async open(ref: SegmentRef, ext: string) {\n // Names may contain `:`; a path may not. On Windows `dedup:2026-08-01.roaring` names an NTFS alternate\n // data stream on a file called `dedup` \u2014 the rename SUCCEEDS, the segment is recorded in the manifest\n // rather than `failed[]`, and `readdir` never lists it. A dump whose whole value is being a faithful\n // copy would then assert success over data an ordinary file copy will not carry. Same encoding the\n // LocalFs drivers use, so an export is diffable against the store it came from.\n // `namespacePathPart`, not `encodeNameForPath(ns ?? '_default')`: the sentinel is emitted literally\n // while a caller's namespace is encoded, so a segment in a namespace actually named `_default`\n // does not land in the same directory as the un-namespaced ones.\n const dir = join(out, namespacePathPart(ref.namespace));\n await mkdir(dir, { recursive: true, mode: 0o700 });\n const finalPath = join(dir, `${encodeNameForPath(ref.segment)}${ext}`);\n const tmpPath = `${finalPath}.${randomUUID()}.part`;\n const handle = await open(tmpPath, 'wx', 0o600); // wx = create-exclusive; unique name \u21D2 no collision\n return {\n async write(bytes: Uint8Array): Promise<void> {\n // Loop until every byte lands \u2014 FileHandle.write may do a short write; it rejects on I/O error (no\n // stray 'error' event \u2192 no process crash).\n let off = 0;\n while (off < bytes.length) {\n const { bytesWritten } = await handle.write(bytes, off, bytes.length - off);\n if (bytesWritten === 0) throw new Error('export write made no progress');\n off += bytesWritten;\n }\n },\n async close(): Promise<void> {\n await handle.close();\n try {\n await rename(tmpPath, finalPath);\n } catch (err) {\n await rm(tmpPath, { force: true }); // don't strand the temp if the rename fails\n throw err;\n }\n },\n async abort(): Promise<void> {\n // Discard the partial; best-effort so a failing cleanup never masks the caller's original fault.\n await handle.close().catch(() => {});\n await rm(tmpPath, { force: true });\n },\n };\n },\n };\n}\n\nconst log = (obj: unknown): void => {\n process.stdout.write(`${JSON.stringify(obj)}\\n`);\n};\n\n/** CLI entry: build a LocalFs store, export every enumerated segment, then write the manifest. */\nexport async function main(\n env: Record<string, string | undefined> = process.env,\n now: () => number = () => Date.now(),\n): Promise<ExportManifest> {\n const config = parseConfig(env);\n const storage = new LocalFsStorage(config.root);\n const store = new CloudRoaring({ storage });\n\n const manifest = await store.exportSegments(fsSink(config.out), {\n format: config.format,\n namespace: config.namespace,\n });\n\n // The manifest is written LAST (after every segment file is committed), so its presence marks a finished run \u2014\n // and it's written the same atomic (temp\u2192rename) way, so the marker itself can't be torn by a crash mid-write.\n // Owner-only (0o600) \u2014 the dump is cleartext. (A finished run may still have skipped unreadable segments \u2014 see\n // `manifest.failed`.)\n await mkdir(config.out, { recursive: true, mode: 0o700 });\n const manifestPath = join(config.out, 'manifest.json');\n const manifestTmp = `${manifestPath}.${randomUUID()}.part`;\n await writeFile(\n manifestTmp,\n `${JSON.stringify({ generatedAt: new Date(now()).toISOString(), ...manifest }, null, 2)}\\n`,\n { encoding: 'utf8', mode: 0o600, flag: 'wx' },\n );\n try {\n await rename(manifestTmp, manifestPath);\n } catch (err) {\n await rm(manifestTmp, { force: true });\n throw err;\n }\n // Log AGGREGATES only \u2014 never per-segment names/counts (a segment name can encode sensitive purpose, and stdout\n // is captured by CI/journald/docker, which don't honor the 0o600 boundary). The detail lives in the manifest.\n log({\n event: 'export',\n out: config.out,\n version: manifest.version,\n format: manifest.format,\n totalSegments: manifest.totalSegments,\n totalIds: manifest.totalIds,\n failed: manifest.failed.length,\n });\n return manifest;\n}\n\n/**\n * Was this module executed as the CLI, rather than imported?\n *\n * Compared as URLs because `process.argv[1]` is a path and `import.meta.url` is a `file:` URL, so a string\n * compare would never match \u2014 and through `realpathSync`, which is the part that was missing.\n *\n * Node resolves a module's `import.meta.url` through symlinks but leaves `process.argv[1]` exactly as it was\n * typed. Every normal installation puts a SYMLINK at `node_modules/.bin/export-segments`, and that is the\n * path `npx` and every npm script invoke, so the two sides disagreed and the guard was false: the CLI exited\n * 0 having done nothing at all. Running the real file worked, which is why it looked fine here \u2014 pnpm writes\n * shell shims that exec the real path, so the repo's own package manager hid it while npm and yarn-classic\n * users got silence.\n *\n * BOTH comparisons are kept, because `--preserve-symlinks-main` inverts which one holds. That flag tells\n * Node not to resolve the main entry, so `import.meta.url` becomes the symlink path while `realpathSync`\n * still returns the real one \u2014 the same mismatch, the other way round, and the same silent exit-0 no-op.\n * Some monorepo and bundler setups put it in `NODE_OPTIONS` globally. The literal comparison is the original\n * condition, which was only ever too NARROW: it matches when this module IS the unresolved entry, so adding\n * it back as a disjunct widens without creating a way to run on import.\n *\n * `realpathSync` can throw, and none of those cases mean \"run the CLI\", so they resolve to false. The one\n * that genuinely reaches the catch is `node -` (a script on stdin), where `argv[1]` is the literal string\n * `\"-\"` and resolving it raises `ENOENT`. (Under `node --eval` there is no `argv[1]` at all, so the early\n * return above handles that one.)\n */\nfunction invokedAsCli(): boolean {\n const entry = process.argv[1];\n if (entry === undefined) return false;\n try {\n return (\n import.meta.url === pathToFileURL(entry).href ||\n import.meta.url === pathToFileURL(realpathSync(entry)).href\n );\n } catch {\n return false;\n }\n}\n\nif (invokedAsCli()) {\n main()\n .then((manifest) => {\n if (manifest.failed.length > 0) {\n // The run finished and the manifest is written, but some segments couldn't be read \u2014 signal it non-zero.\n process.stderr.write(\n `${manifest.failed.length} segment(s) failed to export; see manifest.json \"failed\"\\n`,\n );\n process.exitCode = 1;\n }\n })\n .catch((err: unknown) => {\n process.stderr.write(`${(err as Error).message}\\n`);\n process.exit(1);\n });\n}\n", "/**\n * CloudRoaring \u2014 distributed, cloud-native Roaring Bitmaps, read from object storage.\n *\n * The `CloudRoaring` class is the read engine over **loaded** segments: write-once `.crbm` generations in an\n * object store, behind one registry pointer per segment. You wire storage **once**, as a single config object:\n * pass a **backend** as `storage` \u2014 `S3Storage`, `GcsStorage`, `AzureBlobStorage`, `LocalFsStorage` or\n * `MemoryStorage` \u2014 and it carries both halves, the generations and the pointer, from one bucket and one\n * prefix. Add `encryption: { keystore }` for encryption-at-rest / crypto-shred.\n *\n * Two narrower shapes are also accepted for `storage`: a bare {@link IStorageDriver}, which has no pointer and\n * so resolves generations by list-scanning storage (**cleartext and read-only**), and an already-built\n * {@link StorageChunkSource} for advanced reader options you configure yourself.\n *\n * **Data gets in by loading a generation**, never by mutating one: `store.load()` streams a set of ids into one\n * immutable object and advances the segment's pointer to it. The pointer only moves forward, so a load out-raced by\n * a newer generation reports `superseded` instead of landing, and so does one that read the row when the row has\n * changed since. Every other write in the library is a load in\n * disguise \u2014 `intersectInto`/`unionInto`/`andNotInto` write a new generation of their destination, and\n * `eraseSubject` rewrites a generation without one id. Reads (`has`/`count`/`iterate`/`intersect`/`union`/`andNot`)\n * see whole, checksum-verified generations and nothing else.\n *\n * In-process lifecycle helpers \u2014 `eraseSubject`, `subjectReport`, `dropSegment`, `retireExpired`,\n * `checkConsistency`, `exportSegments` \u2014 reuse the store's own drivers, so you never re-pass them (they need the\n * store built with a backend). See the README and the getting-started guide.\n */\n\nimport {\n BoundedLru,\n PinnedStorageChunkSource,\n segmentKey,\n CrbmStorageChunkSource,\n DEFAULT_BUDGET,\n DEFAULT_RETRY_POLICY,\n withRetry,\n isStorageBackend,\n NOOP_METRICS,\n RetryingStorageChunkSource,\n SegmentEngine,\n UnsupportedError,\n ValidationError,\n WriteConflictError,\n MIN_EXPIRES_AT_MS,\n checkBudget,\n collectWithinBudget,\n excludingReservedRows,\n dropSegment,\n eraseIdFromSegment,\n estimateCost,\n groundedReport,\n loadSegment,\n mapWithConcurrency,\n resolveBudget,\n resolvePerOpBudget,\n retireExpired,\n runConsistencyCheck,\n runExport,\n setSegmentRetention,\n clearSegmentRetention,\n getSegmentRetention,\n safeMetrics,\n splitId,\n} from '@cloudbitmaps/core';\nimport { validateSegmentRef } from '@cloudbitmaps/core/driver-kit';\nimport type {\n Budget,\n BudgetOption,\n GenerationEntry,\n LoadGuard,\n LoadOptions,\n LoadRefusal,\n LoadResult,\n RollbackResult,\n Clock,\n CodecBitmap,\n CodecInterface,\n StorageChunkSource,\n ConsistencyReport,\n CostReport,\n EngineDeps,\n DropResult,\n EstimateInput,\n ExportManifest,\n ExportOptions,\n ExportSink,\n IAuditSink,\n IStorageDriver,\n IKeystore,\n IMetricsSink,\n IRegistryDriver,\n StorageBackend,\n MetricOpName,\n PricingProfile,\n RetentionPolicy,\n RetireExpiredOptions,\n RetireExpiredResult,\n RetryPolicy,\n RetryingOptions,\n Rng,\n SetRetentionResult,\n PinnedAt,\n IdRange,\n SegmentRef,\n Workload,\n} from '@cloudbitmaps/core';\nimport { OpenChargingStorage } from './open-charging-storage';\n// This package's reason to exist: the roaring codec the facade injects into the codec-agnostic engine.\nimport { listGenerations, rollbackSegment } from '@cloudbitmaps/core';\nimport { listSegments, segmentExists } from '@cloudbitmaps/core';\nimport type { SegmentInfo } from '@cloudbitmaps/core';\nimport { refuseReservedNamespace } from './reserved-namespace';\nimport { roaringCodec } from './roaring-codec';\nimport { SystemClock } from './system-clock';\nimport { OPTION_KEYS, type OptionGroup } from './option-keys';\n\n/** Default randomness for backoff jitter \u2014 lives outside `core/`, so `Math.random()` is allowed here. */\nclass SystemRng implements Rng {\n /** A float in `[0, 1)`. Jitter only \u2014 never key material, never anything a caller can observe. */\n next(): number {\n return Math.random();\n }\n}\n\nconst DEFAULT_CACHE_MAX_CHUNKS = 1024;\n/** Default in-flight fan-out for the admin scans (`subjectReport`/`eraseSubject`) \u2014 bounded, no thundering herd. */\nconst DEFAULT_ADMIN_CONCURRENCY = 8;\n/** Fail fast on a bad admin `concurrency` BEFORE the (potentially huge) registry scan, not after. */\nfunction validateConcurrency(concurrency: number | undefined): void {\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ValidationError(`concurrency must be a positive integer; got ${concurrency}`);\n }\n}\n\n/**\n * Tenancy guard for the global-scope admin scans (`subjectReport`/`eraseSubject`). Ids live in ONE global\n * `[0, 2\u00B3\u00B2)` space shared across namespaces, so a namespace-less scan reaches into *every* tenant's segments.\n * Require an explicit `namespace`, or a deliberate `{ allNamespaces: true }` ack, so a fleet-wide sweep is never\n * the accidental default on a shared store.\n */\nfunction requireScope(options: { namespace?: string; allNamespaces?: boolean }, op: string): void {\n // A scope names a namespace like a ref does, and these two scans read the registry themselves rather than\n // through a core function that refuses it.\n refuseReservedNamespace(options.namespace);\n if (options.namespace === undefined && options.allNamespaces !== true) {\n throw new ValidationError(\n `${op} scans the global id space across all namespaces \u2014 pass an explicit \\`namespace\\`, ` +\n `or \\`{ allNamespaces: true }\\` to intentionally sweep the whole fleet`,\n );\n }\n}\n\n/**\n * Wiring for a {@link CloudRoaring} store. **Only `storage` is required** \u2014 the minimal call is\n * `new CloudRoaring({ storage: backend })`. A backend resolves generations with one strong read, reads\n * encrypted segments, and unlocks every lifecycle helper; the narrower shapes `storage` also accepts are\n * described on the option itself. Everything else is **optional\n * tuning with sensible defaults** \u2014 resilience/retries are already on, the cache is bounded, metrics are a\n * no-op \u2014 so reach for them only when you need to.\n */\nexport interface CloudRoaringOptions {\n /**\n * Where the store keeps everything. **The only required option.**\n *\n * Pass a {@link StorageBackend} \u2014 `S3Storage`, `GcsStorage`, `AzureBlobStorage`, `LocalFsStorage`,\n * `MemoryStorage` \u2014 and you are done: it carries both halves, the generations and the `currentGen` pointer,\n * configured from one bucket and one prefix. That is the whole wiring, and it is the shape to reach for.\n *\n * **Pass the backend itself, not `backend.storage`.** They differ by one property access and the mistake is\n * silent: `storage: backend` is the store, while `storage: backend.storage` hands over the *driver half*\n * alone, which constructs without complaint and gives you a cleartext, read-only store that fails later on\n * the first write or lifecycle call. `destroySegment` and `eraseNamespace` take `backend.registry`; the store takes `backend`.\n *\n * Two lower-level shapes stay accepted for wiring the facade does not cover:\n *\n * - a **raw {@link IStorageDriver}**, which the store wraps in a {@link CrbmStorageChunkSource}. There is no\n * registry in this shape, so the store resolves generations by list-scanning storage: **cleartext and\n * read-only**. Encrypted segments, the `*Into` verbs and every lifecycle helper need a backend.\n * - an already-built {@link StorageChunkSource}, used as-is, for advanced reader options.\n */\n readonly storage: StorageBackend | IStorageDriver | StorageChunkSource;\n\n /**\n * Memory and staleness bounds for the read path. Every key is optional and every default is already sane;\n * reach for these when a deployment's shape differs from \"a long-running server with room to breathe\".\n */\n readonly cache?: CacheOptions;\n\n /**\n * Encryption at rest. Omit it entirely for a cleartext store \u2014 encryption is opt-in, and a segment's\n * encryption is decided at its **first** generation.\n */\n readonly encryption?: EncryptionOptions;\n\n /**\n * Resilience: by default every read that answers a query retries **transient** faults (throttling, 5xx, dropped\n * connections) with bounded, jittered exponential backoff (see {@link DEFAULT_RETRY_POLICY}): `has`, `count`,\n * `iterate` and the combines, the `*Into` verbs' reads of their operands included, a pinned handle's reads and\n * `pin()` itself. Writes are not retried, and nor are an erasure's reads, a load's guard read, or the calls that\n * read the registry or list the bucket directly (`exists`, `segments`, `generations`, `getRetention`, and the\n * registry scan `subjectReport`, `exportSegments` and `checkConsistency` start from): they report a transient fault to their caller, because a conditional write that lands and then loses its response would, replayed,\n * report its own write as a conflict. Pass a partial policy to tune it \u2014 anything you leave out keeps its\n * default \u2014 or `false` to turn the read retry off (e.g. if your injected client already retries).\n * Deterministic errors (`ValidationError`/`IntegrityError`/`WriteConflictError`/\u2026) are never retried by this\n * layer.\n */\n readonly retry?: RetryOptions | false;\n\n /**\n * Observability sink: receives typed metric events (storage GET/bytes, cache hit/miss, retries, intersection\n * efficiency, op latency). Defaults to a no-op \u2014 emission is skipped entirely when unused (near-zero\n * overhead). Any exception the sink throws is swallowed \u2014 metrics can never break a read.\n */\n readonly metrics?: IMetricsSink;\n\n /**\n * Per-op **denial-of-wallet** budget: the max backend requests a single\n * `count`/`iterate`/`intersect`/`union`/`andNot`/`subjectReport`/`eraseSubject` may fan out into before it's\n * refused with {@link BudgetExceededError} (`eraseSubject` reports an over-budget segment in its ledger instead,\n * see {@link CloudRoaring.eraseSubject}) \u2014 so one runaway op can't drive unbounded GET cost on a shared\n * backend. **On by default, generous** ({@link DEFAULT_BUDGET}: 1,000,000 requests \u2014 a normal op never hits it).\n * Tune with `{ maxRequests }`, override per op (on the combines / `subjectReport` / `eraseSubject`), or set\n * `false` to disable. The check is O(1) (before fan-out), so the hot path is untouched; per-request bytes are\n * separately size-capped, so bounding requests transitively bounds bytes.\n */\n readonly budget?: BudgetOption;\n\n /**\n * Determinism seams, for tests and replayable jobs. Production stores leave this out and get a system clock\n * and a `Math.random`-backed source.\n */\n readonly seams?: SeamOptions;\n}\n\n/** {@link CloudRoaringOptions.cache} \u2014 the memory and staleness bounds. */\nexport interface CacheOptions {\n /** Ceiling on decoded Storage chunks held in RAM (default 1024). */\n readonly maxChunks?: number;\n /** Optional TTL on cached chunks (ms). Omit to keep a chunk until it is evicted by the count bound. */\n readonly ttlMs?: number;\n /**\n * How long (ms) the store trusts a segment's resolved `currentGen` before re-resolving it on the next read\n * (default 2000) \u2014 the bound on read staleness after a load publishes a new generation. Applies when\n * `storage` is a **backend**, whose registry supplies the cheap `currentGen` read the refresh needs. Lazy \u2014 no\n * timer; \u2264 one registry read per segment per window, opening a new reader only when the generation actually\n * advanced.\n *\n * **While the registry cannot be read, the bound stretches.** A refresh that fails with a\n * {@link TransientError} keeps serving the generation the reader holds, and the key it unwrapped, and is tried\n * again 500 ms later (or after this TTL, if shorter), so the store converges within one retry of the registry\n * answering. A refresh that fails with anything else, an access denial or a row that will not parse, is not\n * ridden out: the read that meets it throws that error, and the reader is dropped.\n *\n * `0` turns this timed refresh off, and so does wiring a bare `IStorageDriver`, which has no registry. That is\n * all it does. The store still moves a segment on to whatever generation is current when its reader cache\n * evicts the segment, when a read has to fetch from a generation a sweep deleted, and when it is invalidated,\n * as its own `load`, `rollback`, `eraseSubject` and `*Into` writes do and {@link CloudRoaring.invalidate} does.\n * A read its caches can answer touches no storage, so a sweep alone moves nothing. What `0` gives up is the bound:\n * the store notices another process's publish, erasure or drop only through one of those, whenever that happens. To read\n * one generation for as long as you need it, take a {@link Segment.pin}.\n */\n readonly genTtlMs?: number;\n /**\n * Ceiling on how many segments' `.crbm` readers (each holding a parsed index) the store keeps open at once\n * (default 1024) \u2014 the steady-state memory bound for a long-running server that reads across many segments.\n * Past it the least-recently-used segment's reader is evicted; re-opening it later is one cheap tail GET.\n * Applies whenever the store builds its own read path \u2014 a backend or a bare `IStorageDriver`. A pre-built\n * `StorageChunkSource` manages its own reader cache.\n */\n readonly readerMax?: number;\n /**\n * Aggregate byte ceiling on the parsed `.crbm` indices the open readers hold (default 64 MiB) \u2014 the byte half\n * of the memory bound, complementing the {@link CacheOptions.readerMax} *count* bound. A wide/dense segment's\n * parsed index can be several MB, so a count-only bound could let the open readers pin ~GBs and blow a small\n * heap (e.g. a 128 MB Lambda); this evicts the least-recently-used reader once the summed index footprint\n * would exceed the ceiling \u2014 whichever of the count/byte bounds binds first. Lower it for memory-tight\n * deployments that read across wide segments. Applies whenever the store builds its own read path.\n */\n readonly readerMaxBytes?: number;\n}\n\n/** {@link CloudRoaringOptions.encryption} \u2014 encryption at rest and crypto-shred. */\nexport interface EncryptionOptions {\n /**\n * The keystore that mints and unwraps per-segment DEKs. Needs a **backend**: the wrapped DEK lives in the\n * registry, so there is nowhere to put it on a store wired with a bare driver, and that is refused at\n * construction rather than at the first read.\n */\n readonly keystore?: IKeystore;\n /**\n * Refuse to touch a **cleartext** segment \u2014 a guard against silently reading, or writing, data that should be\n * encrypted. Needs a backend, for the same reason as {@link EncryptionOptions.keystore}. Off by default.\n *\n * It refuses **writes** as well as reads, which is easy to miss: the `*Into` verbs and `eraseSubject` both\n * carry it into their write path, so on a cleartext segment a materialisation throws and an erasure records\n * `note: 'error: requireEncryption: \u2026'` in its ledger rather than erasing. And since a segment's encryption is\n * decided at its **first** generation, this cannot be switched on for a segment that already has one \u2014 load\n * into a new encrypted segment and drop the old one.\n */\n readonly required?: boolean;\n}\n\n/**\n * {@link CloudRoaringOptions.retry} \u2014 a partial {@link RetryPolicy} plus the retry callback.\n *\n * Partial on purpose, so tuning one field does not mean restating all five. Anything omitted here keeps its\n * {@link DEFAULT_RETRY_POLICY} value.\n */\nexport interface RetryOptions extends Partial<RetryPolicy> {\n /**\n * Observability: called before each transient-retry backoff wait. Best-effort: an error it throws is\n * swallowed, so it can neither stop the retry nor change the error a read fails with.\n */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/** {@link CloudRoaringOptions.seams} \u2014 injected for deterministic tests and replayable jobs. */\nexport interface SeamOptions {\n /** Defaults to a system clock. */\n readonly clock?: Clock;\n /** Defaults to `Math.random`-backed. Drives transient-retry jitter. */\n readonly rng?: Rng;\n}\n\nexport interface SegmentOptions {\n readonly namespace?: string;\n /**\n * **When this segment stops being readable** \u2014 an absolute epoch-ms instant, declared where the segment is\n * named instead of in a separate `setRetention` call.\n *\n * Every read through this handle checks it first: past the deadline, `has` is `false`, `count` is `0`, and\n * `iterate` yields nothing \u2014 **one integer compare against the injected clock, no I/O, on every backend**.\n * That is Redis's lazy expiry, and it is what makes an expiry *correct* rather than *eventually correct*: a\n * deployment whose sweep is late \u2014 or which has no sweep at all, like a Lambda-only reader \u2014 still stops\n * serving the data on time.\n *\n * **Two things this does NOT do, both deliberate:**\n *\n * - It does not reclaim the bytes. That is {@link CloudRoaring.retireExpired}, and until it runs the data is\n * still stored and still billed. `count()` reporting 0 while objects exist is the expected state in that\n * window, not a bug.\n * - It does not apply to *other* handles. The deadline lives on this handle; a second handle opened without\n * the option reads the segment normally. Record the policy with {@link CloudRoaring.setRetention} to make\n * it durable, fleet-visible, and reclaimable.\n *\n * Must be **milliseconds** since the epoch and at or after {@link MIN_EXPIRES_AT_MS} \u2014 a seconds value would\n * land in 1970 and make the segment permanently unreadable, so it is refused rather than honoured.\n */\n readonly expiresAt?: number;\n}\n\n/** A segment reference in a subject report / erasure ledger. */\nexport interface SubjectSegmentRef {\n readonly segment: string;\n readonly namespace?: string;\n}\n\n/** Result of {@link CloudRoaring.subjectReport} \u2014 the segments an id is a member of (over registered segments). */\nexport interface SubjectReport {\n readonly id: number;\n /** The registered segments the id is currently a member of. */\n readonly segments: SubjectSegmentRef[];\n /** How many registered segments were scanned (the completeness denominator). */\n readonly scannedSegments: number;\n}\n\n/** One segment's entry in an erasure ledger (see {@link EraseSubjectResult}). */\nexport interface SubjectErasureEntry {\n readonly segment: string;\n readonly namespace?: string;\n /**\n * True iff the id **was** in the segment and **no generation of it holds the id now** \u2014 not the current one, not\n * one below the pointer, and not one above it, where a rollback leaves the generations it rolled back from. The\n * current generation is one without it, every generation that held it has been deleted from the bucket, and the\n * call listed the bucket and read what was left before this entry was returned (see\n * {@link CloudRoaring.eraseSubject}).\n */\n readonly erased: boolean;\n /**\n * The generation the id was found in (present whenever the segment was read) \u2014 the newest of them, when the\n * current generation did not hold it and several others did.\n */\n readonly fromGeneration?: number;\n /** The generation written without the id (present whenever one was written). */\n readonly generation?: number;\n /**\n * Why the id was NOT erased from this segment, when `erased` is false. `'superseded'` \u2014 the pointer moved while\n * the call was in flight, by a load, another erasure or a rollback, so **this call** did not erase the id;\n * re-run against the new generation, which erases it if it is still there and reports nothing for the segment\n * if the racing writer already removed it. `` `error: <message>` `` \u2014 an isolated per-segment fault\n * (per-segment faults are recorded so one segment can't discard the whole ledger); re-run after fixing the\n * fault. A budget refusal is one of these: the segment's generations did not fit `budget`, so it was not finished;\n * re-run with a higher `budget`. A fault that landed once part of the work was already done \u2014 a Storage `delete` fault, a collect that\n * could not prove the segment was still the same one, or a generation still holding the id when the bucket was\n * listed at the end, whether or not a rewrite was published first \u2014 also re-runs, but **read what the re-run\n * says**: it usually reports `erased: true` against the generation it found the id in, it reports\n * nothing at all if a racing collector took that generation first (the bit is gone, but no run holds a\n * receipt for it), and if the segment's row has since been purged it is no longer scanned at all \u2014 anything\n * left in its bucket is an orphan, which `store.generations(ref)` lists and `store.dropSegment(ref, {\n * confirmSegment })` deletes; `checkConsistency` and the collection a load runs read rows, so neither reaches it.\n * **Segments the id is not in\n * are not listed, and neither are segments that no longer have a registry row** \u2014 an empty ledger is not by\n * itself proof the id is gone.\n */\n readonly note?: string;\n}\n\n/**\n * The erasure ledger returned by {@link CloudRoaring.eraseSubject} \u2014 your proof-of-deletion artifact. It is a\n * return value only (no library-side persistence): persist it / route it to your audit sink as you see fit.\n */\nexport interface EraseSubjectResult {\n readonly id: number;\n /** Per-segment records for the segments the id was found in (absent segments are not listed). */\n readonly erasedFrom: SubjectErasureEntry[];\n /** How many registered segments were scanned. */\n readonly scannedSegments: number;\n}\n\n/**\n * Why a materialisation did not become current.\n *\n * {@link LoadRefusal} minus `'superseded'`: that one is a lost race, and the `*Into` verbs throw\n * {@link WriteConflictError} for it rather than reporting it. Narrowing the type rather than saying so only\n * in prose means the compiler enforces it, and a caller's exhaustive `switch` has no dead branch.\n */\nexport type MaterializeRefusal = Exclude<LoadRefusal, 'superseded'>;\n\n/** What an `*Into` verb wrote: the new generation of the destination, and whether it became current. */\nexport interface MaterializeResult {\n /**\n * The generation written. Present even when refused: the refusal deleted that object, unless the destination's\n * row changed while it was writing, which leaves it in the bucket.\n */\n readonly generation: number;\n /**\n * Whether this generation is now the destination's current one.\n *\n * `false` when the guard refused the result: an empty one over a non-empty destination, or one outside\n * `guard`'s bounds. Branch on it: a refusal is reported, not thrown, so a caller that ignores it sees a\n * successful-looking result for a write that deliberately did not happen.\n */\n readonly published: boolean;\n /** Set only when `published` is false. A lost race throws {@link WriteConflictError} rather than appearing here. */\n readonly reason?: MaterializeRefusal;\n /** Ids in the generation. */\n readonly cardinality: number;\n /**\n * What the destination held when the guard judged it \u2014 `null` when it had no current generation, **or when\n * no bound needed the read**. The read costs an object-header fetch, so it is taken only when a bound will\n * use it: `allowEmpty: true` with no `guard.minRetained` skips it, and this is `null` even though `dest`\n * was non-empty.\n */\n readonly cardinalityBefore: number | null;\n /** Non-empty chunks in the generation. */\n readonly chunkCount: number;\n /** Bytes of the written object. */\n readonly size: number;\n /**\n * The superseded generations collected after publishing. Empty when nothing was published \u2014 and **also\n * empty on a successful publish** unless you passed `keep`, because a materialisation collects nothing by\n * default. See {@link MaterializeOptions.keep}.\n */\n readonly collected: readonly number[];\n}\n\n/**\n * Resolve the `storage` option to a {@link StorageChunkSource} at construction (wiring-time only \u2014 no hot-path cost).\n *\n * `storage` is discriminated by a **brand** for the backend arm and structurally for the other two: a raw {@link IStorageDriver} exposes `putImmutable`\n * (the byte-mover seam); a pre-built {@link StorageChunkSource} exposes `getChunk` (the engine's read seam). The\n * two interfaces are deliberately **disjoint** on these methods (an invariant the driver SDK maintains, pinned\n * by a test) \u2014 an object exposing *both* is ambiguous and rejected, as is one exposing *neither* (incl. a\n * nullish/non-object value from a JS caller): fail fast with a typed error rather than crash on a probe.\n *\n * A backend is wrapped into a {@link CrbmStorageChunkSource} over its storage half, pinned to its registry,\n * with the config's `encryption` group; a bare driver is wrapped the same way but without a\n * registry; a pre-built source is used as-is. `keystore`/`requireEncryption` are meaningful **only** where the\n * store builds the source itself \u2014 pairing either with a pre-built source is a wiring mistake, so reject it\n * rather than silently ignore it. The `CrbmStorageChunkSource` constructor enforces the rest (a keystore /\n * `requireEncryption` needs a registry, so they need a backend; the driver needs range reads).\n *\n * Returns the resolved `source` (what the engine reads through) **and** the raw `driver` when one was passed \u2014\n * the store keeps the raw driver so its lifecycle helpers and the `*Into` verbs can write generations without\n * you re-passing drivers. `driver` is `undefined` for a pre-built source (there's no underlying `IStorageDriver` to\n * write through, so its writes throw {@link UnsupportedError}).\n */\n/**\n * Work out what the caller handed us, and build the read path from it.\n *\n * Three accepted shapes. A backend is identified by its brand, the other two structurally \u2014 never by `instanceof`, so a backend or driver from a\n * different copy of the package still works (the same reason the error predicates are brand-based).\n */\nfunction resolveStorageSource(\n options: CloudRoaringOptions,\n clock: Pick<Clock, 'now'>,\n): {\n source: StorageChunkSource;\n driver: IStorageDriver | undefined;\n registry: IRegistryDriver | undefined;\n} {\n const storage: unknown = options.storage;\n if (storage === null || typeof storage !== 'object') {\n throw new ValidationError(\n '`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource',\n );\n }\n const asBackend = storage as Partial<StorageBackend>;\n const isObject = (v: unknown): v is Record<string, unknown> =>\n v !== null && typeof v === 'object';\n const hasGetChunk = typeof (storage as Partial<StorageChunkSource>).getChunk === 'function';\n const hasPutImmutable = typeof (storage as Partial<IStorageDriver>).putImmutable === 'function';\n\n // The BRAND decides, not the shape. `{ storage, registry }` is also the shape of core's free-function deps\n // object, so before the brand any literal satisfied it \u2014 including one holding halves from two unrelated\n // stores, which the store accepted and then answered empty for a segment that holds data.\n const isBackend = isStorageBackend(storage);\n\n // A branded backend that ALSO quacks like a driver or a source is genuinely ambiguous. Unreachable for the\n // five classes, kept because the alternative to refusing is guessing.\n if (isBackend && (hasGetChunk || hasPutImmutable)) {\n throw new ValidationError(\n '`storage` is a StorageBackend that also exposes ' +\n `${hasGetChunk ? '`getChunk`' : '`putImmutable`'} \u2014 ambiguous. A backend must not also be a driver ` +\n 'or a source; pass whichever one you mean.',\n );\n }\n\n // Unbranded, but carrying both halves. Three sub-cases, and they want different things said.\n const hasStorageHalf = isObject(asBackend.storage);\n const hasRegistryHalf = isObject(asBackend.registry);\n\n // (a) A DRIVER that also carries a registry \u2014 the audit/metrics/tenant-scoping wrapper. Without this it\n // falls through to the bare-driver path, where there is no pointer at all: generations resolve by\n // list-scan, so the store answers from the HIGHEST object in the bucket rather than the published one, and\n // a load that wrote an object but never published it is served as if it had been. Silently, and with the\n // wrapper's registry sitting right there unused.\n if (!isBackend && hasPutImmutable && hasRegistryHalf) {\n throw new ValidationError(\n '`storage` looks like a driver that also carries a `registry`. Passed as a bare driver it would have ' +\n 'no pointer at all \u2014 generations would resolve by list-scan, so reads could serve a generation that ' +\n 'was written but never published. If you meant a backend, use a backend class \u2014 S3Storage, GcsStorage, ' +\n 'AzureBlobStorage, LocalFsStorage or MemoryStorage \u2014 or, to pair a driver of your own with a registry, ' +\n 'brand the pair with `brandAsBackend` from `@cloudbitmaps/core/driver-kit`.',\n );\n }\n\n // (b) Both halves, neither of them a driver or a source: the hand-assembled literal, or a spread of a real\n // backend with one half swapped. Name the classes AND the door \u2014 the five classes cannot express an\n // instrumented half or a foreign registry, which is exactly the case that lands here.\n if (!isBackend && !hasGetChunk && !hasPutImmutable && hasStorageHalf && hasRegistryHalf) {\n const storageOk =\n typeof (asBackend.storage as Partial<IStorageDriver>).putImmutable === 'function';\n const registryOk =\n typeof (asBackend.registry as Partial<IRegistryDriver>).compareAndSwap === 'function';\n // (c) \u2026and if a half is not actually a driver, say THAT rather than lecturing about buckets.\n if (!storageOk || !registryOk) {\n const bad = !storageOk\n ? '`storage` half is not an IStorageDriver (no `putImmutable`)'\n : '`registry` half is not an IRegistryDriver (no `compareAndSwap`)';\n throw new ValidationError(\n '`storage` looks like a backend but its ' +\n bad +\n ' \u2014 use a backend class, or brand a pair of drivers with `brandAsBackend` from ' +\n '`@cloudbitmaps/core/driver-kit`.',\n );\n }\n throw new ValidationError(\n '`storage` must be a backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ' +\n 'MemoryStorage. An object with `.storage` and `.registry` is not one: a backend builds both halves ' +\n 'from a single bucket and prefix, so they cannot disagree, and hand-assembling them re-opens exactly ' +\n 'that mismatch \u2014 a store whose pointer and generations live in different places reads as empty ' +\n 'rather than failing. A driver author who genuinely wants halves of their own \u2014 an instrumented driver, ' +\n 'a registry in a database you already run \u2014 brands the pair with `brandAsBackend` from ' +\n '`@cloudbitmaps/core/driver-kit`, which is taking on that they agree.',\n );\n }\n\n if (isBackend) {\n const backend = storage as StorageBackend;\n return {\n source: new CrbmStorageChunkSource(backend.storage, {\n registry: backend.registry,\n keystore: options.encryption?.keystore,\n requireEncryption: options.encryption?.required,\n clock,\n currentGenTtlMs: options.cache?.genTtlMs,\n maxOpenSegments: options.cache?.readerMax,\n maxOpenIndexBytes: options.cache?.readerMaxBytes,\n }),\n driver: backend.storage,\n registry: backend.registry,\n };\n }\n\n if (hasGetChunk && hasPutImmutable) {\n throw new ValidationError(\n '`storage` exposes both `getChunk` and `putImmutable` \u2014 ambiguous; pass a StorageBackend, an IStorageDriver, or a StorageChunkSource, not a hybrid',\n );\n }\n if (!hasGetChunk && !hasPutImmutable) {\n throw new ValidationError(\n '`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource',\n );\n }\n if (hasGetChunk) {\n // Already a StorageChunkSource \u2014 used as-is. `keystore`/`requireEncryption` only apply when the store\n // builds the source itself; with a pre-built source they are inert, so reject them rather than mislead.\n if (options.encryption?.keystore !== undefined || options.encryption?.required === true) {\n throw new ValidationError(\n 'keystore/requireEncryption apply only when the store builds its own read path; configure them on ' +\n 'the StorageChunkSource you passed instead',\n );\n }\n return { source: storage as StorageChunkSource, driver: undefined, registry: undefined };\n }\n // A bare IStorageDriver: no pointer, so generations resolve by list-scan. Cleartext, read-only.\n const driver = storage as IStorageDriver;\n return {\n source: new CrbmStorageChunkSource(driver, {\n keystore: options.encryption?.keystore,\n requireEncryption: options.encryption?.required,\n clock,\n currentGenTtlMs: options.cache?.genTtlMs,\n maxOpenSegments: options.cache?.readerMax,\n maxOpenIndexBytes: options.cache?.readerMaxBytes,\n }),\n driver,\n registry: undefined,\n };\n}\n\n/** The deps every write-side helper on the store shares: raw storage + registry + the store's codec/crypto/clock. */\ninterface LifecycleDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n readonly codec: CodecInterface;\n readonly clock: Clock;\n readonly keystore?: IKeystore;\n readonly requireEncryption?: boolean;\n}\n\n/** How the store names a group value that is an object to `typeof` but configures nothing, by its built-in tag. */\nconst NOT_A_GROUP: Readonly<Record<string, string>> = {\n Null: 'null',\n Array: 'an array',\n Map: 'a Map',\n Set: 'a Set',\n Boolean: 'a boxed boolean',\n Number: 'a boxed number',\n String: 'a boxed string',\n};\n\nexport class CloudRoaring {\n private readonly engine: SegmentEngine;\n private readonly cache: BoundedLru<string, CodecBitmap>;\n /** The store's retry options, for a pinned engine to read through as the store's own does; undefined when off. */\n private readonly retryOptions: RetryingOptions | undefined;\n private readonly crbmSource: CrbmStorageChunkSource | undefined;\n private readonly clock: Clock;\n private readonly metrics: IMetricsSink;\n // The store's own drivers, kept so the lifecycle helpers and the `*Into` verbs reuse them instead of making\n // you re-pass deps. `storageDriver` is set only when `storage` was a raw IStorageDriver (a pre-built StorageChunkSource has\n // no underlying driver to write through).\n private readonly storageDriver: IStorageDriver | undefined;\n private readonly registry: IRegistryDriver | undefined;\n private readonly keystore: IKeystore | undefined;\n private readonly requireEncryption: boolean;\n /** Resolved store-level per-op budget (null = disabled); the admin scans use it, with a per-op override. */\n private readonly budget: Budget | null;\n\n /**\n * Refuse any option key the store does not take, at the top level or inside a group, naming each one.\n *\n * An option the store ignored would do nothing and look as if it had \u2014 a typo'd `cache.maxChunk`, a key from\n * another library's config spread into this one \u2014 so every key is checked against {@link OPTION_KEYS}.\n */\n private static rejectUnknownOptions(options: CloudRoaringOptions): void {\n // A nullish or non-object bag never reaches `resolveStorageSource` \u2014 the constructor reads\n // `options.seams?.clock` first and would throw a raw TypeError. Report it here, typed, instead.\n if (options === null || options === undefined || typeof options !== 'object') {\n throw new ValidationError(\n 'CloudRoaring needs an options object with a `storage` key \u2014 got ' +\n (options === null ? 'null' : typeof options),\n );\n }\n const bag = options as unknown as Record<string, unknown>;\n const unknown: Array<{ group: OptionGroup | null; key: string }> = [];\n for (const key of Object.keys(bag)) {\n if (!(OPTION_KEYS.top as readonly string[]).includes(key)) unknown.push({ group: null, key });\n }\n const groups = Object.keys(OPTION_KEYS).filter((g): g is OptionGroup => g !== 'top');\n for (const group of groups) {\n const value = bag[group];\n if (value === undefined) continue;\n const offOk = group === 'retry' || group === 'budget';\n if (value === false && offOk) continue;\n // A group that is not an object configures nothing: `encryption: true` would build a cleartext store. The\n // built-in tag, not `instanceof`, so a boxed `new Boolean(true)` and a Map from another realm are caught.\n const tag = Object.prototype.toString.call(value).slice(8, -1);\n if (typeof value !== 'object' || value === null || NOT_A_GROUP[tag] !== undefined) {\n const got = typeof value !== 'object' ? typeof value : NOT_A_GROUP[tag];\n throw new ValidationError(\n `CloudRoaring's \\`${group}\\` must be an object${offOk ? ' or `false`' : ''} \u2014 got ${got}`,\n );\n }\n const known = OPTION_KEYS[group] as readonly string[];\n for (const key of Object.keys(value)) if (!known.includes(key)) unknown.push({ group, key });\n }\n if (unknown.length === 0) return;\n const takes = (keys: readonly string[]): string => keys.map((k) => `\\`${k}\\``).join(', ');\n const named = [...new Set(unknown.map((u) => u.group))];\n throw new ValidationError(\n `CloudRoaring does not take ${takes(unknown.map((u) => (u.group === null ? u.key : `${u.group}.${u.key}`)))}. ` +\n named\n .map((g) =>\n g === null\n ? `The store takes ${takes(OPTION_KEYS.top)}.`\n : `\\`${g}\\` takes ${takes(OPTION_KEYS[g])}.`,\n )\n .join(' ') +\n ' https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/api-reference.md#build-a-store--new-cloudroaringoptions',\n );\n }\n\n constructor(options: CloudRoaringOptions) {\n CloudRoaring.rejectUnknownOptions(options);\n const clock = options.seams?.clock ?? new SystemClock();\n const rng = options.seams?.rng ?? new SystemRng();\n // Wrap the user sink so a throwing/buggy sink can never break I/O (observability is best-effort).\n const metrics = safeMetrics(options.metrics ?? NOOP_METRICS);\n const cache = new BoundedLru<string, CodecBitmap>({\n maxEntries: options.cache?.maxChunks ?? DEFAULT_CACHE_MAX_CHUNKS,\n ttlMs: options.cache?.ttlMs,\n clock,\n });\n // Resolve the Storage seam to a StorageChunkSource: a raw IStorageDriver is wrapped into the `.crbm` storage source\n // here (with the store's registry/keystore) so drivers are wired once; a pre-built source is used as-is.\n const resolved = resolveStorageSource(options, clock);\n let storage: StorageChunkSource = resolved.source;\n // Resilience on by default: wrap the source so transient faults retry with jittered backoff. `false` opts\n // out (e.g. the injected client already retries); a RetryPolicy tunes it.\n if (options.retry !== false) {\n // The policy is a partial, and the rest is filled from the default \u2014 so tuning one field does not mean\n // restating all five, and `{ onRetry }` alone is a legal, useful value.\n //\n // Field by field with `??`, NOT `{ ...DEFAULT, ...overrides }`. A spread lets a key that is *present with\n // value `undefined`* overwrite the default instead of falling back to it, and `exactOptionalPropertyTypes`\n // is off, so `retry: { baseDelayMs: cfg.baseDelayMs }` typechecks clean when `cfg.baseDelayMs` is absent \u2014\n // the ordinary shape for a value read from env or JSON. The result was `NaN` delays; `SystemClock.sleep`\n // takes the `setTimeout(resolve, NaN)` path, which Node coerces to 1 ms, so bounded jittered backoff\n // silently became a ~1 ms hot retry loop with the read still succeeding and the retry metric still\n // emitting. That is the thundering-herd and denial-of-wallet protection gone with nothing to see.\n // A `Partial` policy is what puts this in reach: were a whole `RetryPolicy` required, each would be a compile\n // error.\n const { onRetry: userOnRetry, ...ov } = options.retry ?? {};\n const policy: RetryPolicy = {\n maxAttempts: ov.maxAttempts ?? DEFAULT_RETRY_POLICY.maxAttempts,\n baseDelayMs: ov.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,\n maxDelayMs: ov.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,\n backoffFactor: ov.backoffFactor ?? DEFAULT_RETRY_POLICY.backoffFactor,\n jitter: ov.jitter ?? DEFAULT_RETRY_POLICY.jitter,\n };\n const retryOpts: RetryingOptions = {\n clock,\n rng,\n policy,\n // Bridge transient-fault retries into the metrics stream, then call the user's own hook.\n onRetry: (info) => {\n metrics.onEvent({\n kind: 'retry',\n reason: 'transient',\n attempt: info.attempt,\n delayMs: info.delayMs,\n });\n userOnRetry?.(info);\n },\n };\n storage = new RetryingStorageChunkSource(storage, retryOpts);\n this.retryOptions = retryOpts;\n }\n // Resolve the denial-of-wallet budget once (validates; `false` \u21D2 null = disabled) and share it between the\n // engine (count/iterate/combines) and the facade's admin scans (subjectReport/eraseSubject).\n this.budget = resolveBudget(options.budget, DEFAULT_BUDGET);\n const deps: EngineDeps = {\n storage,\n cache,\n codec: roaringCodec, // the facade injects the flagship codec; core stays codec-agnostic\n clock,\n metrics,\n budget: this.budget,\n };\n this.engine = new SegmentEngine(deps);\n this.cache = cache;\n // The UNWRAPPED `.crbm` source, kept for `pin()` \u2014 the only reader that resolves a specific generation.\n // `undefined` when the caller supplied a pre-built source, which has nothing to pin.\n this.crbmSource =\n resolved.source instanceof CrbmStorageChunkSource ? resolved.source : undefined;\n this.clock = clock;\n this.metrics = metrics;\n // Keep the raw drivers for the lifecycle helpers (see the fields above). They use the raw drivers directly \u2014\n // a one-shot admin op surfaces a transient fault to the caller rather than retrying under the hood.\n this.storageDriver = resolved.driver;\n this.registry = resolved.registry;\n this.keystore = options.encryption?.keystore;\n this.requireEncryption = options.encryption?.required ?? false;\n }\n\n /**\n * The write-side deps, from the store's own drivers, for the lifecycle helpers and the `*Into` verbs. Requires\n * the store to have been constructed with a **backend**, which supplies both halves: an `IStorageDriver` to\n * write generations through (a pre-built `StorageChunkSource` has none) and the registry holding the pointer\n * every write publishes.\n */\n private lifecycleDeps(op: string): LifecycleDeps {\n if (this.storageDriver === undefined) {\n throw new UnsupportedError(\n `${op} needs the store built with a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, ` +\n `LocalFsStorage or MemoryStorage. A pre-built StorageChunkSource is read-only: it has no ` +\n `IStorageDriver underneath to write generations through. Build the store on one of those backend ` +\n `classes to write.`,\n );\n }\n if (this.registry === undefined) {\n throw new UnsupportedError(\n `${op} needs a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ` +\n `MemoryStorage. A bare IStorageDriver has no generation pointer to publish through, and there is ` +\n `no separate \\`registry\\` option: a backend carries it.`,\n );\n }\n return {\n storage: this.storageDriver,\n registry: this.registry,\n clock: this.clock,\n codec: roaringCodec, // facade injects the flagship codec\n keystore: this.keystore,\n requireEncryption: this.requireEncryption,\n };\n }\n\n /** Get a handle to a segment. Validates the name (non-empty, well-formed, within the encoded-length cap). */\n segment(name: string, options?: SegmentOptions): Segment {\n const ref: SegmentRef = { segment: name, namespace: options?.namespace };\n validateSegmentRef(ref);\n refuseReservedNamespace(ref.namespace);\n const expiresAt = options?.expiresAt;\n if (expiresAt !== undefined) {\n // Fail at the handle, not at the first read that silently returns nothing. The floor is the same one\n // `setRetention` enforces: a seconds-based value would land in 1970 and make the segment permanently\n // and invisibly empty.\n if (\n !Number.isFinite(expiresAt) ||\n !Number.isInteger(expiresAt) ||\n expiresAt < MIN_EXPIRES_AT_MS\n ) {\n throw new ValidationError(\n `segment: expiresAt must be an integer epoch-MILLISECONDS >= ${MIN_EXPIRES_AT_MS}; got ${expiresAt}` +\n ` (a value in seconds lands in 1970 and would make the segment read as permanently empty)`,\n );\n }\n }\n return makeSegment({\n engine: this.engine,\n ref,\n clock: this.clock,\n metrics: this.metrics,\n materialize: (dest, ids, op, options) => this.materialize(dest, ids, op, options),\n pinned: (r, e) => this.pinSegment(r, e),\n combineEngine: (handles) => this.engineForCombine(handles),\n expiresAt,\n });\n }\n\n /**\n * Write `ids` as a **new generation of `dest`** and publish it \u2014 the shared body of the `*Into` verbs. An `*Into`\n * materialisation is a load, and publishes the same way (hard invariant 1): every load that finds a row fences its\n * publish on the row's token; a guarded load (the default, since the empty refusal reads the current generation)\n * also fences on the pointer it judged (`expectFrom`), and one that found no row fences on that absence instead.\n * Only an unguarded load (`allowEmpty: true` and no `guard.minRetained`) onto a segment with no row publishes bare\n * forward-only. The destination's previous generation stays readable until the publish lands (readers re-resolve\n * within `cache.genTtlMs`).\n *\n * This routes through `loadSegment` rather than writing the generation itself, and that is the whole point\n * of it. A materialisation is a load whose ids happen to come from a combine instead of from upstream, so\n * everything `load()` learned the hard way applies unchanged: the generation is written UNPUBLISHED, the\n * guard runs while the old generation is still authoritative, the publish is fenced as above, and a refused\n * object is reclaimed only when a re-read finds the row unchanged (the same token) or gone (hard invariant 1:\n * deleting it after a purge-and-recreate would put a live row over a missing generation).\n *\n * That last check narrows the window rather than closing it: the row read and the delete are two round\n * trips, and `IStorageDriver` has no conditional delete to make them one. the collection a load runs carries\n * the same residual. The failure it leaves is an orphan object, which costs storage until\n * something collects it \u2014 deliberately the cheaper side of the trade.\n *\n * Written and published in one step, with no guard, an empty combine \u2014 a typo'd operand, an `exclude` that\n * swallowed everything, an operand that had not loaded yet \u2014 would silently replace `dest` with an empty\n * generation: the same failure `load()`'s guard exists to prevent, on the same data, reachable without passing\n * any option at all.\n *\n * **A lost race throws.** `loadSegment` reports one as `reason: 'superseded'`; the `*Into` verbs throw\n * {@link WriteConflictError} for it, so a caller can `catch (WriteConflictError)`. That one refusal is\n * translated into the throw, and `MaterializeResult.reason` never carries it.\n *\n * **A `WriteConflictError` does not by itself mean nothing was published**, and that is worth knowing\n * before you write the retry. `'superseded'` covers five different causes \u2014 the write-once PUT collided,\n * the pointer moved, a row appeared where the load found none, the row's token changed, the row was purged \u2014\n * and only the first three are the \"somebody beat us\" the name suggests. A token can also change on a write\n * that is not a supersession at all, such as a `setRetention` on the destination. On top of that, the collection pass that runs AFTER a\n * successful publish can raise the same error. So: treat it as \"re-read the destination and decide\",\n * never as \"the write did not happen\".\n *\n * **And by default it collects nothing**, unlike `load()`. See the `keep` default below.\n */\n private async materialize(\n dest: SegmentRef,\n ids: AsyncIterable<number>,\n op: string,\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n const deps = this.lifecycleDeps(op);\n let result: Awaited<ReturnType<typeof loadSegment>>;\n try {\n result = await loadSegment(dest, ids, deps, {\n ...(options?.allowEmpty === undefined ? {} : { allowEmpty: options.allowEmpty }),\n ...(options?.guard === undefined ? {} : { guard: options.guard }),\n // COLLECT NOTHING by default, which `loadSegment` does not \u2014 it keeps a grace window of 1 and deletes\n // the rest. By default a materialisation collects nothing: the guide states \"**It deletes nothing**,\n // unlike `load()`. The destination's previous generations stay in the bucket until you collect them\", and\n // the ownership table\n // puts that call on the operator. Inheriting `load()`'s collection would silently delete the\n // generations an operator's recovery story depends on \u2014 `rollbackSegment` refuses a collected target \u2014\n // as a side effect of adding a guard whose entire purpose is preventing data loss. Opt in with `keep`.\n keep: options?.keep ?? KEEP_EVERY_GENERATION,\n ...(options?.audit === undefined ? {} : { audit: options.audit }),\n });\n } finally {\n // As `load()` does: this store's view of `dest` is behind whatever just happened, and a throw can still have\n // published first. Left alone, the store read its own write's predecessor: indefinitely, with no timed refresh.\n this.engine.invalidate(dest);\n }\n // Checked on `reason` alone, not `published && reason`: the compiler narrows a const through an equality\n // test, so after this throw `reason` is provably a `MaterializeRefusal` and the return below type-checks\n // without an assertion. `'superseded'` only ever accompanies `published: false` anyway.\n const reason = result.reason;\n if (reason === 'superseded') {\n // The object is durable, but a concurrent writer published a higher generation of `dest` between our\n // numbering and our publish, so ours is an orphan no reader will resolve. Returning it here would name\n // `generation` as \"the destination's new current generation\" \u2014 which is what `MaterializeResult`\n // documents it to be, and it would be false. The destination holds someone else's content.\n //\n // A throw rather than a flag: every other write path in the library reports a lost race loudly, and a\n // materialisation that silently did not take effect is the one outcome a caller cannot detect on its\n // own.\n // `size > 0` distinguishes the two ways a materialisation loses the race, and the operator needs them\n // apart: the object either exists as an orphan above the pointer (collected by the first load that collects\n // once a generation above it is current) or was\n // never written at all, because the write-once PUT itself collided. Telling someone to look for an\n // orphan that does not exist is a wasted investigation.\n // Deliberately does NOT assert which of the four causes it was. \"A newer generation was published first\"\n // is wrong for two of them: a `setRetention` on the\n // destination bumps the row's token without publishing anything, and a purge leaves no row at all.\n // Telling an operator to go looking for a newer generation that does not exist costs a real\n // investigation. `size > 0` is the one thing this path can state as fact.\n const wrote =\n result.size > 0\n ? `generation ${result.generation} was written and did not become current`\n : `nothing was written \u2014 another writer took generation ${result.generation} first`;\n throw new WriteConflictError(\n `${op}: the destination \"${dest.segment}\" changed while this materialisation was in flight, so it ` +\n `never became current: ${wrote}. The pointer may have moved, the row may have been rewritten ` +\n `(a retention policy does this) or purged. Re-read the destination and re-run.`,\n );\n }\n return {\n generation: result.generation,\n published: result.published,\n ...(reason === undefined ? {} : { reason }),\n cardinality: result.cardinality,\n cardinalityBefore: result.cardinalityBefore,\n chunkCount: result.chunkCount,\n size: result.size,\n collected: result.collected,\n };\n }\n\n /**\n * **Subject access (GDPR Art. 15 / CCPA right-to-know): which segments is this id a member of?**\n *\n * Enumerates the **registered** segments (via the store's own `registry`) and does a `has(id)` on each \u2014 no\n * drivers to re-pass. Complete only over registered segments (every loaded segment has a row, so build the\n * store on the backend the loads used). There is deliberately **no `id \u2192 segments` reverse index** \u2014 that would\n * tax every load for a rare request; this admin scan is `O(registered segments)` and touches no hot path. Needs\n * a storage backend (throws {@link UnsupportedError} otherwise).\n *\n * **Current as of the registry row, not as of the reader's cache.** Each segment's resolved generation is\n * compared with the row the scan listed, and a segment whose cached generation differs is re-resolved before the\n * read, so a load or an erasure from another process shows at once \u2014 whatever `cache.genTtlMs` is, `0` included.\n * The comparison is on the generation **and** the row's token, so a segment retired, purged and loaded again from\n * generation 0 while this store held its old generation 0 is told apart too.\n */\n async subjectReport(\n id: number,\n options: {\n namespace?: string;\n allNamespaces?: boolean;\n concurrency?: number;\n budget?: BudgetOption;\n } = {},\n ): Promise<SubjectReport> {\n const registry = this.requireRegistry('subjectReport');\n requireScope(options, 'subjectReport'); // tenancy: explicit namespace, or an { allNamespaces: true } ack\n validateConcurrency(options.concurrency); // fail fast before the (possibly huge) registry scan\n const budget = resolvePerOpBudget(options.budget, this.budget); // partial override inherits the store's tightening\n splitId(id); // fail fast on a non-u32 id even when no segments are registered\n // Bounded INCREMENTALLY: draining the whole registry and only then checking the budget would refuse the\n // work after paying for the list \u2014 measured at 20,000 records buffered under `maxRequests: 2`. This is a\n // GDPR Art. 15 entry point plausibly wired to end-user traffic, so resident memory must be O(budget), not\n // O(fleet size).\n const recs = await collectWithinBudget(\n // A subject cannot be in a due-index row, and charging this request's budget for them would refuse a\n // GDPR Art. 15 report for a reason unrelated to the subject.\n excludingReservedRows(registry.list(options.namespace)),\n budget,\n 'subjectReport',\n );\n // Bounded fan-out of `has()` across registered segments. Order-preserving \u21D2 deterministic result. A has()\n // fault propagates (a report that can't read a segment must fail loud, not silently under-report).\n const membership = await mapWithConcurrency(\n recs,\n options.concurrency ?? DEFAULT_ADMIN_CONCURRENCY,\n async (rec): Promise<SubjectSegmentRef | null> => {\n if (rec.status === 'destroyed') return null; // already unreadable \u2014 never a member\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n // The row this scan just listed is authoritative; the reader's snapshot may be up to `cache.genTtlMs` behind\n // it, or have no timed refresh (`genTtlMs: 0`). An access report must not lag another process's load or\n // erasure, so a segment whose snapshot is not the listed row's is forgotten before the read. The snapshot's\n // version is `<generation>:<row token>` (invariant 1: the row's OCC token is the identity, the number\n // restarts at 0 once a row is purged), so a retired name loaded again is told apart too. Only a segment\n // that differs is re-resolved: one whose row has not moved keeps its snapshot and costs no extra read.\n if (this.crbmSource !== undefined) {\n const held = await this.crbmSource.currentVersion(ref);\n const listed = rec.currentGen === null ? null : `${rec.currentGen}:${String(rec.token)}`;\n if (held !== listed) this.engine.invalidate(ref);\n }\n return (await this.engine.has(ref, id))\n ? { segment: rec.segment, namespace: rec.namespace }\n : null;\n },\n );\n const segments = membership.filter((m): m is SubjectSegmentRef => m !== null);\n return { id, segments, scannedSegments: recs.length };\n }\n\n /**\n * **Subject erasure (GDPR Art. 17): remove an id from every segment it's in, with the bit physically gone\n * from the bucket on return.**\n *\n * For each **registered** segment the id is a member of, `eraseIdFromSegment` rewrites the current generation\n * without the id \u2014 every chunk streamed through, one bit cleared \u2014 publishes the rewrite **fenced on the\n * generation it was derived from**, and collects the generation that held the bit. A segment whose current\n * generation does not hold the id is searched anyway, every generation in its bucket: a retained superseded one\n * can still hold it, and so can one above the pointer after a {@link CloudRoaring.rollback}, which the rollback\n * could make current again. Each holder is deleted \u2014 below the pointer by a `keep: 0` collection, above it one\n * by one, re-proved against the row first \u2014 and the generations above the pointer that never held the id stay\n * as rollback targets. An entry says `erased: true` only once the call has listed the bucket and read what is\n * left: **no generation of the segment holds the id**. The returned per-segment record is your **erasure ledger** \u2014\n * persist it / route it to your audit sink as the proof of deletion (a `segment.rewrite` audit event is also\n * emitted per rewrite when you pass `audit`).\n *\n * Uses the backend's **own** two halves, so the membership check and the rewrite provably run\n * over the same generation. Requires the store built with a **backend** (throws\n * {@link UnsupportedError} otherwise; a pre-built `StorageChunkSource` store has no `IStorageDriver` to write\n * through; build the store on a backend instead).\n *\n * **One contract remains** (an integrator obligation the library cannot check): **do not load the segment\n * while erasing from it.** A load that lands after the rewrite carries whatever its source held, and the\n * library cannot know that source was meant to exclude the id. Quiesce loads of the affected segments for the\n * duration, or fix the source first and load after. A writer that lands *during* the rewrite is caught: the\n * rewrite's publish is refused **by the fence** \u2014 the publish lands its compare-and-swap only\n * while the pointer is still on the generation the rewrite streamed \u2014 and the entry says `note: 'superseded'`,\n * so re-run. Forward-only alone would NOT refuse it: the rewrite's number goes above everything in the bucket,\n * so the rewrite would out-rank the newer generation and then collect it.\n *\n * A racing **erasure** is caught before that, and reported the same way. It collects with `keep: 0`, taking\n * every generation below its new pointer \u2014 the one this rewrite is streaming, and the object this rewrite\n * just wrote \u2014 so the loser can find its own inputs deleted mid-flight. That surfaces as an outcome rather than\n * an error, read off the row: a moved pointer is a `'superseded'` entry, which a re-run settles, and a segment\n * that a concurrent `dropSegment` tombstoned or a retention sweep purged is left out of the ledger, as a fresh\n * call would leave it out.\n *\n * **Read `note` on any `erased: false` entry \u2014 the two reasons mean different things.** `'superseded'` means\n * another writer (a load, another erasure, or a rollback) moved the pointer mid-call, so **this call** did not\n * erase the id. Re-run: it erases the id if it is still there, and lists nothing for the segment if a racing\n * erasure of the same id already removed it. Do not read `'superseded'` as \"the id is still present\" \u2014\n * read it as \"not done by this call, and the re-run settles it\".\n * `` `error: \u2026` `` is a per-segment fault (caught so one segment can't discard the whole ledger) and it can land\n * on either side of the publish: if the rewrite had not published, the id is still there and a re-run erases\n * it; if the publish succeeded and only the **collection** of the old generation failed, the id is already\n * absent from every read and what remains is an object in the bucket that still contains the bit. The same\n * note, after a publish, can mean a rollback moved the pointer back onto a generation that still holds the id\n * while the collection ran \u2014 then the id is served again, and the entry says so rather than `erased: true`. A\n * re-run searches every generation in the bucket, so it rewrites or collects what is left and usually reports\n * `erased: true`; {@link SubjectErasureEntry.note} says what else a re-run can report. Re-running is otherwise safe\n * and idempotent: a segment the id is no longer in is not listed. Admin-only path;\n * `O(registered segments + superseded generations)`, no hot-path cost: a segment whose current generation lacks\n * the id is searched generation by generation, one open for each other generation in its bucket, and with the\n * keep-everything default of the `*Into` verbs that is one per generation the segment ever had. The per-op\n * `budget` is charged one unit for each segment and one for each generation opened beyond the one its row names,\n * so a fleet with long histories can exhaust it where the segment count alone would not. A segment that does is\n * reported `erased: false` with an `error:` note, before it deletes anything (the one refusal that can come after a\n * rewrite is the last check for a generation a concurrent writer left behind), and the\n * rest of the scan continues: the call itself does not throw for it. Per-subject crypto-shred is infeasible (a subject's bit is\n * co-mingled in a shared container), so this is the single-subject erasure route; whole-segment/tenant erasure\n * is `dropSegment` / the `destroySegment`/`eraseNamespace` free functions.\n */\n async eraseSubject(\n id: number,\n options: {\n namespace?: string;\n allNamespaces?: boolean;\n audit?: IAuditSink;\n concurrency?: number;\n budget?: BudgetOption;\n } = {},\n ): Promise<EraseSubjectResult> {\n const deps = this.lifecycleDeps('eraseSubject');\n requireScope(options, 'eraseSubject'); // tenancy: explicit namespace, or an { allNamespaces: true } ack\n validateConcurrency(options.concurrency); // fail fast before the (possibly huge) registry scan\n const budget = resolvePerOpBudget(options.budget, this.budget); // partial override inherits the store's tightening\n splitId(id); // fail fast on a non-u32 id even when nothing is registered\n // Bounded incrementally \u2014 see subjectReport above. Art. 17 erasure is likewise reachable from ordinary\n // \"delete my account\" traffic, so the enumeration itself has to respect the budget.\n const recs = await collectWithinBudget(\n excludingReservedRows(deps.registry.list(options.namespace)),\n budget,\n 'eraseSubject',\n );\n // The scan charged one unit a segment. A segment whose current generation lacks the id is searched generation by\n // generation, and each open past the current one is charged too, to the same call-wide count. With no budget\n // there is nothing to charge and the drivers are used as they are.\n let opens = 0;\n const charge = (): void => {\n opens += 1;\n checkBudget(budget, recs.length + opens, 'eraseSubject');\n };\n // Bounded fan-out. Each segment is an independent generation, so rewriting distinct segments concurrently is\n // safe. Per-segment faults stay isolated INSIDE each task \u2014 one failure never aborts the ledger \u2014 and the\n // pool preserves input order, so the ledger stays deterministic.\n const entries = await mapWithConcurrency(\n recs,\n options.concurrency ?? DEFAULT_ADMIN_CONCURRENCY,\n async (rec): Promise<SubjectErasureEntry | null> => {\n if (rec.status === 'destroyed') return null; // already crypto-shredded \u2014 nothing to erase\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n try {\n // The rewrite does its own membership check against the CURRENT registry generation \u2014 not the\n // engine's cached view, which may lag a load by up to `cache.genTtlMs`. An Art. 17 erasure must never\n // skip a segment because a read cache hasn't caught up yet.\n const result = await eraseIdFromSegment(\n ref,\n id,\n budget === null\n ? deps\n : { ...deps, storage: new OpenChargingStorage(deps.storage, rec.currentGen, charge) },\n { audit: options.audit },\n );\n if (result.reason === 'not-member' || result.reason === 'absent') return null;\n if (result.reason === 'no-generation') return null; // a row with no data yet holds no id\n if (result.reason === 'destroyed') return null;\n return {\n segment: rec.segment,\n namespace: rec.namespace,\n erased: result.erased,\n fromGeneration: result.fromGeneration,\n generation: result.generation,\n note: result.erased ? undefined : result.reason,\n };\n } catch (err) {\n return {\n segment: rec.segment,\n namespace: rec.namespace,\n erased: false,\n note: `error: ${err instanceof Error ? err.message : String(err)}`,\n };\n } finally {\n // Whatever the outcome, this process's own view of the segment is now suspect: a landed rewrite\n // deleted the generation our caches were built on, and a refused one means somebody else's did.\n // Without this the erasing store keeps answering `true` for the id it just reported erased \u2014 out of\n // RAM, with no storage read for any control to intercept. `finally`, not the happy path: a rewrite\n // that published and then THREW on its collect is precisely the case where this view is stale, and\n // it is reachable from an ordinary retirement landing mid-call.\n //\n // Swallowed, because a `finally` that throws replaces the outcome above it: it would escape the\n // per-segment catch, abort the whole ledger, and discard the error it was masking \u2014 breaking the\n // isolation this fan-out promises. Dropping cache entries cannot fail today; this keeps that from\n // becoming a whole-run failure if it ever can.\n try {\n this.engine.invalidate(ref);\n } catch {\n /* best-effort: never let cache bookkeeping discard a segment's result */\n }\n }\n },\n );\n const erasedFrom = entries.filter((e): e is SubjectErasureEntry => e !== null);\n return { id, erasedFrom, scannedSegments: recs.length };\n }\n\n /**\n * Every generation still in the bucket for this segment, ascending, with the current one marked.\n *\n * What the bucket holds, not what the segment has ever been \u2014 collection deletes superseded objects, so this is\n * the grace window plus whatever has not been collected yet. It is the set {@link CloudRoaring.rollback} can\n * choose from, which is the reason to look at it. One registry read and one listing; it does not open the objects.\n *\n * Needs a backend.\n */\n async generations(ref: SegmentRef): Promise<GenerationEntry[]> {\n validateSegmentRef(ref);\n return listGenerations(ref, this.lifecycleDeps('generations'));\n }\n\n /**\n * Whether a read of this segment would find anything \u2014 the \"do I already have this?\" question, as one\n * registry point read.\n *\n * There is no `create` in this library: {@link CloudRoaring.segment} is a validated address and does no I/O,\n * so naming a segment can never collide with an existing one. A segment starts existing when something is\n * first loaded into it, and this is how you ask whether that has happened.\n *\n * **Not the same as `count() > 0`.** A segment loaded with no ids exists and counts zero. Distinguishing\n * \"never loaded\" from \"loaded, and genuinely empty\" is the thing `count()` cannot do and the reason this\n * exists. It is `false` for a segment whose row was minted ahead of its first load (by `setRetention`) and\n * for a `destroyed` tombstone, because a read answers empty in both cases.\n *\n * Two states answer `true` where a read still gives you nothing: a torn restore (a live pointer whose object\n * was deleted) makes reads *throw* rather than answer empty \u2014 `checkConsistency` is the call for that \u2014 and\n * a handle carrying an expired `expiresAt` reads empty by a rule that lives on the handle, not the row.\n *\n * Not a lock: the answer can change the moment it returns. If it has to hold, use the fence built for that \u2014\n * `load`'s `guard`, or `expectFrom`/`expectToken` on a publish. Needs a storage backend.\n *\n * ```ts\n * if (!(await store.exists({ segment: 'users' }))) {\n * await store.load({ segment: 'users' }, idsFromUpstream);\n * }\n * ```\n */\n async exists(ref: SegmentRef): Promise<boolean> {\n validateSegmentRef(ref);\n return segmentExists(ref, this.requireRegistry('exists'));\n }\n\n /**\n * Every segment the registry knows about, streamed \u2014 optionally scoped to one namespace.\n *\n * The registry is already the list of your segments, which is why you should not keep a second one beside it:\n * a hand-maintained list is a source of truth that drifts from this one the first time a load fails halfway.\n *\n * **An admin/discovery call, not a request-path one.** This is the registry's own enumeration \u2014 a paged\n * LIST over the `registry/` prefix \u2014 so its cost grows with the size of the fleet rather than with what you\n * are looking for.\n *\n * Scoping to a namespace narrows the LIST prefix, so it really is the difference between reading one tenant\n * and reading all of them.\n *\n * It streams, and stopping the iteration stops the scan. It reads the registry directly and is not retried: a\n * transient fault part-way through ends the loop with that error, and calling `segments()` again scans from the\n * start.\n *\n * Yields `destroyed` tombstones and rows with `currentGen: null`, because a filtered enumeration that looks\n * complete is worse than an honest one \u2014 filter on `status`/`currentGen` yourself, or ask\n * {@link CloudRoaring.exists} the narrower question. Needs a storage backend.\n *\n * ```ts\n * for await (const s of store.segments({ namespace: 'active-daily' })) {\n * console.log(s.segment, s.currentGen, s.status);\n * }\n * ```\n */\n segments(options: { namespace?: string } = {}): AsyncIterable<SegmentInfo> {\n if (options.namespace !== undefined) {\n // Synchronously, at the call, where `listSegments` (an async generator, which refuses the reserved\n // namespace too for a direct caller) would only throw at the first iteration.\n validateSegmentRef({ segment: 'x', namespace: options.namespace });\n refuseReservedNamespace(options.namespace);\n }\n return listSegments(this.requireRegistry('segments'), options);\n }\n\n /**\n * Move this segment's pointer **back** to a generation still in the bucket \u2014 the one write in the library that\n * is not forward-only.\n *\n * Forward-only is right for a writer: a load whose ids came from upstream loses nothing by being out-raced, and\n * letting it regress would let a slow loader silently undo a fast one. It is wrong for an operator who has\n * looked at the segment, decided the current generation is wrong, and knows which one they want. So this is\n * reachable only by asking for it by name \u2014 no sweep, retry or reconciliation calls it \u2014 and it is audited\n * (`segment.rollback`), because every other pointer move can be reconstructed from \"a load happened\" and this\n * one cannot.\n *\n * It refuses rather than guesses: a generation not in the bucket (collected, or never written) throws\n * `NotFoundError` naming what *is* available, and a crypto-shredded segment throws\n * {@link ValidationError} because every generation of it is unreadable. Rolling to the generation already\n * current is a no-op that reports itself.\n *\n * It deletes nothing. The generations above the new pointer stay put \u2014 which is what makes this reversible \u2014\n * and are then *above* `currentGen`, where collection never looks. They remain until a load numbers above them\n * (collection then keeps the newest `keep` of what is below its pointer), {@link CloudRoaring.dropSegment}\n * deletes them, or {@link CloudRoaring.eraseSubject} does: all of those present when it rewrites, and only those holding\n * the id when the current generation does not. An operator who has just undone a bad load should not have the\n * evidence collected out from under them, while a rollback target that still holds erased data would make the\n * erasure undoable.\n *\n * A target **above** the pointer needs `{ allowForward: true }`, and is refused with {@link ValidationError}\n * without it: that is also where objects live that were never published, such as a load that wrote its object\n * and died before the publish. Undoing an earlier rollback is what the opt-in is for.\n *\n * Needs a backend.\n */\n async rollback(\n ref: SegmentRef,\n toGeneration: number,\n options: { audit?: IAuditSink; allowForward?: boolean } = {},\n ): Promise<RollbackResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('rollback');\n try {\n return await rollbackSegment(ref, toGeneration, deps, options);\n } finally {\n // The pointer moved under this store's cached view \u2014 and unlike a load, it moved to content the caches may\n // still be holding from before. Drop it either way.\n this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Replace this segment's contents** with `ids`, as one new immutable generation, and make it current.\n *\n * The whole write path in one call: take the next generation number, write the object, check the result is\n * plausible, move the pointer, collect what the move superseded. Composed by hand those are four functions and\n * the one that gets left out is the last, so segments quietly accumulate superseded generations nobody pays\n * attention to and everybody pays for.\n *\n * ```ts\n * const r = await store.load({ segment: 'audience:active' }, idsFromWarehouse, {\n * guard: { minRetained: 0.5 }, // refuse a load that would drop more than half the segment\n * });\n * if (!r.published) console.warn(`load refused: ${r.reason}`);\n * ```\n *\n * **A load REPLACES.** Whatever the stream contains is what the segment contains afterwards, so an upstream\n * query that returns fewer rows than usual is a shrink nobody asked for and an empty one is a wipe \u2014 both\n * reported as a successful write, because at the storage layer they are one. That is what `guard` and the\n * default empty refusal are for, and why they run **between** the write and the publish: the only moment where\n * the new content is known and the old one is still authoritative.\n *\n * **Branch on `published`.** A refusal is a normal outcome, not an exception \u2014 `published: false` with a\n * `reason`, in the same shape as a success \u2014 so a discarded result is a load that silently did nothing, and\n * with the empty guard on by default this verb refuses more readily than any other. Note the sibling `*Into`\n * verbs *throw* on the same superseded condition rather than reporting it; this one follows\n * `eraseIdFromSegment` instead, because three of its four refusals are expected guard outcomes rather than\n * faults.\n *\n * `'superseded'` means another writer got there first: another load took the same generation number, so this\n * one wrote nothing (`size: 0`), or the segment's registry row changed while the load was writing \u2014 another load\n * published, a retention change, a rollback or an erasure wrote the row, or the row was deleted.\n *\n * A refused load deletes the object it wrote before returning \u2014 it sits above `currentGen`, where generation\n * collection deliberately never looks \u2014 but only while the segment's registry row is unchanged or gone. Once\n * another write has changed the row, the generation number it holds may name another incarnation's live object,\n * so it leaves the orphan rather than risk deleting live data. The orphan is an ordinary generation once a later\n * one is current above it, and collection counts it within `keep`.\n *\n * What it **throws** for is a fault rather than an outcome: invalid options or ids, and a crypto-shredded\n * segment (`ValidationError`); a key the keystore cannot provide (`KeyUnavailableError`); a current generation\n * that will not open when a guard reads its size (`IntegrityError`); a driver failure; and a collection pass\n * that could not prove the segment was still the same one (`WriteConflictError`). The last can be raised\n * **after** the publish already landed, so a throw does not by itself mean the load did not take effect \u2014\n * re-read the pointer rather than assuming.\n *\n * Needs a backend (throws {@link UnsupportedError} otherwise).\n */\n async load(\n ref: SegmentRef,\n ids: Iterable<number> | AsyncIterable<number>,\n options: LoadOptions = {},\n ): Promise<LoadResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('load');\n try {\n return await loadSegment(ref, ids, deps, options);\n } finally {\n // This store's view of the segment is now behind whatever just happened \u2014 a published load superseded the\n // generation the caches were built on, and a throw can still have published before failing its collect.\n // `finally`, so the one path where the view is most likely stale is not the one path that skips the drop.\n this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Dispose of a segment \u2014 tombstone it, then delete its storage objects.** Irreversible.\n *\n * The operation a rolling window needs: `destroySegment` crypto-shreds (bytes unreadable everywhere including\n * backups, but still sitting in your bucket and still billed, and it requires encryption), while this one\n * removes the storage and works on a cleartext segment. On an encrypted segment it does both.\n *\n * Pass `{ dryRun: true }` first \u2014 it reports the generations it *would* delete and changes nothing. That\n * matters more than the `confirmSegment` guard for anything automated, because in a loop the guard is the same\n * variable twice.\n *\n * ```ts\n * for (const day of expiredDays) {\n * // The family in the namespace, the date in the segment \u2014 `registry.list(namespace)` then enumerates\n * // exactly this family's buckets, which a flat `active:2026-08-01` name cannot do without string-matching.\n * const ref = { namespace: 'active-daily', segment: day };\n * await store.dropSegment(ref, { confirmSegment: ref.segment });\n * }\n * ```\n *\n * **Omitting the namespace addresses a different segment and is a silent no-op** \u2014 you get\n * `{ dropped: false, reason: 'absent' }`, not a throw, so a retention loop with that mistake deletes nothing\n * forever and quietly. Branch on `dropped`, and treat `reason: 'absent'` as the alert.\n *\n * **Inspect `generationsRemaining`.** Empty is the normal outcome; non-empty means the storage was NOT fully\n * reclaimed and the drop should be re-run. A load that was already writing when the tombstone landed still\n * finishes its object, so a single sweep can miss it \u2014 this call re-sweeps and then reports whatever it still\n * could not remove rather than returning a result that looks like a clean drop.\n *\n * Reads become empty within `cache.genTtlMs` (default 2 s), not instantly: a store that had already read this\n * segment may answer from its cached generation + cached chunks until that window lapses, or, while the registry\n * cannot be read because of a transient fault, until a retry 500 ms apart reaches it again. A reader that never\n * touched it sees empty at once. **That bound needs a registry and `cache.genTtlMs > 0`.** A store with no registry\n * (a bare `IStorageDriver`), with `cache.genTtlMs: 0`, or on a storage source built with no clock, has no timed\n * refresh. It notices the drop only when a read has to fetch\n * from a deleted generation or its reader cache evicts the segment, and until then a chunk it has cached\n * answers without reaching storage, so it can keep answering `true` for a dropped segment indefinitely. Tell\n * it with {@link invalidate}, or restart it.\n *\n * Needs the store built with a **backend** (throws {@link UnsupportedError} otherwise),\n * because it has to enumerate and delete generations \u2014 a pre-built `StorageChunkSource` only reads.\n */\n async dropSegment(\n ref: SegmentRef,\n options: { confirmSegment: string; dryRun?: boolean; audit?: IAuditSink },\n ): Promise<DropResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('dropSegment');\n try {\n return await dropSegment(ref, { registry: deps.registry, storage: deps.storage }, options);\n } finally {\n if (options.dryRun !== true) this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Record when this segment becomes eligible for retirement.** One registry write; nothing is deleted here,\n * and nothing starts running. `retireExpired` is what acts on the policy, and **you** decide when that runs \u2014\n * an EventBridge rule, a CronJob, a queue consumer, whatever your deployment already has. This library starts\n * no background thread (it has to work identically in a Lambda, an edge isolate and a long-lived server).\n *\n * `expiresAt` is an **absolute epoch-ms you compute**, not a duration the library derives. A relative TTL would\n * have to be anchored to something the library knows \u2014 `updatedAt`, or the current generation \u2014 and every load\n * rewrites both, so \"expire 30 days after the last write\" would keep a busy daily bucket alive forever\n * precisely because it is being reloaded.\n *\n * ```ts\n * const DAY = 86_400_000;\n * const ref = { namespace: 'active-daily', segment: '2026-08-05' };\n * await store.setRetention(ref, { expiresAt: Date.now() + 30 * DAY });\n * ```\n *\n * **Works before the first load**: a segment with no registry row yet gets one (`createdRow: true` in the\n * result) with **no Storage generation**, so the policy is recorded ahead of the data and the segment is already\n * enumerable by the sweep; the first load then publishes onto that row.\n *\n * A value in the past is legal and means \"eligible on the next sweep\" \u2014 backfilling a policy onto existing\n * buckets is normal. A value below `MIN_EXPIRES_AT_MS` (2001-09-09) is rejected: it is almost certainly epoch\n * **seconds**, which would read as long-expired and retire the segment on the next pass. Needs a storage\n * backend (throws {@link UnsupportedError} otherwise), and refuses a crypto-shredded segment.\n */\n async setRetention(ref: SegmentRef, policy: RetentionPolicy): Promise<SetRetentionResult> {\n validateSegmentRef(ref);\n return setSegmentRetention(ref, { registry: this.requireRegistry('setRetention') }, policy);\n }\n\n /**\n * **The stored retention policy**, or `null` if the segment has none (or has no registry row, or is a\n * tombstone). Returns the string `'invalid'` for a row whose `expiresAt` is present but unusable \u2014 a\n * hand-edited row, or one from a restore \u2014 so a malformed policy is visible rather than silently reading as\n * \"never expires\" on a segment someone believes is expiring.\n */\n async getRetention(ref: SegmentRef): Promise<RetentionPolicy | null | 'invalid'> {\n validateSegmentRef(ref);\n return getSegmentRetention(ref, { registry: this.requireRegistry('getRetention') });\n }\n\n /**\n * **Cancel a segment's expiry** so no sweep retires it. Returns whether a policy was actually removed (`false`\n * when there was none). A separate verb from `setRetention` on purpose: \"never expire\" as a magic value passed\n * to the setter is how a typo becomes a deletion.\n */\n async clearRetention(ref: SegmentRef): Promise<boolean> {\n validateSegmentRef(ref);\n return clearSegmentRetention(ref, { registry: this.requireRegistry('clearRetention') });\n }\n\n /**\n * **Run the retention sweep: retire every segment whose `expiresAt` has passed.** This is the call that acts on\n * the policies `setRetention` records \u2014 and it is a **call, not a daemon**. Nothing schedules it; you run it from\n * whatever heartbeat your deployment already has (an EventBridge rule, a Kubernetes CronJob, a queue consumer,\n * the job that runs your loads). A library that started a timer would behave differently in a Lambda, an edge\n * isolate and a long-lived server, which is worse than not having one.\n *\n * Each retirement goes through `dropSegment`, so the registry \u2192 Storage ordering, the re-sweep for an object a\n * load was still writing, and the `generationsRemaining` report all come from one implementation rather than\n * two.\n *\n * ```ts\n * // In your scheduled handler. Start with a preview in a new deployment.\n * const preview = await store.retireExpired({ namespace: 'active-daily', dryRun: true });\n * console.log(`would retire ${preview.wouldRetire} of ${preview.scanned} (limited: ${preview.limited})`);\n *\n * const swept = await store.retireExpired({ namespace: 'active-daily' });\n * for (const e of swept.entries) {\n * if (e.action === 'skipped') console.warn(`${e.segment}: ${e.reason}`); // invalid-policy / limit / failed: \u2026\n * if (e.action === 'retired' && e.result.generationsRemaining.length > 0) {\n * console.warn(`${e.segment}: storage not fully reclaimed \u2014 re-run`);\n * }\n * }\n * if (swept.limited) scheduleAnotherPassSoon(); // more are still eligible\n * ```\n *\n * **Read the ledger.** A per-segment *fault* is an entry, not an exception \u2014 a throw from the middle of a fleet\n * sweep would leave the caller unable to say which segments were retired, having already retired some. (A bad\n * argument does throw, and so does a fleet larger than `maxScanSegments`.) `limited: true` means the per-cycle\n * `limit` (default 100) cut the pass short and more are eligible. That cap is charged on **attempts**, not\n * successes, which is what makes it a real bound: `dropSegment` writes the tombstone before sweeping Storage, so a\n * fault in the Storage phase is a segment that is already retired. Retirements are sequential, so `limit` is a\n * wall-clock knob too, and `retired` counts deletions only \u2014 a dry run reports `wouldRetire` instead, so a\n * dashboard summing `retired` can never show a phantom deletion.\n *\n * It also **deletes the tombstone rows its own past retirements left**, after `tombstoneGraceMs` (default 24 h)\n * and only once that segment's Storage generations are provably gone \u2014 collecting a straggler generation itself\n * first, since nothing else ever would for a tombstoned segment. Attribution is a **positive marker the sweep\n * stamps on its own retirements**, not an inference from \"destroyed + an expired policy\": a crypto-shred leaves\n * `retention` untouched, so setting a policy and then honouring a right-to-erasure request mid-window produces\n * exactly that row, and deleting it would destroy the Art. 17 attestation and un-fence the name. By default a\n * segment that held nothing has its row deleted in the pass that retires it, since that row would only fence the name.\n * Pass `purgeTombstones: false` to keep every tombstone, that row included.\n *\n * Needs the store built with a **backend** (throws {@link UnsupportedError} otherwise),\n * because retiring a segment deletes its storage objects. `now` defaults to the store's clock.\n */\n async retireExpired(\n options: Omit<RetireExpiredOptions, 'now'> & { now?: number } = {},\n ): Promise<RetireExpiredResult> {\n const deps = this.lifecycleDeps('retireExpired');\n const result = await retireExpired(\n { registry: deps.registry, storage: deps.storage },\n { ...options, now: options.now ?? this.clock.now() },\n );\n // A retirement tombstones and reclaims segments this store may already have resolved. `dryRun` changes\n // nothing, so it invalidates nothing.\n if (options.dryRun !== true) {\n for (const entry of result.entries) {\n this.engine.invalidate({ segment: entry.segment, namespace: entry.namespace });\n }\n }\n return result;\n }\n\n /**\n * **Forget everything this store has cached about a segment.** Use it after destroying or retiring a segment\n * through a path this store did not perform itself.\n *\n * A store keeps two layers of derived state \u2014 a resolved snapshot per segment (an open `.crbm` reader, plus\n * the DEK it unwrapped) and decoded chunks keyed by generation. Both are built for one event: **a publish\n * that advances `currentGen`**, which the snapshot TTL notices and the generation-keyed cache misses on.\n * Neither notices an event that *destroys* what they were derived from.\n *\n * The store's own writes handle themselves: `load`, `rollback`, `eraseSubject`, `dropSegment` and `retireExpired`\n * here, and a segment's `*Into` verbs, invalidate what they touch. This method is for the cases they cannot see:\n *\n * - **`destroySegment` / `eraseNamespace`**, which are free functions over raw drivers rather than methods\n * here, so a crypto-shred performed beside this store invalidates nothing in it. It keeps its open reader and\n * the unwrapped DEK, and decrypts with them, chunks it had never fetched before the shred included, until its\n * snapshot re-resolves: within `cache.genTtlMs` when the store has a registry and a `genTtlMs` above 0, and\n * otherwise only when its caches let the segment go or a read has to fetch from a generation a sweep collected.\n * A pin answers with no timed bound, until it is told or both caches let it go.\n * - **Another process.** Erasing on one box invalidates nothing on the others; each store bounds its own\n * staleness by `cache.genTtlMs`, and a store with no registry (a bare `IStorageDriver`), with\n * `cache.genTtlMs: 0`, or on a storage source built with no clock has no bound at all: it converges only when a read happens to miss its caches. If a compliance deadline depends on every\n * reader converging, you need to signal them \u2014 this is the call to make when your own fan-out delivers.\n *\n * It also forgets any replacement this store found of a pin's object, so once it is called after a restore puts that\n * object back, the pin reads it again.\n *\n * Synchronous, best-effort, and safe to call for a segment this store has never read.\n *\n * ```ts\n * await destroySegment(ref, { registry: backend.registry }, { confirmSegment: ref.segment });\n * store.invalidate(ref); // this process\n * await bus.publish('cloudbitmaps.invalidate', ref); // and every other one\n * ```\n */\n invalidate(ref: SegmentRef): void {\n validateSegmentRef(ref);\n refuseReservedNamespace(ref.namespace);\n this.engine.invalidate(ref);\n }\n\n /**\n * Build a handle held at the generation `ref` resolves to right now. See {@link Segment.pin}.\n *\n * The pinned handle gets its own engine but **shares the store's chunk cache**, under keys of its own: the\n * pinned view reports the version captured at pin time, marked as a pin's, so its decoded chunks are never\n * those of a live read that fetched across a publish (see {@link PinnedStorageChunkSource.currentVersion}).\n */\n private async pinSegment(ref: SegmentRef, expiresAt?: number): Promise<Segment> {\n const crbm = this.crbmSource;\n if (crbm === undefined) {\n throw new UnsupportedError(\n 'pin() needs the `.crbm` storage source \u2014 pass a backend or a raw IStorageDriver as `storage` (a pre-built StorageChunkSource ' +\n 'that cannot resolve a generation has nothing to pin)',\n );\n }\n // Under the store's retries, as its reads are: a transient fault resolving the pin must not fail pin().\n const at = await this.withRetries(() => crbm.pinGeneration(ref));\n const pinnedAt: PinnedAt = {\n generation: at?.generation ?? null,\n version: at?.version ?? null,\n fingerprint: at?.fingerprint ?? null,\n };\n const pins = new Map([[segmentKey(ref), pinnedAt]]);\n return makeSegment({\n engine: this.engineWithPins(pins),\n ref,\n clock: this.clock,\n metrics: this.metrics,\n materialize: (dest, ids, op, options) => this.materialize(dest, ids, op, options),\n pinned: (r, e) => this.pinSegment(r, e),\n combineEngine: (handles) => this.engineForCombine(handles),\n expiresAt,\n pinnedAt,\n });\n }\n\n /**\n * An engine reading every segment in `pins` at its pinned generation and everything else live, with the store's\n * retries, so a transient fault on a pinned read is retried as it would be on a live one.\n *\n * It **shares the store's chunk cache and its memory bound**, under keys of its own for each pinned segment.\n */\n private engineWithPins(pins: ReadonlyMap<string, PinnedAt>): SegmentEngine {\n const crbm = this.crbmSource;\n if (crbm === undefined) {\n throw new UnsupportedError(\n 'pin() needs the `.crbm` storage source \u2014 pass a backend or a raw IStorageDriver as `storage` (a pre-built StorageChunkSource ' +\n 'that cannot resolve a generation has nothing to pin)',\n );\n }\n const pinned = new PinnedStorageChunkSource(crbm, pins);\n return new SegmentEngine({\n storage:\n this.retryOptions === undefined\n ? pinned\n : new RetryingStorageChunkSource(pinned, this.retryOptions),\n cache: this.cache,\n codec: roaringCodec,\n clock: this.clock,\n metrics: this.metrics,\n budget: this.budget,\n });\n }\n\n /**\n * The engine a combine should run on, given the handles involved.\n *\n * A pinned handle passed as an **operand** must still be read at its pin. Routing by \"which handle the call\n * was made on\" reads it live instead \u2014 `snap.intersect([other])` honours the pin while\n * `other.intersect([snap])` silently does not, and the two are the same question. So the combine collects\n * every pin in play and runs on an engine that honours all of them. With no pins anywhere this is the\n * store's own engine and costs nothing.\n *\n * One engine reads a segment at one generation, so a combine that holds the same segment at two \u2014 two pins of\n * it, or a pin and a live handle \u2014 is refused. Keeping one of them would answer the question for the wrong\n * instant, and say nothing: diffing two snapshots of a segment returned no ids at all.\n */\n private engineForCombine(handles: readonly Segment[]): SegmentEngine | undefined {\n // A combine that pins nothing \u2014 nearly every one \u2014 cannot hold a segment twice at two generations, so it pays\n // one pass over its handles and nothing more.\n if (!handles.some((h) => h.pinnedAt !== undefined)) return undefined;\n const pins = new Map<string, PinnedAt>();\n const held = new Map<string, PinnedAt | undefined>();\n for (const h of handles) {\n const key = h.key();\n const at = h.pinnedAt;\n if (held.has(key)) {\n const before = held.get(key);\n if (!samePin(before, at)) {\n throw new ValidationError(\n `the same segment is in this combine twice, ${twoPins(before, at)}: one call reads a segment at one ` +\n 'generation, so materialise one of them into a segment of its own first, with ' +\n '`intersectInto(dest, [])`',\n );\n }\n } else {\n held.set(key, at);\n }\n if (at !== undefined) pins.set(key, at);\n }\n return this.engineWithPins(pins);\n }\n\n /** `op` under the store's retries, as the store's own reads run; bare when the store has retries off. */\n private withRetries<T>(op: () => Promise<T>): Promise<T> {\n const r = this.retryOptions;\n return r === undefined ? op() : withRetry(op, r.policy ?? DEFAULT_RETRY_POLICY, r);\n }\n\n /** The store's registry, or a typed error naming the operation that needs one. */\n private requireRegistry(op: string): IRegistryDriver {\n if (this.registry === undefined) {\n throw new UnsupportedError(\n `${op} needs a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ` +\n `MemoryStorage. A bare IStorageDriver has no generation pointer to publish through, and there is ` +\n `no separate \\`registry\\` option: a backend carries it.`,\n );\n }\n return this.registry;\n }\n\n /**\n * **Cross-tier DR consistency check.** After a restore/failover, verify every registered segment's `currentGen`\n * actually has its `.crbm` present in Storage \u2014 catching a **torn restore** where the registry (`currentGen`) came\n * back ahead of the object store, so a pointer references a generation that isn't there (reads would then\n * throw). Read-only, bounded fan-out; run it at startup after a restore. Returns `{ checked, inconsistent,\n * errored }` \u2014 `inconsistent` empty \u21D2 coherent; otherwise it names the segments to recover (restore the object\n * store, or roll the registry back to a coherent point). Needs the store built with a **backend**\n * (throws {@link UnsupportedError} otherwise). `destroyed` (crypto-shredded) segments are skipped. Pair it with\n * the DR runbook (docs/guide/disaster-recovery.md).\n *\n * It holds the registry rows it enumerates resident, at most 250,000 of them, and throws\n * `BudgetExceededError` past that rather than report a partial scan as a whole one. This method takes no\n * ceiling of its own: narrow the scan with `namespace`, or call `runConsistencyCheck` over the backend's\n * `storage` and `registry` with a higher `maxScanSegments`.\n */\n async checkConsistency(\n options: { namespace?: string; concurrency?: number } = {},\n ): Promise<ConsistencyReport> {\n const deps = this.lifecycleDeps('checkConsistency');\n return runConsistencyCheck({ storage: deps.storage, registry: deps.registry }, options);\n }\n\n /**\n * **Export (\"eject\") every registered segment's current generation** through the injected `sink`, using only\n * public read APIs \u2014 so your data is readable **without CloudRoaring** (the exit path; see the README's \"Your\n * data stays yours\"). `format: 'roaring'` (default) writes one **portable RoaringBitmap32** per segment\n * (loadable by any roaring library); `'ndjson'` writes newline-delimited ids (zero-dependency, streaming).\n * Enumerates via the store's **own** registry (needs one \u2014 throws {@link UnsupportedError} otherwise) so the\n * enumeration and the read path provably share one registry. Encrypted segments are decrypted transparently\n * **iff** this store was wired with their keystore \u2014 the export is therefore **cleartext**; protect it.\n * Crypto-shredded segments are skipped. A segment that can't be read is isolated into the manifest's `failed[]`\n * (the run continues), so \"a manifest exists\" means the run finished \u2014 check `failed`. The `export-segments`\n * CLI wraps this with a filesystem sink.\n */\n async exportSegments(sink: ExportSink, options: ExportOptions = {}): Promise<ExportManifest> {\n const registry = this.requireRegistry('exportSegments');\n // Pass the codec: core's `runExport` is codec-agnostic and needs one for the `'roaring'` format.\n return runExport(this, registry, sink, {\n ...options,\n codec: options.codec ?? roaringCodec,\n });\n }\n\n /**\n * Planning cost estimate \u2014 pure, no instance/data needed: sizing, sales, what-if. For a real, grounded report\n * from live segment sizes, use `store.segment(name).costReport()`. See {@link CostReport}.\n */\n static estimateCost(input: EstimateInput): CostReport {\n return estimateCost(input);\n }\n}\n\n/**\n * Options common to every chunk-aligned combine (`intersect` / `union` / `andNot`), and the `*Into` verbs.\n *\n * The range, `after` and `through`, applies to every operand and every `exclude`: the combine yields only the ids\n * in `(after, through]` and fetches only the chunks the range overlaps, as {@link Segment.iterate} does.\n */\nexport interface BaseCombineOptions extends IdRange {\n /** Max chunk keys resolved concurrently \u2014 bounds the Storage footprint. A positive integer. */\n readonly concurrency?: number;\n /** Override the store's per-op denial-of-wallet budget for this call (`false` lifts it). */\n readonly budget?: BudgetOption;\n /**\n * Allow an operand naming a segment that does not exist. Default `false`: a combine **refuses** one, because\n * a misspelled or mis-namespaced operand is indistinguishable from a correct one in the result.\n *\n * Reading a segment that does not exist answers empty, and that is right \u2014 but passing one as an operand is\n * different. A suppression list with nobody on it correctly suppresses nothing; one whose `namespace` you\n * omitted *silently* suppresses nothing, and the result is not obviously-empty, it is the full audience and\n * plausibly right. The failure mode is mailing the people who opted out.\n *\n * ```ts\n * // `global-opt-out` lives in the `suppression` namespace. This addresses a DIFFERENT segment:\n * audience.andNot([store.segment('global-opt-out')]); // throws ValidationError\n * audience.andNot([store.segment('global-opt-out', { namespace: 'suppression' })]); // correct\n * ```\n *\n * Set `true` when you genuinely intend to combine against a name that may not exist yet. Checked only for an\n * operand that resolved to no chunks at all, so a normal combine pays nothing for it.\n */\n readonly allowAbsentOperands?: boolean;\n}\n\n/**\n * A combine that can also subtract.\n *\n * `exclude` is why suppression does not need an intermediate segment: applied here it folds into the same\n * chunk-aligned pass, and each exclude is read **only at the keys that survived** \u2014 so a large global opt-out\n * list costs reads proportional to the audience, not to itself.\n */\nexport interface CombineOptions extends BaseCombineOptions {\n /**\n * Segments whose ids are subtracted from the result. An **expired** handle here excludes nothing, in every\n * combine \u2014 it is skipped without being read, exactly as in {@link Segment.andNot}.\n */\n readonly exclude?: Segment[];\n}\n\n/**\n * A combine that WRITES its result \u2014 the extra options `intersect`/`union`/`andNot` have no use for.\n *\n * Separate from {@link CombineOptions} on purpose: `allowEmpty` and `guard` decide whether a generation is\n * published, and a read verb publishes nothing. Offering them on `intersect()` would be offering a parameter\n * that cannot do anything.\n */\nexport interface MaterializeOptions extends CombineOptions {\n /**\n * Audit sink. A materialisation publishes a generation, and a publish is an auditable event\n * (`segment.publish`, exactly as a load emits) \u2014 as is a refusal (`segment.load-refused`).\n *\n * It is on the call rather than on the store because that is where every other auditable operation takes it\n * (`eraseSubject`, `dropSegment`, `retireExpired`): the caller who performs the act decides where the record\n * goes. Without it a `*Into` would be the one write path in the library that could make a generation current\n * and leave no trace in the compliance trail.\n *\n * It sits HERE rather than on {@link BaseCombineOptions} for the reason this type exists: the streaming verbs\n * write nothing, so an audit sink on `intersect()` would be a parameter that could not do anything.\n */\n readonly audit?: IAuditSink;\n /**\n * Publish an empty result over a non-empty destination. Off by default, exactly as on {@link CloudRoaring.load}:\n * an empty combine is far more often a mistake upstream \u2014 a typo'd operand, a segment that has not loaded\n * yet, an `exclude` that swallowed everything \u2014 than an intent, and once it lands it is indistinguishable\n * from a correct run.\n */\n readonly allowEmpty?: boolean;\n /** Refuse an implausible result rather than publish it. Same bounds, and same meaning, as on `load()`. */\n readonly guard?: LoadGuard;\n /**\n * Generations to keep below the new pointer \u2014 see {@link LoadOptions.keep}. A value that is not a non-negative\n * integer throws `ValidationError`.\n *\n * **Defaults to keeping everything**, unlike `load()`, which keeps 1 and collects the rest. An operator's\n * recovery story can depend on a materialisation collecting nothing: `rollbackSegment` refuses a target that\n * has been collected. Pass a number to collect on the way through; `0` keeps only the\n * generation this call publishes.\n */\n readonly keep?: number;\n}\n\n/**\n * An id stream that fails when it is first read. A combine refuses its arguments this way, as the engine's own\n * checks do, so a caller's try/catch around the iteration catches it.\n */\nconst failing = (err: unknown): AsyncIterable<number> => ({\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(err) }),\n});\n\n/** Whether two handles of one segment read it at one generation: both live, or both pinned to one object. */\nconst samePin = (a: PinnedAt | undefined, b: PinnedAt | undefined): boolean =>\n a === undefined || b === undefined\n ? a === b\n : a.generation === b.generation && a.fingerprint === b.fingerprint;\n\n/** How a refusal names two handles of one segment that read it at two generations. */\nconst twoPins = (a: PinnedAt | undefined, b: PinnedAt | undefined): string => {\n const one = (p: PinnedAt | undefined): string =>\n p === undefined ? 'live' : `pinned at generation ${p.generation ?? 'none'}`;\n return a !== undefined && b !== undefined && a.generation === b.generation\n ? `pinned twice at generation ${a.generation ?? 'none'}, as two different objects`\n : `${one(a)} and ${one(b)}`;\n};\n\n/** Every key of `T`, each possibly `undefined`: a copy typed this way fails to compile until it names every field. */\ntype EveryField<T> = { [K in keyof Required<T>]: T[K] | undefined };\n\n/** A read's range, read once, now, from whatever object holds it: a getter or an inherited bound included. */\nconst rangeOf = (options: IdRange): EveryField<IdRange> => ({\n after: options.after,\n through: options.through,\n});\n\n/**\n * A combine's options, read once, now, field by field, for the same reason as {@link rangeOf}. Typed to name every\n * field, so an option added to {@link BaseCombineOptions} and not listed here fails to compile instead of being\n * dropped.\n */\nconst readOptions = (options: BaseCombineOptions): EveryField<BaseCombineOptions> => ({\n ...rangeOf(options),\n concurrency: options.concurrency,\n budget: options.budget,\n allowAbsentOperands: options.allowAbsentOperands,\n});\n\nconst NO_SEGMENTS: readonly Segment[] = [];\n\n/** The empty id stream every expired read path returns \u2014 allocated once, so an expired read costs nothing. */\nconst EMPTY_IDS: AsyncIterable<number> = {\n async *[Symbol.asyncIterator]() {\n // deliberately yields nothing\n },\n};\n\n/**\n * What `andNotInto` takes: the write options without `exclude`, because its `excludes` argument IS the\n * subtraction \u2014 a second one in the options would be two spellings of one thing.\n *\n * Named rather than left as an inline `Omit` so it can be imported and annotated. The read sibling `andNot`\n * solves the same problem the same way, by taking {@link BaseCombineOptions}.\n */\nexport type AndNotIntoOptions = Omit<MaterializeOptions, 'exclude'>;\n\n/**\n * The `keep` a materialisation passes when the caller does not: a grace window wide enough to collect nothing.\n *\n * The collection keeps the newest `keep` generations below the pointer and deletes the rest, so an\n * integer at the top of the range keeps all of them. It has to be an integer \u2014 `loadSegment` validates that,\n * and `Infinity` is rejected \u2014 which is why this is `MAX_SAFE_INTEGER` and not the value that reads more\n * naturally.\n */\nconst KEEP_EVERY_GENERATION = Number.MAX_SAFE_INTEGER;\n\n/** How a `Segment` hands a result stream back to its store to become a new generation of `dest`. */\n/** Build a pinned twin of a handle \u2014 injected into `Segment` so it stays free of store wiring. */\ntype Pin = (ref: SegmentRef, expiresAt?: number) => Promise<Segment>;\n\n/**\n * The engine a combine should run on, given every handle involved \u2014 `undefined` when none is pinned and the\n * store's own engine will do. Injected so `Segment` stays free of store wiring.\n */\ntype CombineEngine = (handles: readonly Segment[]) => SegmentEngine | undefined;\n\ntype Materialize = (\n dest: SegmentRef,\n ids: AsyncIterable<number>,\n op: string,\n options?: MaterializeOptions,\n) => Promise<MaterializeResult>;\n\n/** What a {@link Segment} is built from: the store's own wiring, which is why a handle is not constructible. */\ninterface SegmentParts {\n engine: SegmentEngine;\n ref: SegmentRef;\n clock: Clock;\n metrics: IMetricsSink;\n materialize: Materialize;\n /** Build a pinned twin of this handle \u2014 injected so `Segment` stays free of store wiring. */\n pinned: Pin;\n combineEngine: CombineEngine;\n expiresAt?: number;\n pinnedAt?: PinnedAt;\n}\n\n/** The store's one way to mint a {@link Segment}, bound by the class's static block. */\nlet makeSegment: (parts: SegmentParts) => Segment;\n/** True only while {@link makeSegment} is constructing, so a `new Segment(...)` from plain JS is refused. */\nlet minting = false;\n\n/**\n * A handle bound to one segment \u2014 the read verbs, plus the three `*Into` verbs that write a **new generation**\n * of another segment.\n *\n * **IDs must be integers in `[0, 2^32)`** (dense 32-bit). A non-integer / negative / out-of-range id\n * throws {@link ValidationError}.\n *\n * A handle has no per-id write: data enters a segment as a whole generation (`store.load()`, or one of the\n * `*Into` verbs), and leaves it the same way (`eraseSubject`, `dropSegment`).\n */\nexport class Segment {\n private readonly metricsOn: boolean;\n private readonly engine: SegmentEngine;\n private readonly ref: SegmentRef;\n private readonly clock: Clock;\n private readonly metrics: IMetricsSink;\n private readonly materialize: Materialize;\n private readonly pinned: Pin;\n private readonly combineEngine: CombineEngine;\n /** Absolute epoch-ms deadline from {@link SegmentOptions.expiresAt}; `undefined` \u21D2 this handle never expires. */\n readonly expiresAt?: number;\n /**\n * The generation this handle is held at, when it came from {@link Segment.pin}. Read by the store so a\n * pinned handle passed as an **operand** is still read at its pin rather than live.\n */\n readonly pinnedAt?: PinnedAt;\n\n static {\n makeSegment = (parts) => {\n minting = true;\n try {\n return new Segment(parts);\n } finally {\n minting = false;\n }\n };\n }\n\n /**\n * Not constructible: a handle comes from {@link CloudRoaring.segment}, which wires it to the store's engine,\n * caches and write path. The constructor takes those internals, so it is not part of the surface.\n */\n private constructor(parts: SegmentParts) {\n if (!minting) {\n throw new ValidationError(\n 'a Segment is not constructed directly; call `store.segment(name)`',\n );\n }\n this.engine = parts.engine;\n this.ref = parts.ref;\n this.clock = parts.clock;\n this.metrics = parts.metrics;\n this.materialize = parts.materialize;\n this.pinned = parts.pinned;\n this.combineEngine = parts.combineEngine;\n this.expiresAt = parts.expiresAt;\n this.pinnedAt = parts.pinnedAt;\n this.metricsOn = parts.metrics !== NOOP_METRICS;\n }\n\n /**\n * **Hold this segment at the generation that is current right now**, for as long as you keep the handle.\n *\n * An ordinary handle re-resolves on `cache.genTtlMs`, so a publish part-way through a long job means its second\n * half describes a different instant than its first \u2014 every chunk whole and verified, but the answer covering\n * two moments, with nothing in the result saying so. That is fine for a dashboard and wrong for an export, a\n * reconciliation, or a send that has to match the count you reported. A pin is how you get one instant.\n *\n * ```ts\n * const snap = await store.segment('active-30d').pin();\n * const total = await snap.count(); // the number you report\n * for await (const id of snap.iterate()) { \u2026 } // \u2026and the ids it counted, however long this takes\n * ```\n *\n * **Only this segment is pinned.** `snap.intersect([other])` reads `snap` at its pinned generation and\n * `other` at whatever is current \u2014 pin each segment if you want the whole query held. And a pinned handle\n * used as an *operand* is still read at its pin, never live.\n *\n * **One call reads a segment at one generation**, so a combine that holds this segment at two \u2014\n * `snap0.andNot([snap1])`, or `live.intersect([snap])` \u2014 throws {@link ValidationError} when it is read, and an\n * `*Into` of one throws before it reads anything. Materialise one side first, with `intersectInto(dest, [])`.\n *\n * **A pin knows its object, not only its number.** A name purged and loaded again starts again at generation\n * 0, so a pin of the old segment never reads the new one: what it has already read still answers, as the\n * instant it pinned, and anything it would have to fetch fails with `NotFoundError`, as a swept pin's does.\n *\n * **It is a hold, not a lease.** Nothing here stops a collection deleting the generation underneath\n * you: a pinned read deliberately does **not** heal forward, because silently serving a different generation\n * is the one thing a pin exists to prevent, so it fails instead. Size `keep` to cover your longest pinned\n * job \u2014 see [Generations and `keep`](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/loading.md#generations-and-keep) \u2014 or take the pin on a segment\n * you are not collecting.\n *\n * A segment with no current generation pins nothing and reads empty, exactly as it would unpinned. A pinned\n * segment whose row is later dropped or destroyed fails once it must open its object again, rather than go empty\n * part-way through a call. **A pin\n * keeps the key its reader unwrapped for as long as that reader stays open, and answers from the chunks it\n * decoded for as long as they stay cached.** This store invalidates a pin:\n *\n * - a `load`, a `rollback` or an `*Into` invalidates a pin of the segment it writes;\n * - `dropSegment` invalidates a pin of the segment it drops, and `retireExpired` a pin of each segment its ledger\n * lists, retired or not, neither on a dry run;\n * - `eraseSubject` invalidates a pin of each segment it scans that is not already destroyed.\n *\n * An invalidated pin opens its object again, and fails if that object is gone or replaced, or its row is gone or\n * destroyed.\n * Anything else leaves the pin as it is: after a `destroySegment` beside this store, or an erasure, a drop or a\n * retirement through another store, in this process or another, the pin answers from what it holds until this\n * store's reader cache evicts the pin's reader and its chunk cache evicts the chunks the pin decoded, or\n * {@link CloudRoaring.invalidate} is called on this store. Where the\n * object the pin reads has been deleted, by an erasure, a drop or a sweep, a chunk the pin has not cached fails at\n * once. No timed refresh bounds any of that, as none bounds anything else a pin holds.\n *\n * A replacement a pin has found is remembered, so its later chunk reads fail with no request, until the store\n * forgets it: an invalidation of the segment does, as does a later `pin()` of the same version that opens the object\n * again, and the store remembers at most `cache.readerMax` of them. So once a restore puts the pinned object back,\n * call {@link CloudRoaring.invalidate} on this store: the pin then reads the object again.\n *\n * `pin()` reads the registry row and opens the generation at once, so the pin knows its object before its first\n * read. With a registry, pins of one generation taken while its row is unchanged share one reader while the store\n * keeps it open, pins taken at the same moment included: the first costs a tail read, and a key unwrap for an\n * encrypted segment, whether or not it is read, and the rest cost the row read alone. Without a registry every\n * `pin()` lists the segment's objects and makes the tail read, since only the object can tell two incarnations of\n * a name apart there. It retries a\n * transient fault as the store's reads do, and heals a generation swept between the two, but it fails where the\n * generation cannot be opened: `NotFoundError` for a pointer at a missing object, `IntegrityError` for a damaged\n * or misfiled one.\n *\n * Needs a store built on the `.crbm` storage source (the default when you pass a backend or a raw driver). Throws\n * {@link UnsupportedError} on a store wired with a pre-built source that cannot pin.\n */\n async pin(): Promise<Segment> {\n return this.pinned(this.ref, this.expiresAt);\n }\n\n /**\n * An opaque string that names this handle's segment, namespace included: two handles of one segment have the\n * same key, a live handle and its pins among them. Use it as a `Map` key or a log field when you track handles\n * and have not kept the name you made them with. The format is not specified and is not a storage key, so\n * compare keys, never parse one.\n */\n key(): string {\n return segmentKey(this.ref);\n }\n\n /**\n * Has this handle's deadline passed? **The lazy half of expiry** \u2014 the whole check is one comparison against\n * the injected clock, so it costs nothing on a handle with no deadline and no I/O on one that has expired.\n *\n * Deliberately evaluated per call rather than cached: a long-lived handle created before its deadline must\n * start reading empty the moment the deadline passes, without the caller re-creating it.\n */\n private expired(): boolean {\n return this.expiresAt !== undefined && this.clock.now() >= this.expiresAt;\n }\n\n /**\n * Refuse a materialisation that involves an **expired** handle. Called by the three `*Into` verbs only.\n *\n * On the read verbs an expired handle answers empty, which is the point of lazy expiry. On a *write* the same\n * rule would be destructive in a way nobody asks for: `a.intersectInto(dest, [b])` where `b`'s deadline has\n * quietly passed would, unrefused, replace `dest` with an **empty generation** \u2014 a wipe, reported as a successful\n * write, with the cause (a deadline on a handle somewhere) nowhere in the result. Reads degrade to empty; writes must not.\n *\n * So every handle in the call is checked, `dest` included: an expired `dest` does not change the bytes written,\n * but a caller who put a deadline on the thing they are writing into has said something contradictory and is\n * better told than guessed at. Open a handle without `expiresAt` to write, or drop the deadline.\n *\n * (The broader guard \u2014 refusing to publish an empty or implausible generation over a non-empty one, with an\n * `allowEmpty` override \u2014 covers these verbs too: they route through the same guarded write path as\n * {@link CloudRoaring.load}. The two stay separate because they differ in kind. That one is a REPORTED\n * refusal a caller may legitimately override; an expired handle is a wiring mistake, so it THROWS, before\n * any object is written \u2014 and `allowEmpty: true` does not reach it.)\n *\n * The verbs are `async` so this surfaces as a **rejected promise**, like every other validation in the facade \u2014\n * a synchronous throw out of a promise-returning method escapes a caller who attached `.catch()` instead of\n * awaiting.\n */\n private refuseIfExpired(op: string, dest: Segment, operands: readonly Segment[]): void {\n const stale: string[] = [];\n for (const seg of [this, dest, ...operands]) {\n if (seg.expired())\n stale.push(seg.ref.namespace ? `${seg.ref.namespace}/${seg.ref.segment}` : seg.ref.segment);\n }\n if (stale.length > 0) {\n throw new ValidationError(\n `${op}: refusing to publish a generation while these handles have expired \u2014 ${[...new Set(stale)].join(', ')}. ` +\n `An expired handle reads as empty, so this would write an empty (or short) generation over \"${dest.ref.segment}\". ` +\n `Open the handles without \\`expiresAt\\` if you meant to materialise, or drop the deadline.`,\n );\n }\n }\n\n /**\n * Time an op with the injected clock and emit an `op` metric on completion (success or throw). Skipped\n * entirely when no sink is wired, so the default path pays nothing.\n */\n private async timed<T>(name: MetricOpName, fn: () => Promise<T>): Promise<T> {\n if (!this.metricsOn) return fn();\n const startedAt = this.clock.now();\n try {\n return await fn();\n } finally {\n this.metrics.onEvent({ kind: 'op', name, ms: Math.max(0, this.clock.now() - startedAt) });\n }\n }\n\n /** Membership: one chunk \u2014 the cache, else one ranged GET. Throws {@link ValidationError} on a bad id. */\n has(id: number): Promise<boolean> {\n if (this.expired()) return Promise.resolve(false);\n return this.timed('has', () => this.engine.has(this.ref, id));\n }\n /**\n * Cardinality \u2014 summed from the `.crbm` index with **zero payload reads** on a loaded segment.\n *\n * What this trusts: the answer is the sum of the per-chunk cardinalities the index records, and no payload is\n * decoded to confirm it. The index is checked for internal consistency when the object is opened (each key in\n * range and ascending, each cardinality in `1..65536`, each payload inside the payload region, and, on an\n * unencrypted object, the footer's chunk count and total agreeing with the index), and a corrupt index that is\n * still internally consistent yields a wrong count. `iterate()` and the combines decode the payloads, whose\n * structure is checked.\n */\n count(): Promise<number> {\n if (this.expired()) return Promise.resolve(0);\n return this.timed('count', () => this.engine.count(this.ref));\n }\n /**\n * Every id, ascending, streamed one chunk at a time. Pass a range to read part of the segment: the ids in\n * `(after, through]`, fetching only the chunks the range overlaps. The per-op budget is charged for every chunk in\n * the range, so give a page `through` as well as `after`. On a pinned handle it reads the pinned generation, as a\n * full read does.\n *\n * ```ts\n * // Keyset paging: each page resumes where the one before ended, and stops at its window's end.\n * for await (const id of seg.iterate({ after: previousEnd, through: windowEnd })) await send(id);\n * ```\n *\n * Each bound is optional and an integer in `0..4294967295`; a bad one throws {@link ValidationError} when the\n * stream is first read. `after >= through` is an empty range, which reads nothing. An expired handle reads empty\n * without checking its options, as every read of one does.\n */\n iterate(options?: IdRange): AsyncIterable<number> {\n if (this.expired()) return EMPTY_IDS;\n // Neither bound set is no range at all, which the engine reads on its full-read path.\n const range = options == null ? undefined : rangeOf(options);\n const none = range === undefined || (range.after === undefined && range.through === undefined);\n return this.engine.iterate(this.ref, none ? undefined : range);\n }\n\n /**\n * The options a combine hands the engine, read once, when it is called ({@link readOptions}), with the `exclude`\n * it was given, already reduced to its live handles ({@link liveExcludes}) and mapped down to the plain refs\n * `core` takes. A method rather than a module function because `ref` is class-private \u2014 the encapsulation is\n * worth more than the free function.\n *\n * Each field is named rather than copied with a rest spread: a rest copy takes only own enumerable properties, so\n * a bound held in a getter or inherited from a prototype was dropped, and the read silently widened to the whole\n * segment.\n */\n private refsIn(\n options: CombineOptions | null | undefined,\n exclude: readonly Segment[],\n ): (BaseCombineOptions & { exclude?: SegmentRef[] }) | undefined {\n if (options == null) return undefined;\n return {\n ...readOptions(options),\n exclude: exclude.length > 0 ? exclude.map((o) => o.ref) : undefined,\n };\n }\n\n /**\n * The handles in `options.exclude` that have not expired. **An expired exclusion excludes nothing**, in every\n * combine, so it is dropped here, before the engine is asked for anything: it is never fetched, never\n * checked for absence, and never counted in the pin-consistency check. `exclude` is read once, so a getter sees\n * one call.\n *\n * With no `exclude` this is one property read and a shared empty list, and with none expired it returns the\n * caller's own array, so the common case allocates nothing.\n */\n private liveExcludes(options: CombineOptions | null | undefined): readonly Segment[] {\n const exclude = options?.exclude;\n if (exclude == null || exclude.length === 0) return NO_SEGMENTS;\n return exclude.some((e) => e.expired()) ? exclude.filter((e) => !e.expired()) : exclude;\n }\n\n /**\n * Chunk-skipping intersection: stream the ids in **this** segment AND every segment in `others`, ascending.\n * Fetches only the Storage chunks present in *all* operands (a key absent from any operand contributes nothing\n * and is never downloaded), streaming under a bounded in-flight window \u2014 so the Storage footprint stays small\n * (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer).\n * AND is commutative, so `a.intersect([b])` and `b.intersect([a])` yield the same ids. Pass `budget` to\n * override the store's per-op denial-of-wallet budget for this call (or `false` to lift it).\n */\n intersect(others: Segment[], options?: CombineOptions): AsyncIterable<number> {\n // An expired operand is empty, and anything ANDed with the empty set is empty. Guarding here rather than\n // only in `count()` is what keeps the surface coherent: a segment whose `count()` is 0 must not still\n // contribute members to an intersection.\n if (this.expired() || others.some((o) => o.expired())) return EMPTY_IDS;\n const exclude = this.liveExcludes(options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...others, ...exclude]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.intersect([this.ref, ...others.map((o) => o.ref)], this.refsIn(options, exclude));\n }\n\n /**\n * Materialize `this \u2229 others\u2026` (minus `exclude`) as a **new generation of `dest`** \u2014 `dest`'s previous contents\n * are superseded, not added to. Streaming + bounded-memory; the result is one immutable object published\n * as a load is (the pointer advances to it, fenced on the row), so readers of `dest` see either the old generation\n * or the new one, never a partial. Needs the\n * store built with a backend (throws {@link UnsupportedError} otherwise).\n *\n * **An empty result does NOT overwrite a non-empty destination.** A combine that comes out empty is far more\n * often a mistake upstream \u2014 a typo'd operand, an `exclude` that swallowed everything, an operand that has\n * not loaded yet \u2014 than an intent, and once it publishes it is indistinguishable from a correct run. So the\n * write is **refused and reported**: `published: false`, `reason: 'empty'`, and `dest` keeps what it had.\n * Pass `allowEmpty: true` when emptying the destination is the point.\n *\n * `guard` adds the same plausibility bounds `load()` takes \u2014 `minCardinality` and `minRetained` \u2014 judged\n * against what `dest` held before. A refusal is **reported, not thrown**, exactly as on `load()`; branch on\n * `published`. A lost race is the one outcome that still throws ({@link WriteConflictError}), because a\n * materialisation that silently did not take effect is the one thing a caller cannot detect on its own.\n *\n * A call involving an **expired handle** is refused before any of this. See {@link refuseIfExpired}.\n */\n async intersectInto(\n dest: Segment,\n others: Segment[],\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('intersectInto', dest, [...others, ...(options?.exclude ?? [])]);\n // Refused here, before `materialize` reads anything of `dest`, rather than when the load reads the combine: a\n // broken destination would otherwise answer first, and hide the refusal behind its own error.\n this.combineEngine([this, ...others, ...(options?.exclude ?? [])]);\n return this.timed('intersectInto', () =>\n this.materialize(dest.ref, this.intersect(others, options), 'intersectInto', options),\n );\n }\n\n /**\n * `this \u222A others\u2026`, minus `options.exclude` \u2014 streamed ascending.\n *\n * **The one composite read with no chunk-skipping,** and that is inherent to union rather than a limitation\n * here: an id in *any* operand belongs to the result, so every chunk of every operand must be read.\n * `intersect` prunes any key missing from any operand; union has nothing to prune. It is charged against the\n * same per-op budget, so a wide union is refused rather than quietly billed \u2014 pass `budget` to raise it\n * deliberately. If you find yourself unioning the same segments on every read, materializing the combined\n * segment once (`unionInto`, or a load) is the cheaper shape.\n */\n union(others: Segment[], options?: CombineOptions): AsyncIterable<number> {\n // OR: drop the expired operands and union what is left. All expired \u21D2 empty.\n const live = others.filter((o) => !o.expired());\n if (this.expired()) {\n if (live.length === 0) return EMPTY_IDS;\n return (live[0] as Segment).union(live.slice(1), options);\n }\n if (live.length === 0 && others.length > 0) {\n // Every operand expired \u21D2 just us. But `exclude` is not an operand of the union, it is a subtraction\n // applied to the result, so it still applies: `(this \u222A nothing) \\ exclude` is `this \\ exclude`. Returning\n // a bare `iterate()` here dropped it silently \u2014 an opt-out list that does not apply, on a library whose\n // headline is composable suppression, and reachable from nothing more exotic than a segment handle aging\n // out. `andNot` reads each exclude only where it overlaps, so this is also the cheap spelling.\n // With no exclude it is this segment alone, read as a one-operand union rather than as `iterate()`, so the\n // call's own `budget`, `concurrency` and range apply exactly as they would have to the union.\n const exclude = this.liveExcludes(options);\n return exclude.length > 0 ? this.andNot([...exclude], options) : this.union([], options);\n }\n if (live.length !== others.length) return this.union(live, options);\n const exclude = this.liveExcludes(options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...others, ...exclude]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.union([this.ref, ...others.map((o) => o.ref)], this.refsIn(options, exclude));\n }\n\n /** Materialize `this \u222A others\u2026` (minus `exclude`) as a **new generation of `dest`** \u2014 see {@link intersectInto}. */\n async unionInto(\n dest: Segment,\n others: Segment[],\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('unionInto', dest, [...others, ...(options?.exclude ?? [])]);\n this.combineEngine([this, ...others, ...(options?.exclude ?? [])]); // as intersectInto: before any read\n return this.timed('unionInto', () =>\n this.materialize(dest.ref, this.union(others, options), 'unionInto', options),\n );\n }\n\n /**\n * `this \\ (excludes\u2026)` \u2014 streamed ascending. Suppression on its own.\n *\n * Reads every chunk of `this` (any of them may survive the subtraction) but each exclude **only where it\n * overlaps this segment**, so the cost tracks the segment being filtered rather than the size of the\n * suppression list: at most one read per surviving key of `this`, so subtracting a 61,000-chunk global\n * opt-out list from a 40-chunk audience costs at most 40 reads, not 61,000.\n *\n * An expired handle in `excludes` excludes nothing, and is skipped without being read; if every one has\n * expired the result is `this` whole. An expired `this` is empty. `exclude` on `intersect` and `union` follows\n * the same rule.\n *\n * To filter the *result of an intersection*, do not chain \u2014 pass `exclude` to {@link intersect} instead, so\n * the suppression folds into the same pass rather than materializing an intermediate segment first.\n */\n andNot(excludes: Segment[], options?: BaseCombineOptions): AsyncIterable<number> {\n // MINUS: an expired base is empty; an expired exclusion excludes nothing.\n if (this.expired()) return EMPTY_IDS;\n const liveExcludes = excludes.filter((e) => !e.expired());\n // Every exclusion expired \u21D2 nothing to subtract. Recursing with an empty list would throw, since `andNot`\n // requires at least one operand \u2014 a caller whose suppression list happened to age out must not get an error.\n // It is read as a one-operand union rather than as `iterate()`, so the call's own `budget`, `concurrency` and range\n // still apply.\n // Only the call's own options go on, not an `exclude` a caller routed here with it: the excludes that expired are\n // the ones this branch exists to drop, and an expired exclusion excludes nothing.\n if (liveExcludes.length === 0 && excludes.length > 0) {\n return this.union([], options == null ? undefined : readOptions(options));\n }\n if (liveExcludes.length !== excludes.length) return this.andNot(liveExcludes, options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...excludes]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.andNot(\n this.ref,\n excludes.map((o) => o.ref),\n options == null ? undefined : readOptions(options),\n );\n }\n\n /** Materialize `this \\ (excludes\u2026)` as a **new generation of `dest`** \u2014 see {@link intersectInto}. */\n async andNotInto(\n dest: Segment,\n excludes: Segment[],\n options?: AndNotIntoOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('andNotInto', dest, excludes);\n this.combineEngine([this, ...excludes]); // as intersectInto: before any read\n return this.timed('andNotInto', () =>\n this.materialize(dest.ref, this.andNot(excludes, options), 'andNotInto', options),\n );\n }\n\n /**\n * Grounded cost report for this segment: storage cost from its **real** `.crbm` size (exact, no payload\n * reads); request cost from the supplied `workload` rates. A segment with no Storage generation reports zero\n * storage. The pointer refresh is priced at the store's own `cache.genTtlMs`, or at none when the store never\n * refreshes, unless the workload sets `genTtlMs`. See {@link CostReport} \u2014 it always includes a verdict (incl.\n * the lose-zone).\n */\n async costReport(options?: {\n pricing?: PricingProfile;\n workload?: Workload;\n }): Promise<CostReport> {\n const canMeasure = this.engine.supportsStorageSize;\n const size = canMeasure ? await this.engine.segmentSize(this.ref) : null;\n const refreshMs = this.engine.pointerRefreshMs;\n const workload =\n refreshMs === undefined || options?.workload?.genTtlMs !== undefined\n ? options?.workload\n : { ...options?.workload, genTtlMs: refreshMs };\n return groundedReport({\n storageBytes: size?.sizeBytes ?? 0,\n grounded: canMeasure,\n workload,\n pricing: options?.pricing,\n extraNotes: canMeasure\n ? undefined\n : ['storage source has no sizeOf() \u2014 storage not measured, reported as $0.'],\n });\n }\n}\n\n// ---------------------------------------------------------------------------------------------------\n// What `@cloudbitmaps/roaring` re-exports from `@cloudbitmaps/core`, by name: the store's verbs' types, the errors,\n// the types its signatures name, the backends' shared types, and the constants and helpers an application calls.\n// An application installs this package and imports from it alone. Flavor and driver authors import everything\n// else (the engine, the free-function forms of the store's methods, the retry and budget internals) from\n// `@cloudbitmaps/core` and `@cloudbitmaps/core/driver-kit`. A name added here is a public name of this package, so\n// add one on purpose: `tests/docs/api-reference-sync.test.ts` fails until the API reference lists it.\n// ---------------------------------------------------------------------------------------------------\nexport {\n // Backends\n MemoryStorage,\n LocalFsStorage,\n CrbmStorageChunkSource,\n // Crypto-shred and the retention policy helpers\n destroySegment,\n eraseNamespace,\n excludingReservedRows,\n readRetentionPolicy,\n MIN_EXPIRES_AT_MS,\n // Encryption\n InProcessKeystore,\n NodeAead,\n aadFor,\n // Errors and their copy-safe predicates\n CloudRoaringError,\n ValidationError,\n WriteConflictError,\n IntegrityError,\n NotFoundError,\n UnsupportedError,\n CapabilityError,\n TransientError,\n KeyUnavailableError,\n BudgetExceededError,\n isCloudRoaringError,\n isWriteConflictError,\n isTransientError,\n isNotFoundError,\n isIntegrityError,\n isValidationError,\n // The `.crbm` reader and its blob source\n CrbmReader,\n BufferReader,\n // Metrics, audit and pricing\n CountingMetricsSink,\n RecordingAuditSink,\n DEFAULT_RETRY_POLICY,\n AWS_US_EAST_1_ONDEMAND,\n ELASTICACHE_REDIS_US_EAST_1_ONDEMAND,\n ONE_REDIS_HA_CLUSTER,\n} from '@cloudbitmaps/core';\nexport type {\n Aead,\n AeadSealed,\n AuditEvent,\n BlobReader,\n BlobSink,\n Budget,\n BudgetOption,\n ChunkRef,\n Clock,\n CodecBitmap,\n CodecInterface,\n ConsistencyErrorEntry,\n ConsistencyIssue,\n ConsistencyReport,\n CostReport,\n CrbmCrypto,\n CrbmReaderOptions,\n CrbmStorageChunkSourceOptions,\n DestroyResult,\n DropResult,\n EraseDeps,\n EstimateInput,\n ExportFailure,\n ExportFormat,\n ExportManifest,\n ExportOptions,\n ExportSink,\n ExportWriter,\n ExportedSegment,\n GenKey,\n GenerationEntry,\n GovernanceMeta,\n IAuditSink,\n IKeystore,\n IMetricsSink,\n IRegistryDriver,\n IStorageDriver,\n IdRange,\n InProcessKeystoreOptions,\n LoadGuard,\n LoadOptions,\n LoadRefusal,\n LoadResult,\n LocalFsStorageOptions,\n MemoryStorageOptions,\n MetricEvent,\n MetricOpName,\n MetricsSnapshot,\n NewRegistryRecord,\n PinnedAt,\n PinnedObject,\n PricingProfile,\n RedisNodeType,\n RedisSizing,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n RegistryStatus,\n RetentionPolicy,\n RetireEntry,\n RetireExpiredOptions,\n RetireExpiredResult,\n RetryPolicy,\n Rng,\n RollbackResult,\n SegmentInfo,\n SegmentRef,\n SegmentSize,\n SegmentSizing,\n SetRetentionResult,\n StorageBackend,\n StorageCaps,\n StorageChunkSource,\n Token,\n Workload,\n WrappedDek,\n} from '@cloudbitmaps/core';\n", "/**\n * A storage driver that charges every **generation open** to a per-op budget, for `eraseSubject`.\n *\n * The budget counts fan-out in units of one backend read. `eraseSubject`'s scan charges one unit per registered\n * segment, but a segment whose current generation lacks the id is searched anyway: every other generation in its\n * bucket is opened, one tail read each, and with the keep-everything default of the `*Into` verbs that is one per\n * generation the segment ever had. Those opens are the work the scan's own count leaves out. They are counted here,\n * at the storage port where they happen, so an open added to the erasure later is charged without anyone\n * remembering to charge it, and no option of the public erasure call had to grow.\n *\n * Two opens are never charged, because the segment's unit already pays for them: the generation the row named when\n * the scan listed it, which every erasure must read to decide membership, and an object this call wrote itself,\n * which it reads back to verify. A refusal here comes from a read, and in an erasure the reads that can be refused\n * come before the deletes.\n */\nimport type { GenKey, IStorageDriver, SegmentRef } from '@cloudbitmaps/core';\n\nexport class OpenChargingStorage implements IStorageDriver {\n private readonly free = new Set<number>();\n\n /**\n * @param inner the driver the erasure would otherwise use\n * @param current the generation the segment's row named when it was listed, or `null` when it named none\n * @param charge called once per charged open; it throws to refuse\n */\n constructor(\n private readonly inner: IStorageDriver,\n current: number | null,\n private readonly charge: () => void,\n ) {\n if (current !== null) this.free.add(current);\n }\n\n capabilities(): ReturnType<IStorageDriver['capabilities']> {\n return this.inner.capabilities();\n }\n\n async putImmutable(\n key: GenKey,\n write: Parameters<IStorageDriver['putImmutable']>[1],\n ): ReturnType<IStorageDriver['putImmutable']> {\n const written = await this.inner.putImmutable(key, write);\n this.free.add(key.generation);\n return written;\n }\n\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n return this.inner.getRange(key, offset, length);\n }\n\n /** One `getTail` is one open: a reader takes the footer and the index from it, and reads chunks with `getRange`. */\n async getTail(key: GenKey, maxBytes: number): ReturnType<IStorageDriver['getTail']> {\n if (!this.free.has(key.generation)) this.charge();\n return this.inner.getTail(key, maxBytes);\n }\n\n delete(key: GenKey): Promise<void> {\n return this.inner.delete(key);\n }\n\n list(ref: SegmentRef): AsyncIterable<GenKey> {\n return this.inner.list(ref);\n }\n}\n", "/**\n * The facade's refusal of the namespace the library keeps for its own rows.\n *\n * `cbm.due.` is where the due index stores its pointers, and every fleet-wide scan skips a row there as\n * bookkeeping, so a segment in it would be invisible to an erasure, a consistency check, an export and a retention\n * sweep. `@cloudbitmaps/core` refuses the prefix in every call that takes a ref or a `namespace` option; this is a\n * copy of that one constant, for the checks the facade makes itself before anything reaches core (`segment()`,\n * `invalidate()` and the scope of the two subject scans, which read the registry directly). A test holds the copy\n * equal to core's, so the two cannot drift.\n *\n * Internal: not exported from the package entry.\n */\nimport { ValidationError } from '@cloudbitmaps/core';\n\nexport const RESERVED_NAMESPACE_PREFIX = 'cbm.due.';\n\n/** Throw `ValidationError` for a namespace in the reserved prefix; `undefined` and every look-alike pass. */\nexport function refuseReservedNamespace(namespace: string | undefined): void {\n if (namespace !== undefined && namespace.startsWith(RESERVED_NAMESPACE_PREFIX)) {\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 * SafeBitmap \u2014 the thin wrapper around the `roaring` (CRoaring) engine that owns the\n * untrusted-bytes boundary.\n *\n * All (de)serialization uses the **portable** format \u2014 the stable, bounds-checked one. The\n * `unsafe_frozen_*` formats are never used (they are explicitly documented as crash/attack\n * vectors). Every deserialize is preceded by a hard size cap and a structural check, because the native\n * portable deserializer bounds its reads and checks nothing else (see `portable/layout.ts`).\n */\n// `roaring` is a CommonJS native addon. A *named* ESM import (`import { RoaringBitmap32 } from 'roaring'`)\n// crashes Node's ESM loader \u2014 its static lexer can't see the CJS module's exports \u2014 so we take the runtime\n// values off the module's default export (Node maps a CJS module's `module.exports` to `default`). This\n// keeps the shipped ESM bundle importable under Node ESM. The instance type is derived from the value so we\n// still get a `RoaringBitmap32` type without a (conflicting) second import.\nimport roaring from 'roaring';\nimport type { CodecBitmap, CodecInterface } from '@cloudbitmaps/core';\nimport { IntegrityError } from '@cloudbitmaps/core';\nimport { checkPortableLayout } from './portable/layout';\n\nconst { RoaringBitmap32, SerializationFormat, DeserializationFormat } = roaring;\ntype RoaringBitmap32 = InstanceType<typeof RoaringBitmap32>;\n\nexport class SafeBitmap implements CodecBitmap {\n private readonly bitmap: RoaringBitmap32;\n\n private constructor(bitmap: RoaringBitmap32) {\n this.bitmap = bitmap;\n }\n\n static empty(): SafeBitmap {\n return new SafeBitmap(new RoaringBitmap32());\n }\n\n static fromValues(values: Iterable<number>): SafeBitmap {\n return new SafeBitmap(new RoaringBitmap32(values));\n }\n\n /**\n * Cap the size, check the structure, then deserialize with the **portable** format.\n * Throws `IntegrityError` if the input exceeds `maxBytes`, is not a well-formed portable bitmap, or fails to\n * decode \u2014 the native addon is never handed unbounded, malformed or unsafe-format input.\n *\n * The structural check is what makes the decoded bitmap's answers mean anything. The native deserializer\n * bounds its reads and checks nothing else, so bytes of the right length and the wrong shape (containers or\n * values out of order, overlapping runs, a cardinality that disagrees with the bits) decode into a bitmap\n * whose `maximum()`, `has()` and `size` are wrong, and some of those shapes crash the process when used.\n */\n static safeDeserialize(bytes: Uint8Array, maxBytes: number): SafeBitmap {\n if (bytes.length > maxBytes) {\n throw new IntegrityError(`serialized bitmap is ${bytes.length}B, exceeds cap ${maxBytes}B`);\n }\n checkPortableLayout(bytes);\n try {\n return new SafeBitmap(RoaringBitmap32.deserialize(bytes, DeserializationFormat.portable));\n } catch (err) {\n throw new IntegrityError(`failed to deserialize bitmap: ${(err as Error).message}`);\n }\n }\n\n serialize(): Uint8Array {\n return this.bitmap.serialize(SerializationFormat.portable);\n }\n\n /**\n * Convert containers to run-encoding where that is smaller. Representation only \u2014 membership is untouched, and\n * the portable format still round-trips through {@link RoaringCodec.safeDeserialize}.\n *\n * Roaring's third container type is a RUN, and no implementation selects it on its own: it takes an explicit\n * `runOptimize()` pass. Nothing here made that call, so run-shaped ids paid array or bitset prices \u2014 measured\n * at **570\u00D7** for a contiguous 1M-id range (128.1 KiB \u2192 0.2 KiB) and **63\u00D7** for a 2,000-run shape\n * (536.5 KiB \u2192 8.5 KiB). Sparse ids come out byte-identical, so this is never a losing trade; roaring keeps\n * whichever encoding is smaller per container.\n *\n * Those two factors are THIS CALL's own before/after on the same ids. They are not the ones the site quotes\n * (543\u00D7 and 63\u00D7) \u2014 those compare the optimized encoding against the best *fixed* representation at its floor,\n * a different baseline that happens to land near 63\u00D7 on the run shape too. `pnpm bench:encoding` prints both\n * columns; don't carry a figure between them without checking which denominator it had.\n *\n * Called only when writing an immutable objects generation \u2014 see {@link CodecBitmap.optimize} for why the read\n * path deliberately does not.\n */\n optimize(): void {\n this.bitmap.runOptimize();\n }\n\n /**\n * Largest value, or `undefined` when empty. O(1) \u2014 roaring reads it off the last container, so the engine's\n * per-chunk range assertion costs one call per chunk rather than a walk per id. The last container holds the\n * largest value only because {@link SafeBitmap.safeDeserialize} refuses bytes whose containers or values are\n * out of order.\n */\n maximum(): number | undefined {\n return this.bitmap.isEmpty ? undefined : this.bitmap.maximum();\n }\n\n add(value: number): void {\n this.bitmap.add(value);\n }\n\n addMany(values: Iterable<number>): void {\n this.bitmap.addMany(values);\n }\n\n remove(value: number): void {\n this.bitmap.remove(value);\n }\n\n removeMany(values: Iterable<number>): void {\n this.bitmap.removeMany(values);\n }\n\n has(value: number): boolean {\n return this.bitmap.has(value);\n }\n\n get size(): number {\n return this.bitmap.size;\n }\n\n get isEmpty(): boolean {\n return this.bitmap.isEmpty;\n }\n\n clone(): SafeBitmap {\n return new SafeBitmap(this.bitmap.clone());\n }\n\n // The binary set ops take the `CodecBitmap` interface type (per the seam), but a single store is\n // single-codec (homogeneity contract), so `other` is always a `SafeBitmap` here \u2014 reach its private\n // `bitmap` (accessible on same-class instances) for the native op.\n /** In-place union: `this = this \u222A other`. */\n orInPlace(other: CodecBitmap): void {\n this.bitmap.orInPlace((other as SafeBitmap).bitmap);\n }\n\n /** In-place difference: `this = this \\ other`. */\n andNotInPlace(other: CodecBitmap): void {\n this.bitmap.andNotInPlace((other as SafeBitmap).bitmap);\n }\n\n /** In-place intersection: `this = this \u2229 other`. */\n andInPlace(other: CodecBitmap): void {\n this.bitmap.andInPlace((other as SafeBitmap).bitmap);\n }\n\n /** Ascending iterator over the set values. */\n [Symbol.iterator](): IterableIterator<number> {\n return this.bitmap[Symbol.iterator]();\n }\n\n toArray(): number[] {\n return this.bitmap.toArray();\n }\n}\n\n/**\n * The roaring {@link CodecInterface} \u2014 the flagship codec, delegating to {@link SafeBitmap}'s statics. This is\n * the default the `CloudRoaring` facade injects into the engine; `core/` itself never hard-references it once a\n * caller supplies a codec.\n */\nexport const roaringCodec: CodecInterface = {\n empty: () => SafeBitmap.empty(),\n fromValues: (values) => SafeBitmap.fromValues(values),\n safeDeserialize: (bytes, maxBytes) => SafeBitmap.safeDeserialize(bytes, maxBytes),\n};\n", "/**\n * The layout of a portable-roaring bitmap: parsed, and checked for the structure every reader of it assumes.\n *\n * WHY THIS EXISTS. `roaring` deserializes the portable format with CRoaring's\n * `roaring_bitmap_portable_deserialize_safe`, and that function makes exactly one promise: it never reads past the\n * buffer. CRoaring's header says the bitmap it returns must then pass `roaring_bitmap_internal_validate` before\n * anything uses it, and `roaring` neither calls that function nor exposes it. Every other invariant of the format\n * is therefore taken on trust from bytes that come off a storage tier, which hard invariant 5 says are hostile\n * until proven otherwise. What `roaring` 2.7.0 does with such bytes when nothing checks them first:\n *\n * - **Containers out of order.** `maximum()` reads the last container, so a chunk payload listing container 1\n * before container 0 passes the engine's 16-bit range check, and a read then yields container 1's values masked\n * into the chunk: ids the segment does not hold, which `has()` denies.\n * - **Values or runs out of order, duplicated or overlapping.** `has()` binary-searches, so it denies values that\n * iteration yields, `size` counts duplicates, and a range read stops early.\n * - **A run past the end of its container.** `maximum()` wraps to a small value, so the range check passes, and\n * iteration yields values from the next container's id space.\n * - **A run container with no runs.** Iterating it, or intersecting or unioning with it, crashes the process.\n * - **A bitset whose header cardinality disagrees with its bits.** `size` answers the header. Where the header\n * says fewer values than the bits hold, `remove()` converts the container into an array sized by the header and\n * writes every bit into it: a heap overflow in the native addon, and then a crash.\n *\n * None of those is caught by a CRC, which proves only that the bytes are the bytes that were written. Anyone who\n * can write the bucket writes those.\n *\n * WHAT IT CHECKS, which is what `roaring_bitmap_internal_validate` checks, stated on the serialized form: container\n * keys strictly ascend; array values strictly ascend; runs ascend, stay inside their container, and neither overlap\n * nor touch (a writer merges touching runs); a run container has at least one run; a bitset's popcount is the\n * cardinality its header states. And two things the native deserializer ignores and the pure-JS reader uses: every\n * offset in the offset header is where its container really starts, and a run container's header cardinality is\n * the number of values its runs cover. Anything a real writer produces passes, because a real writer produces\n * exactly this structure.\n *\n * WHAT IT COSTS. One pass over the bytes the decode is about to copy anyway, once per decode: never per id, and\n * never on a cache hit. Measured on an M3 Pro under Node 24, with the check, the native deserialize and a CRC32C\n * of the same bytes timed in alternating rounds: about 70 ns for a payload of one small container, 0.7 us for a\n * 2 KB array container, and 2.5 to 3.2 us for an 8 KB one of any kind. That is a third to a half of the CRC32C the\n * `.crbm` reader already computes over the stored payload before it gets here.\n *\n * Both decoders run it: `SafeBitmap.safeDeserialize` before the native addon sees a byte, and the pure-JS reader\n * in `decode.ts`, which builds on the layout it returns. One check in one place is what keeps the two decoders\n * from disagreeing about which bytes are a bitmap.\n *\n * @see https://github.com/RoaringBitmap/RoaringFormatSpec\n */\nimport { IntegrityError } from '@cloudbitmaps/core';\n\n/** Cookie for a bitmap with no run containers. Followed by a u32 container count. */\nconst SERIAL_COOKIE_NO_RUNCONTAINER = 12_346;\n/** Cookie (low 16 bits) for a bitmap that may contain run containers; the high 16 bits hold `count - 1`. */\nconst SERIAL_COOKIE = 12_347;\n/**\n * Below this many containers, a run-cookie bitmap omits the offset header and containers must be located by\n * walking their sizes. At or above it the header is present. (A `NO_RUNCONTAINER` bitmap always has it.)\n */\nconst NO_OFFSET_THRESHOLD = 4;\n/** A container holding more than this many values is stored as a flat 8 KiB bitset rather than a u16 array. */\nconst ARRAY_MAX_CARDINALITY = 4_096;\n/** 65,536 bits, flat. */\nconst BITMAP_CONTAINER_BYTES = 8_192;\n/** The largest value a container holds: its low 16 bits. */\nconst MAX_LOW = 0xffff;\n\n/** A container of sorted `u16` values. */\nexport const ARRAY = 0;\n/** A container of 65,536 bits. */\nexport const BITMAP = 1;\n/** A container of `(start, length)` runs. */\nexport const RUN = 2;\nexport type ContainerKind = typeof ARRAY | typeof BITMAP | typeof RUN;\n\nexport interface PortableContainer {\n /** High 16 bits of every value in this container. */\n readonly key: number;\n /** Number of values. Stored as `cardinality - 1` on the wire, normalized here. */\n readonly cardinality: number;\n readonly kind: ContainerKind;\n /** Absolute byte offset of this container's payload within the source buffer; a run container's run count. */\n readonly offset: number;\n}\n\n/**\n * The error for a field that runs past the buffer. Callers test the bound inline and call this only when it\n * fails, so a well-formed bitmap never builds the message: the test runs once per container, and a string built\n * on every pass would cost a bitmap of many small containers more than the check itself does.\n */\nfunction overrun(bytes: Uint8Array, offset: number, length: number, what: string): IntegrityError {\n return new IntegrityError(\n `portable roaring: ${what} needs bytes [${offset}, ${offset + length}) of a ${bytes.byteLength}-byte buffer`,\n );\n}\n\n/**\n * Parse the portable-format bitmap in `bytes`, and check its structure.\n *\n * An empty buffer is the empty bitmap, as it is to the native addon, which returns one without reading a byte.\n *\n * @throws {IntegrityError} if the cookie is unrecognized, any field runs past the buffer, or the structure is not\n * one a writer produces (see the module header for the list).\n */\nexport function parsePortableLayout(bytes: Uint8Array): PortableContainer[] {\n const containers: PortableContainer[] = [];\n walk(bytes, containers);\n return containers;\n}\n\n/**\n * {@link parsePortableLayout}'s check alone, for a caller that hands the bytes to another decoder afterwards and\n * so has no use for the layout: it allocates nothing per container.\n *\n * @throws {IntegrityError} exactly where {@link parsePortableLayout} does.\n */\nexport function checkPortableLayout(bytes: Uint8Array): void {\n walk(bytes, null);\n}\n\n/** Check every container of `bytes`, appending each one's layout to `out` when there is one to append to. */\nfunction walk(bytes: Uint8Array, out: PortableContainer[] | null): void {\n const length = bytes.byteLength;\n if (length === 0) return;\n const view = new DataView(bytes.buffer, bytes.byteOffset, length);\n\n if (length < 4) throw overrun(bytes, 0, 4, 'the cookie');\n const cookie = view.getUint32(0, true);\n let count: number;\n /** Where the run-container flag bits start, or -1 under the cookie that has none. */\n let runFlagsAt = -1;\n let pos: number;\n if (cookie === SERIAL_COOKIE_NO_RUNCONTAINER) {\n if (length < 8) throw overrun(bytes, 4, 4, 'the container count');\n count = view.getUint32(4, true);\n pos = 8;\n } else if ((cookie & 0xffff) === SERIAL_COOKIE) {\n // The count is packed into the cookie's high half as `count - 1`, so it can never be zero here.\n count = (cookie >>> 16) + 1;\n runFlagsAt = 4;\n const flagBytes = (count + 7) >>> 3;\n if (runFlagsAt + flagBytes > length) {\n throw overrun(bytes, runFlagsAt, flagBytes, 'the run-container bitmap');\n }\n pos = runFlagsAt + flagBytes;\n } else {\n throw new IntegrityError(\n `portable roaring: unrecognized cookie 0x${cookie.toString(16)}, not a portable-format bitmap`,\n );\n }\n\n // Descriptive header: (key, cardinality - 1) per container. Then the offset header, when this layout has one.\n const descriptiveAt = pos;\n if (pos + count * 4 > length) throw overrun(bytes, pos, count * 4, 'the descriptive header');\n pos += count * 4;\n let offsetsAt = -1;\n if (runFlagsAt < 0 || count >= NO_OFFSET_THRESHOLD) {\n if (pos + count * 4 > length) throw overrun(bytes, pos, count * 4, 'the offset header');\n offsetsAt = pos;\n pos += count * 4;\n }\n\n let previousKey = -1;\n // Containers lie back to back from here. That is how the native deserializer finds them (it never reads the\n // offset header), so the offsets are checked against it rather than followed.\n for (let i = 0; i < count; i++) {\n const key = view.getUint16(descriptiveAt + i * 4, true);\n if (key <= previousKey) {\n throw new IntegrityError(\n `portable roaring: container keys are not strictly ascending (${previousKey} then ${key} at index ${i})`,\n );\n }\n previousKey = key;\n const cardinality = view.getUint16(descriptiveAt + i * 4 + 2, true) + 1;\n const isRun =\n runFlagsAt >= 0 && ((bytes[runFlagsAt + (i >>> 3)] as number) & (1 << (i & 7))) !== 0;\n const kind: ContainerKind = isRun ? RUN : cardinality > ARRAY_MAX_CARDINALITY ? BITMAP : ARRAY;\n if (offsetsAt >= 0) {\n const stated = view.getUint32(offsetsAt + i * 4, true);\n if (stated !== pos) {\n throw new IntegrityError(\n `portable roaring: the offset header puts container ${i} at byte ${stated}, but it starts at ${pos}`,\n );\n }\n }\n\n let size: number;\n if (kind === ARRAY) {\n size = cardinality * 2;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (array)`);\n checkArray(view, pos, cardinality, i);\n } else if (kind === BITMAP) {\n size = BITMAP_CONTAINER_BYTES;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (bitmap)`);\n const bits = popcount(view, pos);\n if (bits !== cardinality) {\n throw new IntegrityError(\n `portable roaring: container ${i} (bitmap) holds ${bits} values, but its header says ${cardinality}`,\n );\n }\n } else {\n if (pos + 2 > length) throw overrun(bytes, pos, 2, `container ${i} (run count)`);\n const runs = view.getUint16(pos, true);\n size = 2 + runs * 4;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (run)`);\n const covered = checkRuns(view, pos + 2, runs, i);\n // A header cannot state zero values, so this is also what refuses a run container with no runs, the shape\n // that crashes the native addon when anything iterates it.\n if (covered !== cardinality) {\n throw new IntegrityError(\n `portable roaring: container ${i} (run) covers ${covered} values, but its header says ${cardinality}`,\n );\n }\n }\n out?.push({ key, cardinality, kind, offset: pos });\n pos += size;\n }\n}\n\n/**\n * An array container's values must strictly ascend: `has` binary-searches them and iteration yields them in order.\n *\n * Read two values per `u32` (little-endian, so the first value is the low half): half the loads and half the loop\n * trips of reading them one at a time, which measured about twice as fast.\n */\nfunction checkArray(view: DataView, at: number, cardinality: number, index: number): void {\n let previous = -1;\n let p = at;\n const end = at + cardinality * 2;\n for (; p + 4 <= end; p += 4) {\n const pair = view.getUint32(p, true);\n const first = pair & 0xffff;\n const second = pair >>> 16;\n if (first <= previous || second <= first) throw unordered(index, (p - at) / 2);\n previous = second;\n }\n if (p < end && view.getUint16(p, true) <= previous) throw unordered(index, (p - at) / 2);\n}\n\nfunction unordered(index: number, element: number): IntegrityError {\n return new IntegrityError(\n `portable roaring: container ${index} (array) is not strictly ascending at or after element ${element}`,\n );\n}\n\n/**\n * Runs must ascend, stay inside the container, and leave at least one value between each other: overlapping runs\n * count their shared values twice, and touching ones are two runs a writer would have merged into one. Returns the\n * number of values the runs cover. Each run is one `u32`: its start in the low half, its length in the high.\n */\nfunction checkRuns(view: DataView, at: number, runs: number, index: number): number {\n let covered = 0;\n /** The lowest start the next run may have: one past the value after the previous run's last. */\n let lowest = 0;\n for (let r = 0; r < runs; r++) {\n const run = view.getUint32(at + r * 4, true);\n const start = run & 0xffff;\n const last = start + (run >>> 16);\n if (start < lowest) {\n throw new IntegrityError(\n `portable roaring: container ${index} (run) has run ${r} out of order, overlapping or touching the one before`,\n );\n }\n if (last > MAX_LOW) {\n throw new IntegrityError(\n `portable roaring: container ${index} (run) has run ${r} running past the end of the container`,\n );\n }\n covered += last - start + 1;\n lowest = last + 2;\n }\n return covered;\n}\n\n/** Set bits in a bitset container's 2,048 little-endian `u32` words. */\nfunction popcount(view: DataView, at: number): number {\n let bits = 0;\n for (let p = at, end = at + BITMAP_CONTAINER_BYTES; p < end; p += 4) {\n let w = view.getUint32(p, true);\n w -= (w >>> 1) & 0x5555_5555;\n w = (w & 0x3333_3333) + ((w >>> 2) & 0x3333_3333);\n bits += Math.imul((w + (w >>> 4)) & 0x0f0f_0f0f, 0x0101_0101) >>> 24;\n }\n return bits;\n}\n", "/**\n * The default real-time {@link Clock} \u2014 the production half of the determinism seam.\n *\n * It lives outside `core/`, so `Date.now()`, `setTimeout` and `setImmediate` are allowed here; that separation is\n * the whole point of the seam, and it is lint-enforced on the other side.\n *\n * It sits in its own module rather than in `index.ts` so the facade, the tests and anything else that needs a real\n * clock can import it without importing the whole barrel.\n */\nimport type { Clock } from '@cloudbitmaps/core';\n\n/** Default real-time clock \u2014 lives outside `core/`, so `Date.now()` + timers are allowed here. */\nexport class SystemClock implements Clock {\n now(): number {\n return Date.now();\n }\n\n sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n // A *ref'd* timer, deliberately. Every `sleep` on this clock backs a caller-awaited, bounded retry \u2014 today\n // the transient-retry loop (`withRetry`) that wraps the chunk source. A pending backoff therefore always means unfinished\n // awaited work, so the timer MUST keep the event loop alive until it resolves. An unref'd timer lets a\n // short-lived process \u2014 CLI, Lambda, a bare script \u2014 whose only remaining handle is the backoff timer exit 0\n // mid-retry, silently dropping the awaited operation with neither a result nor a thrown error. When a\n // transient fault repeats (a backend throttling a hot key, say), the backoff timer can be the last handle\n // standing.\n // Retries are bounded (`maxAttempts`/`maxRetries` + `maxDelayMs`), so a ref'd timer can only\n // extend a process by the small remaining backoff budget of work that is genuinely still in flight.\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n\n /**\n * `setImmediate`, and it has to be \u2014 this is the one place where the choice of primitive is the whole feature.\n *\n * A long CPU-bound loop in `core/` (bulk-load is the one that matters) periodically hands the loop back so a\n * co-resident HTTP server keeps answering. Measured on the **synthetic yield-primitive benchmark** \u2014 a\n * 61,035-iteration loop yielding every 1,024, isolating the primitive rather than timing a real load (the\n * end-to-end figures are 519 ms \u2192 24 ms; see `cooperative.ts`, which lists all three experiments):\n *\n * ```text\n * no yield 568 ms wall 568.0 ms worst event-loop gap\n * sleep(0) 555 ms wall 555.2 ms \u2190 a microtask. Yields NOTHING.\n * setImmediate 569 ms wall 13.8 ms \u2190 free, and 41x less starvation\n * setTimeout(1) 625 ms wall 15.0 ms \u2190 +10% wall for no extra relief\n * ```\n *\n * `sleep(0)` resolving on a microtask is correct for its own contract and useless for this: microtasks drain\n * before the loop ever advances a phase, so `await sleep(0)` in a tight loop never lets a single pending I/O\n * callback run. `setImmediate` fires in the check phase *after* pending I/O, which is exactly the ordering a\n * server wants \u2014 inbound requests are serviced before the loop resumes chewing.\n *\n * A timer is not ref'd here (unlike {@link sleep}): a yield expresses \"someone else may go first\", never\n * \"there is outstanding work\" \u2014 and `setImmediate` cannot outlive the turn that scheduled it anyway.\n */\n yieldNow(): Promise<void> {\n return new Promise((resolve) => {\n setImmediate(resolve);\n });\n }\n}\n", "/**\n * The keys `new CloudRoaring(options)` takes: at the top level, and inside each group whose value is an object. The\n * constructor refuses any other key by name, because an option it ignored would do nothing and look as if it had,\n * and the gates that read the docs' samples and the harnesses' option bags hold them to the same table. A test\n * holds the table to the option interfaces, in both directions.\n *\n * NOT part of the public API. It is its own module, rather than an `export` from the barrel, so the constructor\n * and those gates read one copy.\n */\nexport const OPTION_KEYS = {\n top: ['storage', 'cache', 'encryption', 'retry', 'metrics', 'budget', 'seams'],\n cache: ['maxChunks', 'ttlMs', 'genTtlMs', 'readerMax', 'readerMaxBytes'],\n encryption: ['keystore', 'required'],\n retry: ['maxAttempts', 'baseDelayMs', 'maxDelayMs', 'backoffFactor', 'jitter', 'onRetry'],\n budget: ['maxRequests'],\n seams: ['clock', 'rng'],\n} as const satisfies Record<string, readonly string[]>;\n\n/** The groups: the top-level keys whose value, when it is an object, has keys of its own. */\nexport type OptionGroup = Exclude<keyof typeof OPTION_KEYS, 'top'>;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\n/**\n * `export-segments` \u2014 the standalone **eject / data-export** CLI (the exit path; see the README's \"Your data\n * stays yours\"). Dumps every registered segment's current generation to a portable file, so your data is\n * readable **without CloudRoaring**. A thin filesystem wrapper over `CloudRoaring.exportSegments`.\n *\n * Two formats:\n * - `roaring` (default) \u2014 one portable RoaringBitmap32 per segment (`<segment>.roaring`), loadable by any\n * roaring library (Java/Go/Python/Rust/C++/\u2026).\n * - `ndjson` \u2014 newline-delimited ids per segment (`<segment>.ndjson`), zero dependencies to read, streamed.\n *\n * Output layout: `<out>/<namespace|_default>/<segment>.<ext>` + a self-describing `<out>/manifest.json`. A\n * `:` in a name is percent-encoded as `%3A` in the path (a colon cannot go into a Windows filename), so the\n * manifest's names are authoritative and the directory is portable. Files\n * are written to a unique `.part` temp and atomically renamed on completion; the manifest is written last (also\n * atomically), so a directory with a `manifest.json` means the run **finished** (a crash leaves no manifest \u2192\n * re-run). A segment that couldn't be read is isolated into the manifest's `failed[]` and the CLI exits non-zero\n * \u2014 always check it, because \"manifest present\" is *the run finished*, not \"every segment succeeded\". Re-running\n * overwrites the segments it re-exports but does **not** prune files for segments that have since disappeared \u2014\n * **export to a fresh directory** for a clean dump. Artifacts are owner-only (decrypted **cleartext** \u2014 protect it).\n *\n * Ships the **local-filesystem** backend (zero-dependency, the dev/reference target). For a cloud store, wire a\n * short script that builds the backend for the storage you have and calls `store.exportSegments(sink,\n * { format })` with your own sink \u2014 the binary stays SDK-free:\n *\n * new CloudRoaring({ storage: new S3Storage({ bucket }) })\n *\n * One backend object, not a driver pair. Assembling `{ storage, registry }` by hand is refused with a\n * `ValidationError` that names the backend classes.\n *\n * Config is read from the environment (12-factor-friendly):\n * CR_EXPORT_ROOT (required) \u2014 the local-filesystem root holding storage/ registry/\n * CR_EXPORT_OUT (required) \u2014 the output directory for the dump\n * CR_EXPORT_FORMAT roaring | ndjson (default: roaring)\n * CR_EXPORT_NAMESPACE scope the export to one namespace\n */\nimport { randomUUID } from 'node:crypto';\nimport { realpathSync } from 'node:fs';\nimport { mkdir, open, rename, rm, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { encodeNameForPath, namespacePathPart } from '@cloudbitmaps/core/driver-kit';\nimport { CloudRoaring, LocalFsStorage } from '../index';\nimport type { ExportFormat, ExportManifest, ExportSink, SegmentRef } from '../index';\n\nexport interface ExportConfig {\n readonly root: string;\n readonly out: string;\n readonly format: ExportFormat;\n readonly namespace?: string;\n}\n\n/** Parse + validate config from an environment map. Throws a clear `Error` on misconfiguration. */\nexport function parseConfig(env: Record<string, string | undefined>): ExportConfig {\n const root = env.CR_EXPORT_ROOT;\n if (root === undefined || root === '') {\n throw new Error('CR_EXPORT_ROOT is required (the local-filesystem storage root)');\n }\n const out = env.CR_EXPORT_OUT;\n if (out === undefined || out === '') {\n throw new Error('CR_EXPORT_OUT is required (the output directory for the dump)');\n }\n const format = env.CR_EXPORT_FORMAT ?? 'roaring';\n if (format !== 'roaring' && format !== 'ndjson') {\n throw new Error(`CR_EXPORT_FORMAT must be \"roaring\" or \"ndjson\"; got ${format}`);\n }\n const namespace = env.CR_EXPORT_NAMESPACE || undefined; // treat '' (an unset shell var) as \"no filter\"\n return { root, out, format, namespace };\n}\n\n/**\n * A filesystem {@link ExportSink}. Writes each segment to a **unique** `<segment><ext>.<uuid>.part` temp\n * (`O_EXCL` create, mode `0o600`) and atomically renames it into `<out>/<namespace>/<segment><ext>` on `close()`,\n * so a half-written file never masquerades as complete and concurrent exports to the same dir can't clobber one\n * another. Uses a `FileHandle` (not `createWriteStream`) so an I/O fault **rejects the write** rather than\n * emitting an unhandled `'error'` event that would crash the process, and loops on short writes so a partial\n * `write()` never truncates the output. Artifacts are **owner-only** (dir `0o700`, files `0o600`) \u2014 cleartext.\n */\nexport function fsSink(out: string): ExportSink {\n return {\n async open(ref: SegmentRef, ext: string) {\n // Names may contain `:`; a path may not. On Windows `dedup:2026-08-01.roaring` names an NTFS alternate\n // data stream on a file called `dedup` \u2014 the rename SUCCEEDS, the segment is recorded in the manifest\n // rather than `failed[]`, and `readdir` never lists it. A dump whose whole value is being a faithful\n // copy would then assert success over data an ordinary file copy will not carry. Same encoding the\n // LocalFs drivers use, so an export is diffable against the store it came from.\n // `namespacePathPart`, not `encodeNameForPath(ns ?? '_default')`: the sentinel is emitted literally\n // while a caller's namespace is encoded, so a segment in a namespace actually named `_default`\n // does not land in the same directory as the un-namespaced ones.\n const dir = join(out, namespacePathPart(ref.namespace));\n await mkdir(dir, { recursive: true, mode: 0o700 });\n const finalPath = join(dir, `${encodeNameForPath(ref.segment)}${ext}`);\n const tmpPath = `${finalPath}.${randomUUID()}.part`;\n const handle = await open(tmpPath, 'wx', 0o600); // wx = create-exclusive; unique name \u21D2 no collision\n return {\n async write(bytes: Uint8Array): Promise<void> {\n // Loop until every byte lands \u2014 FileHandle.write may do a short write; it rejects on I/O error (no\n // stray 'error' event \u2192 no process crash).\n let off = 0;\n while (off < bytes.length) {\n const { bytesWritten } = await handle.write(bytes, off, bytes.length - off);\n if (bytesWritten === 0) throw new Error('export write made no progress');\n off += bytesWritten;\n }\n },\n async close(): Promise<void> {\n await handle.close();\n try {\n await rename(tmpPath, finalPath);\n } catch (err) {\n await rm(tmpPath, { force: true }); // don't strand the temp if the rename fails\n throw err;\n }\n },\n async abort(): Promise<void> {\n // Discard the partial; best-effort so a failing cleanup never masks the caller's original fault.\n await handle.close().catch(() => {});\n await rm(tmpPath, { force: true });\n },\n };\n },\n };\n}\n\nconst log = (obj: unknown): void => {\n process.stdout.write(`${JSON.stringify(obj)}\\n`);\n};\n\n/** CLI entry: build a LocalFs store, export every enumerated segment, then write the manifest. */\nexport async function main(\n env: Record<string, string | undefined> = process.env,\n now: () => number = () => Date.now(),\n): Promise<ExportManifest> {\n const config = parseConfig(env);\n const storage = new LocalFsStorage(config.root);\n const store = new CloudRoaring({ storage });\n\n const manifest = await store.exportSegments(fsSink(config.out), {\n format: config.format,\n namespace: config.namespace,\n });\n\n // The manifest is written LAST (after every segment file is committed), so its presence marks a finished run \u2014\n // and it's written the same atomic (temp\u2192rename) way, so the marker itself can't be torn by a crash mid-write.\n // Owner-only (0o600) \u2014 the dump is cleartext. (A finished run may still have skipped unreadable segments \u2014 see\n // `manifest.failed`.)\n await mkdir(config.out, { recursive: true, mode: 0o700 });\n const manifestPath = join(config.out, 'manifest.json');\n const manifestTmp = `${manifestPath}.${randomUUID()}.part`;\n await writeFile(\n manifestTmp,\n `${JSON.stringify({ generatedAt: new Date(now()).toISOString(), ...manifest }, null, 2)}\\n`,\n { encoding: 'utf8', mode: 0o600, flag: 'wx' },\n );\n try {\n await rename(manifestTmp, manifestPath);\n } catch (err) {\n await rm(manifestTmp, { force: true });\n throw err;\n }\n // Log AGGREGATES only \u2014 never per-segment names/counts (a segment name can encode sensitive purpose, and stdout\n // is captured by CI/journald/docker, which don't honor the 0o600 boundary). The detail lives in the manifest.\n log({\n event: 'export',\n out: config.out,\n version: manifest.version,\n format: manifest.format,\n totalSegments: manifest.totalSegments,\n totalIds: manifest.totalIds,\n failed: manifest.failed.length,\n });\n return manifest;\n}\n\n/**\n * Was this module executed as the CLI, rather than imported?\n *\n * Compared as URLs because `process.argv[1]` is a path and `import.meta.url` is a `file:` URL, so a string\n * compare would never match \u2014 and through `realpathSync`, which is the part that was missing.\n *\n * Node resolves a module's `import.meta.url` through symlinks but leaves `process.argv[1]` exactly as it was\n * typed. Every normal installation puts a SYMLINK at `node_modules/.bin/export-segments`, and that is the\n * path `npx` and every npm script invoke, so the two sides disagreed and the guard was false: the CLI exited\n * 0 having done nothing at all. Running the real file worked, which is why it looked fine here \u2014 pnpm writes\n * shell shims that exec the real path, so the repo's own package manager hid it while npm and yarn-classic\n * users got silence.\n *\n * BOTH comparisons are kept, because `--preserve-symlinks-main` inverts which one holds. That flag tells\n * Node not to resolve the main entry, so `import.meta.url` becomes the symlink path while `realpathSync`\n * still returns the real one \u2014 the same mismatch, the other way round, and the same silent exit-0 no-op.\n * Some monorepo and bundler setups put it in `NODE_OPTIONS` globally. The literal comparison is the original\n * condition, which was only ever too NARROW: it matches when this module IS the unresolved entry, so adding\n * it back as a disjunct widens without creating a way to run on import.\n *\n * `realpathSync` can throw, and none of those cases mean \"run the CLI\", so they resolve to false. The one\n * that genuinely reaches the catch is `node -` (a script on stdin), where `argv[1]` is the literal string\n * `\"-\"` and resolving it raises `ENOENT`. (Under `node --eval` there is no `argv[1]` at all, so the early\n * return above handles that one.)\n */\nfunction invokedAsCli(): boolean {\n const entry = process.argv[1];\n if (entry === undefined) return false;\n try {\n return (\n import.meta.url === pathToFileURL(entry).href ||\n import.meta.url === pathToFileURL(realpathSync(entry)).href\n );\n } catch {\n return false;\n }\n}\n\nif (invokedAsCli()) {\n main()\n .then((manifest) => {\n if (manifest.failed.length > 0) {\n // The run finished and the manifest is written, but some segments couldn't be read \u2014 signal it non-zero.\n process.stderr.write(\n `${manifest.failed.length} segment(s) failed to export; see manifest.json \"failed\"\\n`,\n );\n process.exitCode = 1;\n }\n })\n .catch((err: unknown) => {\n process.stderr.write(`${(err as Error).message}\\n`);\n process.exit(1);\n });\n}\n", "/**\n * CloudRoaring \u2014 distributed, cloud-native Roaring Bitmaps, read from object storage.\n *\n * The `CloudRoaring` class is the read engine over **loaded** segments: write-once `.crbm` generations in an\n * object store, behind one registry pointer per segment. You wire storage **once**, as a single config object:\n * pass a **backend** as `storage` \u2014 `S3Storage`, `GcsStorage`, `AzureBlobStorage`, `LocalFsStorage` or\n * `MemoryStorage` \u2014 and it carries both halves, the generations and the pointer, from one bucket and one\n * prefix. Add `encryption: { keystore }` for encryption-at-rest / crypto-shred.\n *\n * Two narrower shapes are also accepted for `storage`: a bare {@link IStorageDriver}, which has no pointer and\n * so resolves generations by list-scanning storage (**cleartext and read-only**), and an already-built\n * {@link StorageChunkSource} for advanced reader options you configure yourself.\n *\n * **Data gets in by loading a generation**, never by mutating one: `store.load()` streams a set of ids into one\n * immutable object and advances the segment's pointer to it. The pointer only moves forward, so a load out-raced by\n * a newer generation reports `superseded` instead of landing, and so does one that read the row when the row has\n * changed since. Every other write in the library is a load in\n * disguise \u2014 `intersectInto`/`unionInto`/`andNotInto` write a new generation of their destination, and\n * `eraseSubject` rewrites a generation without one id. Reads (`has`/`count`/`iterate`/`intersect`/`union`/`andNot`)\n * see whole, checksum-verified generations and nothing else.\n *\n * In-process lifecycle helpers \u2014 `eraseSubject`, `subjectReport`, `dropSegment`, `retireExpired`,\n * `checkConsistency`, `exportSegments` \u2014 reuse the store's own drivers, so you never re-pass them (they need the\n * store built with a backend). See the README and the getting-started guide.\n */\n\nimport {\n BoundedLru,\n PinnedStorageChunkSource,\n segmentKey,\n CrbmStorageChunkSource,\n DEFAULT_BUDGET,\n DEFAULT_RETRY_POLICY,\n withRetry,\n isStorageBackend,\n NOOP_METRICS,\n RetryingStorageChunkSource,\n SegmentEngine,\n UnsupportedError,\n ValidationError,\n WriteConflictError,\n MIN_EXPIRES_AT_MS,\n checkBudget,\n collectWithinBudget,\n excludingReservedRows,\n dropSegment,\n eraseIdFromSegment,\n estimateCost,\n groundedReport,\n loadSegment,\n mapWithConcurrency,\n resolveBudget,\n resolvePerOpBudget,\n retireExpired,\n runConsistencyCheck,\n runExport,\n setSegmentRetention,\n clearSegmentRetention,\n getSegmentRetention,\n safeMetrics,\n splitId,\n} from '@cloudbitmaps/core';\nimport { validateSegmentRef } from '@cloudbitmaps/core/driver-kit';\nimport type {\n Budget,\n BudgetOption,\n GenerationEntry,\n LoadGuard,\n LoadOptions,\n LoadRefusal,\n LoadResult,\n RollbackResult,\n Clock,\n CodecBitmap,\n CodecInterface,\n StorageChunkSource,\n ConsistencyReport,\n CostReport,\n EngineDeps,\n DropResult,\n EstimateInput,\n ExportManifest,\n ExportOptions,\n ExportSink,\n IAuditSink,\n IStorageDriver,\n IKeystore,\n IMetricsSink,\n IRegistryDriver,\n StorageBackend,\n MetricOpName,\n PricingProfile,\n RetentionPolicy,\n RetireExpiredOptions,\n RetireExpiredResult,\n RetryPolicy,\n RetryingOptions,\n Rng,\n SetRetentionResult,\n PinnedAt,\n IdRange,\n SegmentRef,\n Workload,\n} from '@cloudbitmaps/core';\nimport { OpenChargingStorage } from './open-charging-storage';\n// This package's reason to exist: the roaring codec the facade injects into the codec-agnostic engine.\nimport { listGenerations, rollbackSegment } from '@cloudbitmaps/core';\nimport { listSegments, segmentExists } from '@cloudbitmaps/core';\nimport type { SegmentInfo } from '@cloudbitmaps/core';\nimport { refuseReservedNamespace } from './reserved-namespace';\nimport { roaringCodec } from './roaring-codec';\nimport { SystemClock } from './system-clock';\nimport { OPTION_KEYS, type OptionGroup } from './option-keys';\n\n/** Default randomness for backoff jitter \u2014 lives outside `core/`, so `Math.random()` is allowed here. */\nclass SystemRng implements Rng {\n /** A float in `[0, 1)`. Jitter only \u2014 never key material, never anything a caller can observe. */\n next(): number {\n return Math.random();\n }\n}\n\nconst DEFAULT_CACHE_MAX_CHUNKS = 1024;\n/** Default in-flight fan-out for the admin scans (`subjectReport`/`eraseSubject`) \u2014 bounded, no thundering herd. */\nconst DEFAULT_ADMIN_CONCURRENCY = 8;\n/** Fail fast on a bad admin `concurrency` BEFORE the (potentially huge) registry scan, not after. */\nfunction validateConcurrency(concurrency: number | undefined): void {\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ValidationError(`concurrency must be a positive integer; got ${concurrency}`);\n }\n}\n\n/**\n * Tenancy guard for the global-scope admin scans (`subjectReport`/`eraseSubject`). Ids live in ONE global\n * `[0, 2\u00B3\u00B2)` space shared across namespaces, so a namespace-less scan reaches into *every* tenant's segments.\n * Require an explicit `namespace`, or a deliberate `{ allNamespaces: true }` ack, so a fleet-wide sweep is never\n * the accidental default on a shared store.\n */\nfunction requireScope(options: { namespace?: string; allNamespaces?: boolean }, op: string): void {\n // A scope names a namespace like a ref does, and these two scans read the registry themselves rather than\n // through a core function that refuses it.\n refuseReservedNamespace(options.namespace);\n if (options.namespace === undefined && options.allNamespaces !== true) {\n throw new ValidationError(\n `${op} scans the global id space across all namespaces \u2014 pass an explicit \\`namespace\\`, ` +\n `or \\`{ allNamespaces: true }\\` to intentionally sweep the whole fleet`,\n );\n }\n}\n\n/**\n * Wiring for a {@link CloudRoaring} store. **Only `storage` is required** \u2014 the minimal call is\n * `new CloudRoaring({ storage: backend })`. A backend resolves generations with one strong read, reads\n * encrypted segments, and unlocks every lifecycle helper; the narrower shapes `storage` also accepts are\n * described on the option itself. Everything else is **optional\n * tuning with sensible defaults** \u2014 resilience/retries are already on, the cache is bounded, metrics are a\n * no-op \u2014 so reach for them only when you need to.\n */\nexport interface CloudRoaringOptions {\n /**\n * Where the store keeps everything. **The only required option.**\n *\n * Pass a {@link StorageBackend} \u2014 `S3Storage`, `GcsStorage`, `AzureBlobStorage`, `LocalFsStorage`,\n * `MemoryStorage` \u2014 and you are done: it carries both halves, the generations and the `currentGen` pointer,\n * configured from one bucket and one prefix. That is the whole wiring, and it is the shape to reach for.\n *\n * **Pass the backend itself, not `backend.storage`.** They differ by one property access and the mistake is\n * silent: `storage: backend` is the store, while `storage: backend.storage` hands over the *driver half*\n * alone, which constructs without complaint and gives you a cleartext, read-only store that fails later on\n * the first write or lifecycle call. `destroySegment` and `eraseNamespace` take `backend.registry`; the store takes `backend`.\n *\n * Two lower-level shapes stay accepted for wiring the facade does not cover:\n *\n * - a **raw {@link IStorageDriver}**, which the store wraps in a {@link CrbmStorageChunkSource}. There is no\n * registry in this shape, so the store resolves generations by list-scanning storage: **cleartext and\n * read-only**. Encrypted segments, the `*Into` verbs and every lifecycle helper need a backend.\n * - an already-built {@link StorageChunkSource}, used as-is, for advanced reader options.\n */\n readonly storage: StorageBackend | IStorageDriver | StorageChunkSource;\n\n /**\n * Memory and staleness bounds for the read path. Every key is optional and every default is already sane;\n * reach for these when a deployment's shape differs from \"a long-running server with room to breathe\".\n */\n readonly cache?: CacheOptions;\n\n /**\n * Encryption at rest. Omit it entirely for a cleartext store \u2014 encryption is opt-in, and a segment's\n * encryption is decided at its **first** generation.\n */\n readonly encryption?: EncryptionOptions;\n\n /**\n * Resilience: by default every read that answers a query retries **transient** faults (throttling, 5xx, dropped\n * connections) with bounded, jittered exponential backoff (see {@link DEFAULT_RETRY_POLICY}): `has`, `count`,\n * `iterate` and the combines, the `*Into` verbs' reads of their operands included, a pinned handle's reads and\n * `pin()` itself. Writes are not retried, and nor are an erasure's reads, a load's guard read, or the calls that\n * read the registry or list the bucket directly (`exists`, `segments`, `generations`, `getRetention`, and the\n * registry scan `subjectReport`, `exportSegments` and `checkConsistency` start from): they report a transient fault to their caller, because a conditional write that lands and then loses its response would, replayed,\n * report its own write as a conflict. Pass a partial policy to tune it \u2014 anything you leave out keeps its\n * default \u2014 or `false` to turn the read retry off (e.g. if your injected client already retries). A GCS download is retried by\n * the GCS driver whatever this says.\n * Deterministic errors (`ValidationError`/`IntegrityError`/`WriteConflictError`/\u2026) are never retried by this\n * layer.\n */\n readonly retry?: RetryOptions | false;\n\n /**\n * Observability sink: receives typed metric events (storage GET/bytes, cache hit/miss, retries, intersection\n * efficiency, op latency). Defaults to a no-op \u2014 emission is skipped entirely when unused (near-zero\n * overhead). Any exception the sink throws is swallowed \u2014 metrics can never break a read.\n */\n readonly metrics?: IMetricsSink;\n\n /**\n * Per-op **denial-of-wallet** budget: the max backend requests a single\n * `count`/`iterate`/`intersect`/`union`/`andNot`/`subjectReport`/`eraseSubject` may fan out into before it's\n * refused with {@link BudgetExceededError} (`eraseSubject` reports an over-budget segment in its ledger instead,\n * see {@link CloudRoaring.eraseSubject}) \u2014 so one runaway op can't drive unbounded GET cost on a shared\n * backend. **On by default, generous** ({@link DEFAULT_BUDGET}: 1,000,000 requests \u2014 a normal op never hits it).\n * Tune with `{ maxRequests }`, override per op (on the combines / `subjectReport` / `eraseSubject`), or set\n * `false` to disable. The check is O(1) (before fan-out), so the hot path is untouched; per-request bytes are\n * separately size-capped, so bounding requests transitively bounds bytes.\n */\n readonly budget?: BudgetOption;\n\n /**\n * Determinism seams, for tests and replayable jobs. Production stores leave this out and get a system clock\n * and a `Math.random`-backed source.\n */\n readonly seams?: SeamOptions;\n}\n\n/** {@link CloudRoaringOptions.cache} \u2014 the memory and staleness bounds. */\nexport interface CacheOptions {\n /** Ceiling on decoded Storage chunks held in RAM (default 1024). */\n readonly maxChunks?: number;\n /** Optional TTL on cached chunks (ms). Omit to keep a chunk until it is evicted by the count bound. */\n readonly ttlMs?: number;\n /**\n * How long (ms) the store trusts a segment's resolved `currentGen` before re-resolving it on the next read\n * (default 2000) \u2014 the bound on read staleness after a load publishes a new generation. Applies when\n * `storage` is a **backend**, whose registry supplies the cheap `currentGen` read the refresh needs. Lazy \u2014 no\n * timer; \u2264 one registry read per segment per window, opening a new reader only when the generation actually\n * advanced.\n *\n * **While the registry cannot be read, the bound stretches.** A refresh that fails with a\n * {@link TransientError} keeps serving the generation the reader holds, and the key it unwrapped, and is tried\n * again 500 ms later (or after this TTL, if shorter), so the store converges within one retry of the registry\n * answering. A refresh that fails with anything else, an access denial or a row that will not parse, is not\n * ridden out: the read that meets it throws that error, and the reader is dropped.\n *\n * `0` turns this timed refresh off, and so does wiring a bare `IStorageDriver`, which has no registry. That is\n * all it does. The store still moves a segment on to whatever generation is current when its reader cache\n * evicts the segment, when a read has to fetch from a generation a sweep deleted, and when it is invalidated,\n * as its own `load`, `rollback`, `eraseSubject` and `*Into` writes do and {@link CloudRoaring.invalidate} does.\n * A read its caches can answer touches no storage, so a sweep alone moves nothing. What `0` gives up is the bound:\n * the store notices another process's publish, erasure or drop only through one of those, whenever that happens. To read\n * one generation for as long as you need it, take a {@link Segment.pin}.\n */\n readonly genTtlMs?: number;\n /**\n * Ceiling on how many segments' `.crbm` readers (each holding a parsed index) the store keeps open at once\n * (default 1024) \u2014 the steady-state memory bound for a long-running server that reads across many segments.\n * Past it the least-recently-used segment's reader is evicted; re-opening it later is one cheap tail GET.\n * Applies whenever the store builds its own read path \u2014 a backend or a bare `IStorageDriver`. A pre-built\n * `StorageChunkSource` manages its own reader cache.\n */\n readonly readerMax?: number;\n /**\n * Aggregate byte ceiling on the parsed `.crbm` indices the open readers hold (default 64 MiB) \u2014 the byte half\n * of the memory bound, complementing the {@link CacheOptions.readerMax} *count* bound. A wide/dense segment's\n * parsed index can reach about 1.3 MB, so a count-only bound could let the open readers pin over a GB and blow a small\n * heap (e.g. a 128 MB Lambda); this evicts the least-recently-used reader once the summed index footprint\n * would exceed the ceiling \u2014 whichever of the count/byte bounds binds first. Lower it for memory-tight\n * deployments that read across wide segments. Applies whenever the store builds its own read path.\n */\n readonly readerMaxBytes?: number;\n}\n\n/** {@link CloudRoaringOptions.encryption} \u2014 encryption at rest and crypto-shred. */\nexport interface EncryptionOptions {\n /**\n * The keystore that mints and unwraps per-segment DEKs. Needs a **backend**: the wrapped DEK lives in the\n * registry, so there is nowhere to put it on a store wired with a bare driver, and that is refused at\n * construction rather than at the first read.\n */\n readonly keystore?: IKeystore;\n /**\n * Refuse to touch a **cleartext** segment \u2014 a guard against silently reading, or writing, data that should be\n * encrypted. Needs a backend, for the same reason as {@link EncryptionOptions.keystore}. Off by default.\n *\n * It refuses **writes** as well as reads, which is easy to miss: the `*Into` verbs and `eraseSubject` both\n * carry it into their write path, so on a cleartext segment a materialisation throws and an erasure records\n * `note: 'error: requireEncryption: \u2026'` in its ledger rather than erasing. And since a segment's encryption is\n * decided at its **first** generation, this cannot be switched on for a segment that already has one \u2014 load\n * into a new encrypted segment and drop the old one.\n */\n readonly required?: boolean;\n}\n\n/**\n * {@link CloudRoaringOptions.retry} \u2014 a partial {@link RetryPolicy} plus the retry callback.\n *\n * Partial on purpose, so tuning one field does not mean restating all five. Anything omitted here keeps its\n * {@link DEFAULT_RETRY_POLICY} value.\n */\nexport interface RetryOptions extends Partial<RetryPolicy> {\n /**\n * Observability: called before each transient-retry backoff wait. Best-effort: an error it throws is\n * swallowed, so it can neither stop the retry nor change the error a read fails with.\n */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/** {@link CloudRoaringOptions.seams} \u2014 injected for deterministic tests and replayable jobs. */\nexport interface SeamOptions {\n /** Defaults to a system clock. */\n readonly clock?: Clock;\n /** Defaults to `Math.random`-backed. Drives transient-retry jitter. */\n readonly rng?: Rng;\n}\n\nexport interface SegmentOptions {\n readonly namespace?: string;\n /**\n * **When this segment stops being readable** \u2014 an absolute epoch-ms instant, declared where the segment is\n * named instead of in a separate `setRetention` call.\n *\n * Every read through this handle checks it first: past the deadline, `has` is `false`, `count` is `0`, and\n * `iterate` yields nothing \u2014 **one integer compare against the injected clock, no I/O, on every backend**.\n * That is Redis's lazy expiry, and it is what makes an expiry *correct* rather than *eventually correct*: a\n * deployment whose sweep is late \u2014 or which has no sweep at all, like a Lambda-only reader \u2014 still stops\n * serving the data on time.\n *\n * **Two things this does NOT do, both deliberate:**\n *\n * - It does not reclaim the bytes. That is {@link CloudRoaring.retireExpired}, and until it runs the data is\n * still stored and still billed. `count()` reporting 0 while objects exist is the expected state in that\n * window, not a bug.\n * - It does not apply to *other* handles. The deadline lives on this handle; a second handle opened without\n * the option reads the segment normally. Record the policy with {@link CloudRoaring.setRetention} to make\n * it durable, fleet-visible, and reclaimable.\n *\n * Must be **milliseconds** since the epoch and at or after {@link MIN_EXPIRES_AT_MS} \u2014 a seconds value would\n * land in 1970 and make the segment permanently unreadable, so it is refused rather than honoured.\n */\n readonly expiresAt?: number;\n}\n\n/** A segment reference in a subject report / erasure ledger. */\nexport interface SubjectSegmentRef {\n readonly segment: string;\n readonly namespace?: string;\n}\n\n/** Result of {@link CloudRoaring.subjectReport} \u2014 the segments an id is a member of (over registered segments). */\nexport interface SubjectReport {\n readonly id: number;\n /** The registered segments the id is currently a member of. */\n readonly segments: SubjectSegmentRef[];\n /** How many registered segments were scanned (the completeness denominator). */\n readonly scannedSegments: number;\n}\n\n/** One segment's entry in an erasure ledger (see {@link EraseSubjectResult}). */\nexport interface SubjectErasureEntry {\n readonly segment: string;\n readonly namespace?: string;\n /**\n * True iff the id **was** in the segment and **no generation of it holds the id now** \u2014 not the current one, not\n * one below the pointer, and not one above it, where a rollback leaves the generations it rolled back from. The\n * current generation is one without it, every generation that held it has been deleted from the bucket, and the\n * call listed the bucket and read what was left before this entry was returned (see\n * {@link CloudRoaring.eraseSubject}).\n */\n readonly erased: boolean;\n /**\n * The generation the id was found in (present whenever the segment was read) \u2014 the newest of them, when the\n * current generation did not hold it and several others did.\n */\n readonly fromGeneration?: number;\n /** The generation written without the id (present whenever one was written). */\n readonly generation?: number;\n /**\n * Why the id was NOT erased from this segment, when `erased` is false. `'superseded'` \u2014 the pointer moved while\n * the call was in flight, by a load, another erasure or a rollback, so **this call** did not erase the id;\n * re-run against the new generation, which erases it if it is still there and reports nothing for the segment\n * if the racing writer already removed it. `` `error: <message>` `` \u2014 an isolated per-segment fault\n * (per-segment faults are recorded so one segment can't discard the whole ledger); re-run after fixing the\n * fault. A budget refusal is one of these: the segment's generations did not fit `budget`, so it was not finished;\n * re-run with a higher `budget`. A fault that landed once part of the work was already done \u2014 a Storage `delete` fault, a collect that\n * could not prove the segment was still the same one, or a generation still holding the id when the bucket was\n * listed at the end, whether or not a rewrite was published first \u2014 also re-runs, but **read what the re-run\n * says**: it usually reports `erased: true` against the generation it found the id in, it reports\n * nothing at all if a racing collector took that generation first (the bit is gone, but no run holds a\n * receipt for it), and if the segment's row has since been purged it is no longer scanned at all \u2014 anything\n * left in its bucket is an orphan, which `store.generations(ref)` lists and `store.dropSegment(ref, {\n * confirmSegment })` deletes; `checkConsistency` and the collection a load runs read rows, so neither reaches it.\n * **Segments the id is not in\n * are not listed, and neither are segments that no longer have a registry row** \u2014 an empty ledger is not by\n * itself proof the id is gone.\n */\n readonly note?: string;\n}\n\n/**\n * The erasure ledger returned by {@link CloudRoaring.eraseSubject} \u2014 your proof-of-deletion artifact. It is a\n * return value only (no library-side persistence): persist it / route it to your audit sink as you see fit.\n */\nexport interface EraseSubjectResult {\n readonly id: number;\n /** Per-segment records for the segments the id was found in (absent segments are not listed). */\n readonly erasedFrom: SubjectErasureEntry[];\n /** How many registered segments were scanned. */\n readonly scannedSegments: number;\n}\n\n/**\n * Why a materialisation did not become current.\n *\n * {@link LoadRefusal} minus `'superseded'`: that one is a lost race, and the `*Into` verbs throw\n * {@link WriteConflictError} for it rather than reporting it. Narrowing the type rather than saying so only\n * in prose means the compiler enforces it, and a caller's exhaustive `switch` has no dead branch.\n */\nexport type MaterializeRefusal = Exclude<LoadRefusal, 'superseded'>;\n\n/** What an `*Into` verb wrote: the new generation of the destination, and whether it became current. */\nexport interface MaterializeResult {\n /**\n * The generation written. Present even when refused: the refusal deleted that object, unless the destination's\n * row changed while it was writing, which leaves it in the bucket.\n */\n readonly generation: number;\n /**\n * Whether this generation is now the destination's current one.\n *\n * `false` when the guard refused the result: an empty one over a non-empty destination, or one outside\n * `guard`'s bounds. Branch on it: a refusal is reported, not thrown, so a caller that ignores it sees a\n * successful-looking result for a write that deliberately did not happen.\n */\n readonly published: boolean;\n /** Set only when `published` is false. A lost race throws {@link WriteConflictError} rather than appearing here. */\n readonly reason?: MaterializeRefusal;\n /** Ids in the generation. */\n readonly cardinality: number;\n /**\n * What the destination held when the guard judged it \u2014 `null` when it had no current generation, **or when\n * no bound needed the read**. The read costs an object-header fetch, so it is taken only when a bound will\n * use it: `allowEmpty: true` with no `guard.minRetained` skips it, and this is `null` even though `dest`\n * was non-empty.\n */\n readonly cardinalityBefore: number | null;\n /** Non-empty chunks in the generation. */\n readonly chunkCount: number;\n /** Bytes of the written object. */\n readonly size: number;\n /**\n * The superseded generations collected after publishing. Empty when nothing was published \u2014 and **also\n * empty on a successful publish** unless you passed `keep`, because a materialisation collects nothing by\n * default. See {@link MaterializeOptions.keep}.\n */\n readonly collected: readonly number[];\n}\n\n/**\n * Resolve the `storage` option to a {@link StorageChunkSource} at construction (wiring-time only \u2014 no hot-path cost).\n *\n * `storage` is discriminated by a **brand** for the backend arm and structurally for the other two: a raw {@link IStorageDriver} exposes `putImmutable`\n * (the byte-mover seam); a pre-built {@link StorageChunkSource} exposes `getChunk` (the engine's read seam). The\n * two interfaces are deliberately **disjoint** on these methods (an invariant the driver SDK maintains, pinned\n * by a test) \u2014 an object exposing *both* is ambiguous and rejected, as is one exposing *neither* (incl. a\n * nullish/non-object value from a JS caller): fail fast with a typed error rather than crash on a probe.\n *\n * A backend is wrapped into a {@link CrbmStorageChunkSource} over its storage half, pinned to its registry,\n * with the config's `encryption` group; a bare driver is wrapped the same way but without a\n * registry; a pre-built source is used as-is. `keystore`/`requireEncryption` are meaningful **only** where the\n * store builds the source itself \u2014 pairing either with a pre-built source is a wiring mistake, so reject it\n * rather than silently ignore it. The `CrbmStorageChunkSource` constructor enforces the rest (a keystore /\n * `requireEncryption` needs a registry, so they need a backend; the driver needs range reads).\n *\n * Returns the resolved `source` (what the engine reads through) **and** the raw `driver` when one was passed \u2014\n * the store keeps the raw driver so its lifecycle helpers and the `*Into` verbs can write generations without\n * you re-passing drivers. `driver` is `undefined` for a pre-built source (there's no underlying `IStorageDriver` to\n * write through, so its writes throw {@link UnsupportedError}).\n */\n/**\n * Work out what the caller handed us, and build the read path from it.\n *\n * Three accepted shapes. A backend is identified by its brand, the other two structurally \u2014 never by `instanceof`, so a backend or driver from a\n * different copy of the package still works (the same reason the error predicates are brand-based).\n */\nfunction resolveStorageSource(\n options: CloudRoaringOptions,\n clock: Pick<Clock, 'now'>,\n): {\n source: StorageChunkSource;\n driver: IStorageDriver | undefined;\n registry: IRegistryDriver | undefined;\n} {\n const storage: unknown = options.storage;\n if (storage === null || typeof storage !== 'object') {\n throw new ValidationError(\n '`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource',\n );\n }\n const asBackend = storage as Partial<StorageBackend>;\n const isObject = (v: unknown): v is Record<string, unknown> =>\n v !== null && typeof v === 'object';\n const hasGetChunk = typeof (storage as Partial<StorageChunkSource>).getChunk === 'function';\n const hasPutImmutable = typeof (storage as Partial<IStorageDriver>).putImmutable === 'function';\n\n // The BRAND decides, not the shape. `{ storage, registry }` is also the shape of core's free-function deps\n // object, so before the brand any literal satisfied it \u2014 including one holding halves from two unrelated\n // stores, which the store accepted and then answered empty for a segment that holds data.\n const isBackend = isStorageBackend(storage);\n\n // A branded backend that ALSO quacks like a driver or a source is genuinely ambiguous. Unreachable for the\n // five classes, kept because the alternative to refusing is guessing.\n if (isBackend && (hasGetChunk || hasPutImmutable)) {\n throw new ValidationError(\n '`storage` is a StorageBackend that also exposes ' +\n `${hasGetChunk ? '`getChunk`' : '`putImmutable`'} \u2014 ambiguous. A backend must not also be a driver ` +\n 'or a source; pass whichever one you mean.',\n );\n }\n\n // Unbranded, but carrying both halves. Three sub-cases, and they want different things said.\n const hasStorageHalf = isObject(asBackend.storage);\n const hasRegistryHalf = isObject(asBackend.registry);\n\n // (a) A DRIVER that also carries a registry \u2014 the audit/metrics/tenant-scoping wrapper. Without this it\n // falls through to the bare-driver path, where there is no pointer at all: generations resolve by\n // list-scan, so the store answers from the HIGHEST object in the bucket rather than the published one, and\n // a load that wrote an object but never published it is served as if it had been. Silently, and with the\n // wrapper's registry sitting right there unused.\n if (!isBackend && hasPutImmutable && hasRegistryHalf) {\n throw new ValidationError(\n '`storage` looks like a driver that also carries a `registry`. Passed as a bare driver it would have ' +\n 'no pointer at all \u2014 generations would resolve by list-scan, so reads could serve a generation that ' +\n 'was written but never published. If you meant a backend, use a backend class \u2014 S3Storage, GcsStorage, ' +\n 'AzureBlobStorage, LocalFsStorage or MemoryStorage \u2014 or, to pair a driver of your own with a registry, ' +\n 'brand the pair with `brandAsBackend` from `@cloudbitmaps/core/driver-kit`.',\n );\n }\n\n // (b) Both halves, neither of them a driver or a source: the hand-assembled literal, or a spread of a real\n // backend with one half swapped. Name the classes AND the door \u2014 the five classes cannot express an\n // instrumented half or a foreign registry, which is exactly the case that lands here.\n if (!isBackend && !hasGetChunk && !hasPutImmutable && hasStorageHalf && hasRegistryHalf) {\n const storageOk =\n typeof (asBackend.storage as Partial<IStorageDriver>).putImmutable === 'function';\n const registryOk =\n typeof (asBackend.registry as Partial<IRegistryDriver>).compareAndSwap === 'function';\n // (c) \u2026and if a half is not actually a driver, say THAT rather than lecturing about buckets.\n if (!storageOk || !registryOk) {\n const bad = !storageOk\n ? '`storage` half is not an IStorageDriver (no `putImmutable`)'\n : '`registry` half is not an IRegistryDriver (no `compareAndSwap`)';\n throw new ValidationError(\n '`storage` looks like a backend but its ' +\n bad +\n ' \u2014 use a backend class, or brand a pair of drivers with `brandAsBackend` from ' +\n '`@cloudbitmaps/core/driver-kit`.',\n );\n }\n throw new ValidationError(\n '`storage` must be a backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ' +\n 'MemoryStorage. An object with `.storage` and `.registry` is not one: a backend builds both halves ' +\n 'from a single bucket and prefix, so they cannot disagree, and hand-assembling them re-opens exactly ' +\n 'that mismatch \u2014 a store whose pointer and generations live in different places reads as empty ' +\n 'rather than failing. A driver author who genuinely wants halves of their own \u2014 an instrumented driver, ' +\n 'a registry in a database you already run \u2014 brands the pair with `brandAsBackend` from ' +\n '`@cloudbitmaps/core/driver-kit`, which is taking on that they agree.',\n );\n }\n\n if (isBackend) {\n const backend = storage as StorageBackend;\n return {\n source: new CrbmStorageChunkSource(backend.storage, {\n registry: backend.registry,\n keystore: options.encryption?.keystore,\n requireEncryption: options.encryption?.required,\n clock,\n currentGenTtlMs: options.cache?.genTtlMs,\n maxOpenSegments: options.cache?.readerMax,\n maxOpenIndexBytes: options.cache?.readerMaxBytes,\n }),\n driver: backend.storage,\n registry: backend.registry,\n };\n }\n\n if (hasGetChunk && hasPutImmutable) {\n throw new ValidationError(\n '`storage` exposes both `getChunk` and `putImmutable` \u2014 ambiguous; pass a StorageBackend, an IStorageDriver, or a StorageChunkSource, not a hybrid',\n );\n }\n if (!hasGetChunk && !hasPutImmutable) {\n throw new ValidationError(\n '`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource',\n );\n }\n if (hasGetChunk) {\n // Already a StorageChunkSource \u2014 used as-is. `keystore`/`requireEncryption` only apply when the store\n // builds the source itself; with a pre-built source they are inert, so reject them rather than mislead.\n if (options.encryption?.keystore !== undefined || options.encryption?.required === true) {\n throw new ValidationError(\n 'keystore/requireEncryption apply only when the store builds its own read path; configure them on ' +\n 'the StorageChunkSource you passed instead',\n );\n }\n return { source: storage as StorageChunkSource, driver: undefined, registry: undefined };\n }\n // A bare IStorageDriver: no pointer, so generations resolve by list-scan. Cleartext, read-only.\n const driver = storage as IStorageDriver;\n return {\n source: new CrbmStorageChunkSource(driver, {\n keystore: options.encryption?.keystore,\n requireEncryption: options.encryption?.required,\n clock,\n currentGenTtlMs: options.cache?.genTtlMs,\n maxOpenSegments: options.cache?.readerMax,\n maxOpenIndexBytes: options.cache?.readerMaxBytes,\n }),\n driver,\n registry: undefined,\n };\n}\n\n/** The deps every write-side helper on the store shares: raw storage + registry + the store's codec/crypto/clock. */\ninterface LifecycleDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n readonly codec: CodecInterface;\n readonly clock: Clock;\n readonly keystore?: IKeystore;\n readonly requireEncryption?: boolean;\n}\n\n/** How the store names a group value that is an object to `typeof` but configures nothing, by its built-in tag. */\nconst NOT_A_GROUP: Readonly<Record<string, string>> = {\n Null: 'null',\n Array: 'an array',\n Map: 'a Map',\n Set: 'a Set',\n Boolean: 'a boxed boolean',\n Number: 'a boxed number',\n String: 'a boxed string',\n};\n\nexport class CloudRoaring {\n private readonly engine: SegmentEngine;\n private readonly cache: BoundedLru<string, CodecBitmap>;\n /** The store's retry options, for a pinned engine to read through as the store's own does; undefined when off. */\n private readonly retryOptions: RetryingOptions | undefined;\n private readonly crbmSource: CrbmStorageChunkSource | undefined;\n private readonly clock: Clock;\n private readonly metrics: IMetricsSink;\n // The store's own drivers, kept so the lifecycle helpers and the `*Into` verbs reuse them instead of making\n // you re-pass deps. `storageDriver` is set only when `storage` was a raw IStorageDriver (a pre-built StorageChunkSource has\n // no underlying driver to write through).\n private readonly storageDriver: IStorageDriver | undefined;\n private readonly registry: IRegistryDriver | undefined;\n private readonly keystore: IKeystore | undefined;\n private readonly requireEncryption: boolean;\n /** Resolved store-level per-op budget (null = disabled); the admin scans use it, with a per-op override. */\n private readonly budget: Budget | null;\n\n /**\n * Refuse any option key the store does not take, at the top level or inside a group, naming each one.\n *\n * An option the store ignored would do nothing and look as if it had \u2014 a typo'd `cache.maxChunk`, a key from\n * another library's config spread into this one \u2014 so every key is checked against {@link OPTION_KEYS}.\n */\n private static rejectUnknownOptions(options: CloudRoaringOptions): void {\n // A nullish or non-object bag never reaches `resolveStorageSource` \u2014 the constructor reads\n // `options.seams?.clock` first and would throw a raw TypeError. Report it here, typed, instead.\n if (options === null || options === undefined || typeof options !== 'object') {\n throw new ValidationError(\n 'CloudRoaring needs an options object with a `storage` key \u2014 got ' +\n (options === null ? 'null' : typeof options),\n );\n }\n const bag = options as unknown as Record<string, unknown>;\n const unknown: Array<{ group: OptionGroup | null; key: string }> = [];\n for (const key of Object.keys(bag)) {\n if (!(OPTION_KEYS.top as readonly string[]).includes(key)) unknown.push({ group: null, key });\n }\n const groups = Object.keys(OPTION_KEYS).filter((g): g is OptionGroup => g !== 'top');\n for (const group of groups) {\n const value = bag[group];\n if (value === undefined) continue;\n const offOk = group === 'retry' || group === 'budget';\n if (value === false && offOk) continue;\n // A group that is not an object configures nothing: `encryption: true` would build a cleartext store. The\n // built-in tag, not `instanceof`, so a boxed `new Boolean(true)` and a Map from another realm are caught.\n const tag = Object.prototype.toString.call(value).slice(8, -1);\n if (typeof value !== 'object' || value === null || NOT_A_GROUP[tag] !== undefined) {\n const got = typeof value !== 'object' ? typeof value : NOT_A_GROUP[tag];\n throw new ValidationError(\n `CloudRoaring's \\`${group}\\` must be an object${offOk ? ' or `false`' : ''} \u2014 got ${got}`,\n );\n }\n const known = OPTION_KEYS[group] as readonly string[];\n for (const key of Object.keys(value)) if (!known.includes(key)) unknown.push({ group, key });\n }\n if (unknown.length === 0) return;\n const takes = (keys: readonly string[]): string => keys.map((k) => `\\`${k}\\``).join(', ');\n const named = [...new Set(unknown.map((u) => u.group))];\n throw new ValidationError(\n `CloudRoaring does not take ${takes(unknown.map((u) => (u.group === null ? u.key : `${u.group}.${u.key}`)))}. ` +\n named\n .map((g) =>\n g === null\n ? `The store takes ${takes(OPTION_KEYS.top)}.`\n : `\\`${g}\\` takes ${takes(OPTION_KEYS[g])}.`,\n )\n .join(' ') +\n ' https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/api-reference.md#build-a-store--new-cloudroaringoptions',\n );\n }\n\n constructor(options: CloudRoaringOptions) {\n CloudRoaring.rejectUnknownOptions(options);\n const clock = options.seams?.clock ?? new SystemClock();\n const rng = options.seams?.rng ?? new SystemRng();\n // Wrap the user sink so a throwing/buggy sink can never break I/O (observability is best-effort).\n const metrics = safeMetrics(options.metrics ?? NOOP_METRICS);\n const cache = new BoundedLru<string, CodecBitmap>({\n maxEntries: options.cache?.maxChunks ?? DEFAULT_CACHE_MAX_CHUNKS,\n ttlMs: options.cache?.ttlMs,\n clock,\n });\n // Resolve the Storage seam to a StorageChunkSource: a raw IStorageDriver is wrapped into the `.crbm` storage source\n // here (with the store's registry/keystore) so drivers are wired once; a pre-built source is used as-is.\n const resolved = resolveStorageSource(options, clock);\n let storage: StorageChunkSource = resolved.source;\n // Resilience on by default: wrap the source so transient faults retry with jittered backoff. `false` opts\n // out (e.g. the injected client already retries); a RetryPolicy tunes it.\n if (options.retry !== false) {\n // The policy is a partial, and the rest is filled from the default \u2014 so tuning one field does not mean\n // restating all five, and `{ onRetry }` alone is a legal, useful value.\n //\n // Field by field with `??`, NOT `{ ...DEFAULT, ...overrides }`. A spread lets a key that is *present with\n // value `undefined`* overwrite the default instead of falling back to it, and `exactOptionalPropertyTypes`\n // is off, so `retry: { baseDelayMs: cfg.baseDelayMs }` typechecks clean when `cfg.baseDelayMs` is absent \u2014\n // the ordinary shape for a value read from env or JSON. The result was `NaN` delays; `SystemClock.sleep`\n // takes the `setTimeout(resolve, NaN)` path, which Node coerces to 1 ms, so bounded jittered backoff\n // silently became a ~1 ms hot retry loop with the read still succeeding and the retry metric still\n // emitting. That is the thundering-herd and denial-of-wallet protection gone with nothing to see.\n // A `Partial` policy is what puts this in reach: were a whole `RetryPolicy` required, each would be a compile\n // error.\n const { onRetry: userOnRetry, ...ov } = options.retry ?? {};\n const policy: RetryPolicy = {\n maxAttempts: ov.maxAttempts ?? DEFAULT_RETRY_POLICY.maxAttempts,\n baseDelayMs: ov.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,\n maxDelayMs: ov.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,\n backoffFactor: ov.backoffFactor ?? DEFAULT_RETRY_POLICY.backoffFactor,\n jitter: ov.jitter ?? DEFAULT_RETRY_POLICY.jitter,\n };\n const retryOpts: RetryingOptions = {\n clock,\n rng,\n policy,\n // Bridge transient-fault retries into the metrics stream, then call the user's own hook.\n onRetry: (info) => {\n metrics.onEvent({\n kind: 'retry',\n reason: 'transient',\n attempt: info.attempt,\n delayMs: info.delayMs,\n });\n userOnRetry?.(info);\n },\n };\n storage = new RetryingStorageChunkSource(storage, retryOpts);\n this.retryOptions = retryOpts;\n }\n // Resolve the denial-of-wallet budget once (validates; `false` \u21D2 null = disabled) and share it between the\n // engine (count/iterate/combines) and the facade's admin scans (subjectReport/eraseSubject).\n this.budget = resolveBudget(options.budget, DEFAULT_BUDGET);\n const deps: EngineDeps = {\n storage,\n cache,\n codec: roaringCodec, // the facade injects the flagship codec; core stays codec-agnostic\n clock,\n metrics,\n budget: this.budget,\n };\n this.engine = new SegmentEngine(deps);\n this.cache = cache;\n // The UNWRAPPED `.crbm` source, kept for `pin()` \u2014 the only reader that resolves a specific generation.\n // `undefined` when the caller supplied a pre-built source, which has nothing to pin.\n this.crbmSource =\n resolved.source instanceof CrbmStorageChunkSource ? resolved.source : undefined;\n this.clock = clock;\n this.metrics = metrics;\n // Keep the raw drivers for the lifecycle helpers (see the fields above). They use the raw drivers directly \u2014\n // a one-shot admin op surfaces a transient fault to the caller rather than retrying under the hood.\n this.storageDriver = resolved.driver;\n this.registry = resolved.registry;\n this.keystore = options.encryption?.keystore;\n this.requireEncryption = options.encryption?.required ?? false;\n }\n\n /**\n * The write-side deps, from the store's own drivers, for the lifecycle helpers and the `*Into` verbs. Requires\n * the store to have been constructed with a **backend**, which supplies both halves: an `IStorageDriver` to\n * write generations through (a pre-built `StorageChunkSource` has none) and the registry holding the pointer\n * every write publishes.\n */\n private lifecycleDeps(op: string): LifecycleDeps {\n if (this.storageDriver === undefined) {\n throw new UnsupportedError(\n `${op} needs the store built with a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, ` +\n `LocalFsStorage or MemoryStorage. A pre-built StorageChunkSource is read-only: it has no ` +\n `IStorageDriver underneath to write generations through. Build the store on one of those backend ` +\n `classes to write.`,\n );\n }\n if (this.registry === undefined) {\n throw new UnsupportedError(\n `${op} needs a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ` +\n `MemoryStorage. A bare IStorageDriver has no generation pointer to publish through, and there is ` +\n `no separate \\`registry\\` option: a backend carries it.`,\n );\n }\n return {\n storage: this.storageDriver,\n registry: this.registry,\n clock: this.clock,\n codec: roaringCodec, // facade injects the flagship codec\n keystore: this.keystore,\n requireEncryption: this.requireEncryption,\n };\n }\n\n /** Get a handle to a segment. Validates the name (non-empty, well-formed, within the encoded-length cap). */\n segment(name: string, options?: SegmentOptions): Segment {\n const ref: SegmentRef = { segment: name, namespace: options?.namespace };\n validateSegmentRef(ref);\n refuseReservedNamespace(ref.namespace);\n const expiresAt = options?.expiresAt;\n if (expiresAt !== undefined) {\n // Fail at the handle, not at the first read that silently returns nothing. The floor is the same one\n // `setRetention` enforces: a seconds-based value would land in 1970 and make the segment permanently\n // and invisibly empty.\n if (\n !Number.isFinite(expiresAt) ||\n !Number.isInteger(expiresAt) ||\n expiresAt < MIN_EXPIRES_AT_MS\n ) {\n throw new ValidationError(\n `segment: expiresAt must be an integer epoch-MILLISECONDS >= ${MIN_EXPIRES_AT_MS}; got ${expiresAt}` +\n ` (a value in seconds lands in 1970 and would make the segment read as permanently empty)`,\n );\n }\n }\n return makeSegment({\n engine: this.engine,\n ref,\n clock: this.clock,\n metrics: this.metrics,\n materialize: (dest, ids, op, options) => this.materialize(dest, ids, op, options),\n pinned: (r, e) => this.pinSegment(r, e),\n combineEngine: (handles) => this.engineForCombine(handles),\n expiresAt,\n });\n }\n\n /**\n * Write `ids` as a **new generation of `dest`** and publish it \u2014 the shared body of the `*Into` verbs. An `*Into`\n * materialisation is a load, and publishes the same way (hard invariant 1): every load that finds a row fences its\n * publish on the row's token; a guarded load (the default, since the empty refusal reads the current generation)\n * also fences on the pointer it judged (`expectFrom`), and one that found no row fences on that absence instead.\n * Only an unguarded load (`allowEmpty: true` and no `guard.minRetained`) onto a segment with no row publishes bare\n * forward-only. The destination's previous generation stays readable until the publish lands (readers re-resolve\n * within `cache.genTtlMs`).\n *\n * This routes through `loadSegment` rather than writing the generation itself, and that is the whole point\n * of it. A materialisation is a load whose ids happen to come from a combine instead of from upstream, so\n * everything `load()` learned the hard way applies unchanged: the generation is written UNPUBLISHED, the\n * guard runs while the old generation is still authoritative, the publish is fenced as above, and a refused\n * object is reclaimed only when a re-read finds the row unchanged (the same token) or gone (hard invariant 1:\n * deleting it after a purge-and-recreate would put a live row over a missing generation).\n *\n * That last check narrows the window rather than closing it: the row read and the delete are two round\n * trips, and `IStorageDriver` has no conditional delete to make them one. the collection a load runs carries\n * the same residual. The failure it leaves is an orphan object, which costs storage until\n * something collects it \u2014 deliberately the cheaper side of the trade.\n *\n * Written and published in one step, with no guard, an empty combine \u2014 a typo'd operand, an `exclude` that\n * swallowed everything, an operand that had not loaded yet \u2014 would silently replace `dest` with an empty\n * generation: the same failure `load()`'s guard exists to prevent, on the same data, reachable without passing\n * any option at all.\n *\n * **A lost race throws.** `loadSegment` reports one as `reason: 'superseded'`; the `*Into` verbs throw\n * {@link WriteConflictError} for it, so a caller can `catch (WriteConflictError)`. That one refusal is\n * translated into the throw, and `MaterializeResult.reason` never carries it.\n *\n * **A `WriteConflictError` does not by itself mean nothing was published**, and that is worth knowing\n * before you write the retry. `'superseded'` covers five different causes \u2014 the write-once PUT collided,\n * the pointer moved, a row appeared where the load found none, the row's token changed, the row was purged \u2014\n * and only the first three are the \"somebody beat us\" the name suggests. A token can also change on a write\n * that is not a supersession at all, such as a `setRetention` on the destination. On top of that, the collection pass that runs AFTER a\n * successful publish can raise the same error. So: treat it as \"re-read the destination and decide\",\n * never as \"the write did not happen\".\n *\n * **And by default it collects nothing**, unlike `load()`. See the `keep` default below.\n */\n private async materialize(\n dest: SegmentRef,\n ids: AsyncIterable<number>,\n op: string,\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n const deps = this.lifecycleDeps(op);\n let result: Awaited<ReturnType<typeof loadSegment>>;\n try {\n result = await loadSegment(dest, ids, deps, {\n ...(options?.allowEmpty === undefined ? {} : { allowEmpty: options.allowEmpty }),\n ...(options?.guard === undefined ? {} : { guard: options.guard }),\n // COLLECT NOTHING by default, which `loadSegment` does not \u2014 it keeps a grace window of 1 and deletes\n // the rest. By default a materialisation collects nothing: the guide states \"**It deletes nothing**,\n // unlike `load()`. The destination's previous generations stay in the bucket until you collect them\", and\n // the ownership table\n // puts that call on the operator. Inheriting `load()`'s collection would silently delete the\n // generations an operator's recovery story depends on \u2014 `rollbackSegment` refuses a collected target \u2014\n // as a side effect of adding a guard whose entire purpose is preventing data loss. Opt in with `keep`.\n keep: options?.keep ?? KEEP_EVERY_GENERATION,\n ...(options?.audit === undefined ? {} : { audit: options.audit }),\n });\n } finally {\n // As `load()` does: this store's view of `dest` is behind whatever just happened, and a throw can still have\n // published first. Left alone, the store read its own write's predecessor: indefinitely, with no timed refresh.\n this.engine.invalidate(dest);\n }\n // Checked on `reason` alone, not `published && reason`: the compiler narrows a const through an equality\n // test, so after this throw `reason` is provably a `MaterializeRefusal` and the return below type-checks\n // without an assertion. `'superseded'` only ever accompanies `published: false` anyway.\n const reason = result.reason;\n if (reason === 'superseded') {\n // The object is durable, but a concurrent writer published a higher generation of `dest` between our\n // numbering and our publish, so ours is an orphan no reader will resolve. Returning it here would name\n // `generation` as \"the destination's new current generation\" \u2014 which is what `MaterializeResult`\n // documents it to be, and it would be false. The destination holds someone else's content.\n //\n // A throw rather than a flag: every other write path in the library reports a lost race loudly, and a\n // materialisation that silently did not take effect is the one outcome a caller cannot detect on its\n // own.\n // `size > 0` distinguishes the two ways a materialisation loses the race, and the operator needs them\n // apart: the object either exists as an orphan above the pointer (collected by the first load that collects\n // once a generation above it is current) or was\n // never written at all, because the write-once PUT itself collided. Telling someone to look for an\n // orphan that does not exist is a wasted investigation.\n // Deliberately does NOT assert which of the four causes it was. \"A newer generation was published first\"\n // is wrong for two of them: a `setRetention` on the\n // destination bumps the row's token without publishing anything, and a purge leaves no row at all.\n // Telling an operator to go looking for a newer generation that does not exist costs a real\n // investigation. `size > 0` is the one thing this path can state as fact.\n const wrote =\n result.size > 0\n ? `generation ${result.generation} was written and did not become current`\n : `nothing was written \u2014 another writer took generation ${result.generation} first`;\n throw new WriteConflictError(\n `${op}: the destination \"${dest.segment}\" changed while this materialisation was in flight, so it ` +\n `never became current: ${wrote}. The pointer may have moved, the row may have been rewritten ` +\n `(a retention policy does this) or purged. Re-read the destination and re-run.`,\n );\n }\n return {\n generation: result.generation,\n published: result.published,\n ...(reason === undefined ? {} : { reason }),\n cardinality: result.cardinality,\n cardinalityBefore: result.cardinalityBefore,\n chunkCount: result.chunkCount,\n size: result.size,\n collected: result.collected,\n };\n }\n\n /**\n * **Subject access (GDPR Art. 15 / CCPA right-to-know): which segments is this id a member of?**\n *\n * Enumerates the **registered** segments (via the store's own `registry`) and does a `has(id)` on each \u2014 no\n * drivers to re-pass. Complete only over registered segments (every loaded segment has a row, so build the\n * store on the backend the loads used). There is deliberately **no `id \u2192 segments` reverse index** \u2014 that would\n * tax every load for a rare request; this admin scan is `O(registered segments)` and touches no hot path. Needs\n * a storage backend (throws {@link UnsupportedError} otherwise).\n *\n * **Current as of the registry row, not as of the reader's cache.** Each segment's resolved generation is\n * compared with the row the scan listed, and a segment whose cached generation differs is re-resolved before the\n * read, so a load or an erasure from another process shows at once \u2014 whatever `cache.genTtlMs` is, `0` included.\n * The comparison is on the generation **and** the row's token, so a segment retired, purged and loaded again from\n * generation 0 while this store held its old generation 0 is told apart too.\n */\n async subjectReport(\n id: number,\n options: {\n namespace?: string;\n allNamespaces?: boolean;\n concurrency?: number;\n budget?: BudgetOption;\n } = {},\n ): Promise<SubjectReport> {\n const registry = this.requireRegistry('subjectReport');\n requireScope(options, 'subjectReport'); // tenancy: explicit namespace, or an { allNamespaces: true } ack\n validateConcurrency(options.concurrency); // fail fast before the (possibly huge) registry scan\n const budget = resolvePerOpBudget(options.budget, this.budget); // partial override inherits the store's tightening\n splitId(id); // fail fast on a non-u32 id even when no segments are registered\n // Bounded INCREMENTALLY: draining the whole registry and only then checking the budget would refuse the\n // work after paying for the list \u2014 measured at 20,000 records buffered under `maxRequests: 2`. This is a\n // GDPR Art. 15 entry point plausibly wired to end-user traffic, so resident memory must be O(budget), not\n // O(fleet size).\n const recs = await collectWithinBudget(\n // A subject cannot be in a due-index row, and charging this request's budget for them would refuse a\n // GDPR Art. 15 report for a reason unrelated to the subject.\n excludingReservedRows(registry.list(options.namespace)),\n budget,\n 'subjectReport',\n );\n // Bounded fan-out of `has()` across registered segments. Order-preserving \u21D2 deterministic result. A has()\n // fault propagates (a report that can't read a segment must fail loud, not silently under-report).\n const membership = await mapWithConcurrency(\n recs,\n options.concurrency ?? DEFAULT_ADMIN_CONCURRENCY,\n async (rec): Promise<SubjectSegmentRef | null> => {\n if (rec.status === 'destroyed') return null; // already unreadable \u2014 never a member\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n // The row this scan just listed is authoritative; the reader's snapshot may be up to `cache.genTtlMs` behind\n // it, or have no timed refresh (`genTtlMs: 0`). An access report must not lag another process's load or\n // erasure, so a segment whose snapshot is not the listed row's is forgotten before the read. The snapshot's\n // version is `<generation>:<row token>` (invariant 1: the row's OCC token is the identity, the number\n // restarts at 0 once a row is purged), so a retired name loaded again is told apart too. Only a segment\n // that differs is re-resolved: one whose row has not moved keeps its snapshot and costs no extra read.\n if (this.crbmSource !== undefined) {\n const held = await this.crbmSource.currentVersion(ref);\n const listed = rec.currentGen === null ? null : `${rec.currentGen}:${String(rec.token)}`;\n if (held !== listed) this.engine.invalidate(ref);\n }\n return (await this.engine.has(ref, id))\n ? { segment: rec.segment, namespace: rec.namespace }\n : null;\n },\n );\n const segments = membership.filter((m): m is SubjectSegmentRef => m !== null);\n return { id, segments, scannedSegments: recs.length };\n }\n\n /**\n * **Subject erasure (GDPR Art. 17): remove an id from every segment it's in, with the bit physically gone\n * from the bucket on return.**\n *\n * For each **registered** segment the id is a member of, `eraseIdFromSegment` rewrites the current generation\n * without the id \u2014 every chunk streamed through, one bit cleared \u2014 publishes the rewrite **fenced on the\n * generation it was derived from**, and collects the generation that held the bit. A segment whose current\n * generation does not hold the id is searched anyway, every generation in its bucket: a retained superseded one\n * can still hold it, and so can one above the pointer after a {@link CloudRoaring.rollback}, which the rollback\n * could make current again. Each holder is deleted \u2014 below the pointer by a `keep: 0` collection, above it one\n * by one, re-proved against the row first \u2014 and the generations above the pointer that never held the id stay\n * as rollback targets. An entry says `erased: true` only once the call has listed the bucket and read what is\n * left: **no generation of the segment holds the id**. The returned per-segment record is your **erasure ledger** \u2014\n * persist it / route it to your audit sink as the proof of deletion (a `segment.rewrite` audit event is also\n * emitted per rewrite when you pass `audit`).\n *\n * Uses the backend's **own** two halves, so the membership check and the rewrite provably run\n * over the same generation. Requires the store built with a **backend** (throws\n * {@link UnsupportedError} otherwise; a pre-built `StorageChunkSource` store has no `IStorageDriver` to write\n * through; build the store on a backend instead).\n *\n * **One contract remains** (an integrator obligation the library cannot check): **do not load the segment\n * while erasing from it.** A load that lands after the rewrite carries whatever its source held, and the\n * library cannot know that source was meant to exclude the id. Quiesce loads of the affected segments for the\n * duration, or fix the source first and load after. A writer that lands *during* the rewrite is caught: the\n * rewrite's publish is refused **by the fence** \u2014 the publish lands its compare-and-swap only\n * while the pointer is still on the generation the rewrite streamed \u2014 and the entry says `note: 'superseded'`,\n * so re-run. Forward-only alone would NOT refuse it: the rewrite's number goes above everything in the bucket,\n * so the rewrite would out-rank the newer generation and then collect it.\n *\n * A racing **erasure** is caught before that, and reported the same way. It collects with `keep: 0`, taking\n * every generation below its new pointer \u2014 the one this rewrite is streaming, and the object this rewrite\n * just wrote \u2014 so the loser can find its own inputs deleted mid-flight. That surfaces as an outcome rather than\n * an error, read off the row: a moved pointer is a `'superseded'` entry, which a re-run settles, and a segment\n * that a concurrent `dropSegment` tombstoned or a retention sweep purged is left out of the ledger, as a fresh\n * call would leave it out.\n *\n * **Read `note` on any `erased: false` entry \u2014 the two reasons mean different things.** `'superseded'` means\n * another writer (a load, another erasure, or a rollback) moved the pointer mid-call, so **this call** did not\n * erase the id. Re-run: it erases the id if it is still there, and lists nothing for the segment if a racing\n * erasure of the same id already removed it. Do not read `'superseded'` as \"the id is still present\" \u2014\n * read it as \"not done by this call, and the re-run settles it\".\n * `` `error: \u2026` `` is a per-segment fault (caught so one segment can't discard the whole ledger) and it can land\n * on either side of the publish: if the rewrite had not published, the id is still there and a re-run erases\n * it; if the publish succeeded and only the **collection** of the old generation failed, the id is already\n * absent from every read and what remains is an object in the bucket that still contains the bit. The same\n * note, after a publish, can mean a rollback moved the pointer back onto a generation that still holds the id\n * while the collection ran \u2014 then the id is served again, and the entry says so rather than `erased: true`. A\n * re-run searches every generation in the bucket, so it rewrites or collects what is left and usually reports\n * `erased: true`; {@link SubjectErasureEntry.note} says what else a re-run can report. Re-running is otherwise safe\n * and idempotent: a segment the id is no longer in is not listed. Admin-only path;\n * `O(registered segments + superseded generations)`, no hot-path cost: a segment whose current generation lacks\n * the id is searched generation by generation, one open for each other generation in its bucket, and with the\n * keep-everything default of the `*Into` verbs that is one per generation the segment ever had. The per-op\n * `budget` is charged one unit for each segment and one for each generation opened beyond the one its row names,\n * so a fleet with long histories can exhaust it where the segment count alone would not. A segment that does is\n * reported `erased: false` with an `error:` note, before it deletes anything (the one refusal that can come after a\n * rewrite is the last check for a generation a concurrent writer left behind), and the\n * rest of the scan continues: the call itself does not throw for it. Per-subject crypto-shred is infeasible (a subject's bit is\n * co-mingled in a shared container), so this is the single-subject erasure route; whole-segment/tenant erasure\n * is `dropSegment` / the `destroySegment`/`eraseNamespace` free functions.\n */\n async eraseSubject(\n id: number,\n options: {\n namespace?: string;\n allNamespaces?: boolean;\n audit?: IAuditSink;\n concurrency?: number;\n budget?: BudgetOption;\n } = {},\n ): Promise<EraseSubjectResult> {\n const deps = this.lifecycleDeps('eraseSubject');\n requireScope(options, 'eraseSubject'); // tenancy: explicit namespace, or an { allNamespaces: true } ack\n validateConcurrency(options.concurrency); // fail fast before the (possibly huge) registry scan\n const budget = resolvePerOpBudget(options.budget, this.budget); // partial override inherits the store's tightening\n splitId(id); // fail fast on a non-u32 id even when nothing is registered\n // Bounded incrementally \u2014 see subjectReport above. Art. 17 erasure is likewise reachable from ordinary\n // \"delete my account\" traffic, so the enumeration itself has to respect the budget.\n const recs = await collectWithinBudget(\n excludingReservedRows(deps.registry.list(options.namespace)),\n budget,\n 'eraseSubject',\n );\n // The scan charged one unit a segment. A segment whose current generation lacks the id is searched generation by\n // generation, and each open past the current one is charged too, to the same call-wide count. With no budget\n // there is nothing to charge and the drivers are used as they are.\n let opens = 0;\n const charge = (): void => {\n opens += 1;\n checkBudget(budget, recs.length + opens, 'eraseSubject');\n };\n // Bounded fan-out. Each segment is an independent generation, so rewriting distinct segments concurrently is\n // safe. Per-segment faults stay isolated INSIDE each task \u2014 one failure never aborts the ledger \u2014 and the\n // pool preserves input order, so the ledger stays deterministic.\n const entries = await mapWithConcurrency(\n recs,\n options.concurrency ?? DEFAULT_ADMIN_CONCURRENCY,\n async (rec): Promise<SubjectErasureEntry | null> => {\n if (rec.status === 'destroyed') return null; // already crypto-shredded \u2014 nothing to erase\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n try {\n // The rewrite does its own membership check against the CURRENT registry generation \u2014 not the\n // engine's cached view, which may lag a load by up to `cache.genTtlMs`. An Art. 17 erasure must never\n // skip a segment because a read cache hasn't caught up yet.\n const result = await eraseIdFromSegment(\n ref,\n id,\n budget === null\n ? deps\n : { ...deps, storage: new OpenChargingStorage(deps.storage, rec.currentGen, charge) },\n { audit: options.audit },\n );\n if (result.reason === 'not-member' || result.reason === 'absent') return null;\n if (result.reason === 'no-generation') return null; // a row with no data yet holds no id\n if (result.reason === 'destroyed') return null;\n return {\n segment: rec.segment,\n namespace: rec.namespace,\n erased: result.erased,\n fromGeneration: result.fromGeneration,\n generation: result.generation,\n note: result.erased ? undefined : result.reason,\n };\n } catch (err) {\n return {\n segment: rec.segment,\n namespace: rec.namespace,\n erased: false,\n note: `error: ${err instanceof Error ? err.message : String(err)}`,\n };\n } finally {\n // Whatever the outcome, this process's own view of the segment is now suspect: a landed rewrite\n // deleted the generation our caches were built on, and a refused one means somebody else's did.\n // Without this the erasing store keeps answering `true` for the id it just reported erased \u2014 out of\n // RAM, with no storage read for any control to intercept. `finally`, not the happy path: a rewrite\n // that published and then THREW on its collect is precisely the case where this view is stale, and\n // it is reachable from an ordinary retirement landing mid-call.\n //\n // Swallowed, because a `finally` that throws replaces the outcome above it: it would escape the\n // per-segment catch, abort the whole ledger, and discard the error it was masking \u2014 breaking the\n // isolation this fan-out promises. Dropping cache entries cannot fail today; this keeps that from\n // becoming a whole-run failure if it ever can.\n try {\n this.engine.invalidate(ref);\n } catch {\n /* best-effort: never let cache bookkeeping discard a segment's result */\n }\n }\n },\n );\n const erasedFrom = entries.filter((e): e is SubjectErasureEntry => e !== null);\n return { id, erasedFrom, scannedSegments: recs.length };\n }\n\n /**\n * Every generation still in the bucket for this segment, ascending, with the current one marked.\n *\n * What the bucket holds, not what the segment has ever been \u2014 collection deletes superseded objects, so this is\n * the grace window plus whatever has not been collected yet. It is the set {@link CloudRoaring.rollback} can\n * choose from, which is the reason to look at it. One registry read and one listing; it does not open the objects.\n *\n * Needs a backend.\n */\n async generations(ref: SegmentRef): Promise<GenerationEntry[]> {\n validateSegmentRef(ref);\n return listGenerations(ref, this.lifecycleDeps('generations'));\n }\n\n /**\n * Whether a read of this segment would find anything \u2014 the \"do I already have this?\" question, as one\n * registry point read.\n *\n * There is no `create` in this library: {@link CloudRoaring.segment} is a validated address and does no I/O,\n * so naming a segment can never collide with an existing one. A segment starts existing when something is\n * first loaded into it, and this is how you ask whether that has happened.\n *\n * **Not the same as `count() > 0`.** A segment loaded with no ids exists and counts zero. Distinguishing\n * \"never loaded\" from \"loaded, and genuinely empty\" is the thing `count()` cannot do and the reason this\n * exists. It is `false` for a segment whose row was minted ahead of its first load (by `setRetention`) and\n * for a `destroyed` tombstone, because a read answers empty in both cases.\n *\n * Two states answer `true` where a read still gives you nothing: a torn restore (a live pointer whose object\n * was deleted) makes reads *throw* rather than answer empty \u2014 `checkConsistency` is the call for that \u2014 and\n * a handle carrying an expired `expiresAt` reads empty by a rule that lives on the handle, not the row.\n *\n * Not a lock: the answer can change the moment it returns. If it has to hold, use the fence built for that \u2014\n * `load`'s `guard`, or `expectFrom`/`expectToken` on a publish. Needs a storage backend.\n *\n * ```ts\n * if (!(await store.exists({ segment: 'users' }))) {\n * await store.load({ segment: 'users' }, idsFromUpstream);\n * }\n * ```\n */\n async exists(ref: SegmentRef): Promise<boolean> {\n validateSegmentRef(ref);\n return segmentExists(ref, this.requireRegistry('exists'));\n }\n\n /**\n * Every segment the registry knows about, streamed \u2014 optionally scoped to one namespace.\n *\n * The registry is already the list of your segments, which is why you should not keep a second one beside it:\n * a hand-maintained list is a source of truth that drifts from this one the first time a load fails halfway.\n *\n * **An admin/discovery call, not a request-path one.** This is the registry's own enumeration \u2014 a paged\n * LIST over the `registry/` prefix \u2014 so its cost grows with the size of the fleet rather than with what you\n * are looking for.\n *\n * Scoping to a namespace narrows the LIST prefix, so it really is the difference between reading one tenant\n * and reading all of them.\n *\n * It streams, and stopping the iteration stops the scan. It reads the registry directly and is not retried: a\n * transient fault part-way through ends the loop with that error, and calling `segments()` again scans from the\n * start.\n *\n * Yields `destroyed` tombstones and rows with `currentGen: null`, because a filtered enumeration that looks\n * complete is worse than an honest one \u2014 filter on `status`/`currentGen` yourself, or ask\n * {@link CloudRoaring.exists} the narrower question. Needs a storage backend.\n *\n * ```ts\n * for await (const s of store.segments({ namespace: 'active-daily' })) {\n * console.log(s.segment, s.currentGen, s.status);\n * }\n * ```\n */\n segments(options: { namespace?: string } = {}): AsyncIterable<SegmentInfo> {\n if (options.namespace !== undefined) {\n // Synchronously, at the call, where `listSegments` (an async generator, which refuses the reserved\n // namespace too for a direct caller) would only throw at the first iteration.\n validateSegmentRef({ segment: 'x', namespace: options.namespace });\n refuseReservedNamespace(options.namespace);\n }\n return listSegments(this.requireRegistry('segments'), options);\n }\n\n /**\n * Move this segment's pointer **back** to a generation still in the bucket \u2014 the one write in the library that\n * is not forward-only.\n *\n * Forward-only is right for a writer: a load whose ids came from upstream loses nothing by being out-raced, and\n * letting it regress would let a slow loader silently undo a fast one. It is wrong for an operator who has\n * looked at the segment, decided the current generation is wrong, and knows which one they want. So this is\n * reachable only by asking for it by name \u2014 no sweep, retry or reconciliation calls it \u2014 and it is audited\n * (`segment.rollback`), because every other pointer move can be reconstructed from \"a load happened\" and this\n * one cannot.\n *\n * It refuses rather than guesses: a generation not in the bucket (collected, or never written) throws\n * `NotFoundError` naming what *is* available, and a crypto-shredded segment throws\n * {@link ValidationError} because every generation of it is unreadable. Rolling to the generation already\n * current is a no-op that reports itself.\n *\n * It deletes nothing. The generations above the new pointer stay put \u2014 which is what makes this reversible \u2014\n * and are then *above* `currentGen`, where collection never looks. They remain until a load numbers above them\n * (collection then keeps the newest `keep` of what is below its pointer), {@link CloudRoaring.dropSegment}\n * deletes them, or {@link CloudRoaring.eraseSubject} does: all of those present when it rewrites, and only those holding\n * the id when the current generation does not. An operator who has just undone a bad load should not have the\n * evidence collected out from under them, while a rollback target that still holds erased data would make the\n * erasure undoable.\n *\n * A target **above** the pointer needs `{ allowForward: true }`, and is refused with {@link ValidationError}\n * without it: that is also where objects live that were never published, such as a load that wrote its object\n * and died before the publish. Undoing an earlier rollback is what the opt-in is for.\n *\n * Needs a backend.\n */\n async rollback(\n ref: SegmentRef,\n toGeneration: number,\n options: { audit?: IAuditSink; allowForward?: boolean } = {},\n ): Promise<RollbackResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('rollback');\n try {\n return await rollbackSegment(ref, toGeneration, deps, options);\n } finally {\n // The pointer moved under this store's cached view \u2014 and unlike a load, it moved to content the caches may\n // still be holding from before. Drop it either way.\n this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Replace this segment's contents** with `ids`, as one new immutable generation, and make it current.\n *\n * The whole write path in one call: take the next generation number, write the object, check the result is\n * plausible, move the pointer, collect what the move superseded. Composed by hand those are four functions and\n * the one that gets left out is the last, so segments quietly accumulate superseded generations nobody pays\n * attention to and everybody pays for.\n *\n * ```ts\n * const r = await store.load({ segment: 'audience:active' }, idsFromWarehouse, {\n * guard: { minRetained: 0.5 }, // refuse a load that would drop more than half the segment\n * });\n * if (!r.published) console.warn(`load refused: ${r.reason}`);\n * ```\n *\n * **A load REPLACES.** Whatever the stream contains is what the segment contains afterwards, so an upstream\n * query that returns fewer rows than usual is a shrink nobody asked for and an empty one is a wipe \u2014 both\n * reported as a successful write, because at the storage layer they are one. That is what `guard` and the\n * default empty refusal are for, and why they run **between** the write and the publish: the only moment where\n * the new content is known and the old one is still authoritative.\n *\n * **Branch on `published`.** A refusal is a normal outcome, not an exception \u2014 `published: false` with a\n * `reason`, in the same shape as a success \u2014 so a discarded result is a load that silently did nothing, and\n * with the empty guard on by default this verb refuses more readily than any other. Note the sibling `*Into`\n * verbs *throw* on the same superseded condition rather than reporting it; this one follows\n * `eraseIdFromSegment` instead, because three of its four refusals are expected guard outcomes rather than\n * faults.\n *\n * `'superseded'` means another writer got there first: another load took the same generation number, so this\n * one wrote nothing (`size: 0`), or the segment's registry row changed while the load was writing \u2014 another load\n * published, a retention change, a rollback or an erasure wrote the row, or the row was deleted.\n *\n * A refused load deletes the object it wrote before returning \u2014 it sits above `currentGen`, where generation\n * collection deliberately never looks \u2014 but only while the segment's registry row is unchanged or gone. Once\n * another write has changed the row, the generation number it holds may name another incarnation's live object,\n * so it leaves the orphan rather than risk deleting live data. The orphan is an ordinary generation once a later\n * one is current above it, and collection counts it within `keep`.\n *\n * What it **throws** for is a fault rather than an outcome: invalid options or ids, and a crypto-shredded\n * segment (`ValidationError`); a key the keystore cannot provide (`KeyUnavailableError`); a current generation\n * that will not open when a guard reads its size (`IntegrityError`); a driver failure; and a collection pass\n * that could not prove the segment was still the same one (`WriteConflictError`). The last can be raised\n * **after** the publish already landed, so a throw does not by itself mean the load did not take effect \u2014\n * re-read the pointer rather than assuming.\n *\n * Needs a backend (throws {@link UnsupportedError} otherwise).\n */\n async load(\n ref: SegmentRef,\n ids: Iterable<number> | AsyncIterable<number>,\n options: LoadOptions = {},\n ): Promise<LoadResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('load');\n try {\n return await loadSegment(ref, ids, deps, options);\n } finally {\n // This store's view of the segment is now behind whatever just happened \u2014 a published load superseded the\n // generation the caches were built on, and a throw can still have published before failing its collect.\n // `finally`, so the one path where the view is most likely stale is not the one path that skips the drop.\n this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Dispose of a segment \u2014 tombstone it, then delete its storage objects.** Irreversible.\n *\n * The operation a rolling window needs: `destroySegment` crypto-shreds (bytes unreadable everywhere including\n * backups, but still sitting in your bucket and still billed, and it requires encryption), while this one\n * removes the storage and works on a cleartext segment. On an encrypted segment it does both.\n *\n * Pass `{ dryRun: true }` first \u2014 it reports the generations it *would* delete and changes nothing. That\n * matters more than the `confirmSegment` guard for anything automated, because in a loop the guard is the same\n * variable twice.\n *\n * ```ts\n * for (const day of expiredDays) {\n * // The family in the namespace, the date in the segment \u2014 `registry.list(namespace)` then enumerates\n * // exactly this family's buckets, which a flat `active:2026-08-01` name cannot do without string-matching.\n * const ref = { namespace: 'active-daily', segment: day };\n * await store.dropSegment(ref, { confirmSegment: ref.segment });\n * }\n * ```\n *\n * **Omitting the namespace addresses a different segment and is a silent no-op** \u2014 you get\n * `{ dropped: false, reason: 'absent' }`, not a throw, so a retention loop with that mistake deletes nothing\n * forever and quietly. Branch on `dropped`, and treat `reason: 'absent'` as the alert.\n *\n * **Inspect `generationsRemaining`.** Empty is the normal outcome; non-empty means the storage was NOT fully\n * reclaimed and the drop should be re-run. A load that was already writing when the tombstone landed still\n * finishes its object, so a single sweep can miss it \u2014 this call re-sweeps and then reports whatever it still\n * could not remove rather than returning a result that looks like a clean drop.\n *\n * Reads become empty within `cache.genTtlMs` (default 2 s), not instantly: a store that had already read this\n * segment may answer from its cached generation + cached chunks until that window lapses, or, while the registry\n * cannot be read because of a transient fault, until a retry 500 ms apart reaches it again. A reader that never\n * touched it sees empty at once. **That bound needs a registry and `cache.genTtlMs > 0`.** A store with no registry\n * (a bare `IStorageDriver`), with `cache.genTtlMs: 0`, or on a storage source built with no clock, has no timed\n * refresh. It notices the drop only when a read has to fetch\n * from a deleted generation or its reader cache evicts the segment, and until then a chunk it has cached\n * answers without reaching storage, so it can keep answering `true` for a dropped segment indefinitely. Tell\n * it with {@link invalidate}, or restart it.\n *\n * Needs the store built with a **backend** (throws {@link UnsupportedError} otherwise),\n * because it has to enumerate and delete generations \u2014 a pre-built `StorageChunkSource` only reads.\n */\n async dropSegment(\n ref: SegmentRef,\n options: { confirmSegment: string; dryRun?: boolean; audit?: IAuditSink },\n ): Promise<DropResult> {\n validateSegmentRef(ref);\n const deps = this.lifecycleDeps('dropSegment');\n try {\n return await dropSegment(ref, { registry: deps.registry, storage: deps.storage }, options);\n } finally {\n if (options.dryRun !== true) this.engine.invalidate(ref);\n }\n }\n\n /**\n * **Record when this segment becomes eligible for retirement.** One registry write; nothing is deleted here,\n * and nothing starts running. `retireExpired` is what acts on the policy, and **you** decide when that runs \u2014\n * an EventBridge rule, a CronJob, a queue consumer, whatever your deployment already has. This library starts\n * no background thread (it has to work identically in a Lambda, an edge isolate and a long-lived server).\n *\n * `expiresAt` is an **absolute epoch-ms you compute**, not a duration the library derives. A relative TTL would\n * have to be anchored to something the library knows \u2014 `updatedAt`, or the current generation \u2014 and every load\n * rewrites both, so \"expire 30 days after the last write\" would keep a busy daily bucket alive forever\n * precisely because it is being reloaded.\n *\n * ```ts\n * const DAY = 86_400_000;\n * const ref = { namespace: 'active-daily', segment: '2026-08-05' };\n * await store.setRetention(ref, { expiresAt: Date.now() + 30 * DAY });\n * ```\n *\n * **Works before the first load**: a segment with no registry row yet gets one (`createdRow: true` in the\n * result) with **no Storage generation**, so the policy is recorded ahead of the data and the segment is already\n * enumerable by the sweep; the first load then publishes onto that row.\n *\n * A value in the past is legal and means \"eligible on the next sweep\" \u2014 backfilling a policy onto existing\n * buckets is normal. A value below `MIN_EXPIRES_AT_MS` (2001-09-09) is rejected: it is almost certainly epoch\n * **seconds**, which would read as long-expired and retire the segment on the next pass. Needs a storage\n * backend (throws {@link UnsupportedError} otherwise), and refuses a crypto-shredded segment.\n */\n async setRetention(ref: SegmentRef, policy: RetentionPolicy): Promise<SetRetentionResult> {\n validateSegmentRef(ref);\n return setSegmentRetention(ref, { registry: this.requireRegistry('setRetention') }, policy);\n }\n\n /**\n * **The stored retention policy**, or `null` if the segment has none (or has no registry row, or is a\n * tombstone). Returns the string `'invalid'` for a row whose `expiresAt` is present but unusable \u2014 a\n * hand-edited row, or one from a restore \u2014 so a malformed policy is visible rather than silently reading as\n * \"never expires\" on a segment someone believes is expiring.\n */\n async getRetention(ref: SegmentRef): Promise<RetentionPolicy | null | 'invalid'> {\n validateSegmentRef(ref);\n return getSegmentRetention(ref, { registry: this.requireRegistry('getRetention') });\n }\n\n /**\n * **Cancel a segment's expiry** so no sweep retires it. Returns whether a policy was actually removed (`false`\n * when there was none). A separate verb from `setRetention` on purpose: \"never expire\" as a magic value passed\n * to the setter is how a typo becomes a deletion.\n */\n async clearRetention(ref: SegmentRef): Promise<boolean> {\n validateSegmentRef(ref);\n return clearSegmentRetention(ref, { registry: this.requireRegistry('clearRetention') });\n }\n\n /**\n * **Run the retention sweep: retire every segment whose `expiresAt` has passed.** This is the call that acts on\n * the policies `setRetention` records \u2014 and it is a **call, not a daemon**. Nothing schedules it; you run it from\n * whatever heartbeat your deployment already has (an EventBridge rule, a Kubernetes CronJob, a queue consumer,\n * the job that runs your loads). A library that started a timer would behave differently in a Lambda, an edge\n * isolate and a long-lived server, which is worse than not having one.\n *\n * Each retirement goes through `dropSegment`, so the registry \u2192 Storage ordering, the re-sweep for an object a\n * load was still writing, and the `generationsRemaining` report all come from one implementation rather than\n * two.\n *\n * ```ts\n * // In your scheduled handler. Start with a preview in a new deployment.\n * const preview = await store.retireExpired({ namespace: 'active-daily', dryRun: true });\n * console.log(`would retire ${preview.wouldRetire} of ${preview.scanned} (limited: ${preview.limited})`);\n *\n * const swept = await store.retireExpired({ namespace: 'active-daily' });\n * for (const e of swept.entries) {\n * if (e.action === 'skipped') console.warn(`${e.segment}: ${e.reason}`); // invalid-policy / limit / failed: \u2026\n * if (e.action === 'retired' && e.result.generationsRemaining.length > 0) {\n * console.warn(`${e.segment}: storage not fully reclaimed \u2014 re-run`);\n * }\n * }\n * if (swept.limited) scheduleAnotherPassSoon(); // more are still eligible\n * ```\n *\n * **Read the ledger.** A per-segment *fault* is an entry, not an exception \u2014 a throw from the middle of a fleet\n * sweep would leave the caller unable to say which segments were retired, having already retired some. (A bad\n * argument does throw, and so does a fleet larger than `maxScanSegments`.) `limited: true` means the per-cycle\n * `limit` (default 100) cut the pass short and more are eligible. That cap is charged on **attempts**, not\n * successes, which is what makes it a real bound: `dropSegment` writes the tombstone before sweeping Storage, so a\n * fault in the Storage phase is a segment that is already retired. Retirements are sequential, so `limit` is a\n * wall-clock knob too, and `retired` counts deletions only \u2014 a dry run reports `wouldRetire` instead, so a\n * dashboard summing `retired` can never show a phantom deletion.\n *\n * It also **deletes the tombstone rows its own past retirements left**, after `tombstoneGraceMs` (default 24 h)\n * and only once that segment's Storage generations are provably gone \u2014 collecting a straggler generation itself\n * first, since nothing else ever would for a tombstoned segment. Attribution is a **positive marker the sweep\n * stamps on its own retirements**, not an inference from \"destroyed + an expired policy\": a crypto-shred leaves\n * `retention` untouched, so setting a policy and then honouring a right-to-erasure request mid-window produces\n * exactly that row, and deleting it would destroy the Art. 17 attestation and un-fence the name. By default a\n * segment that held nothing has its row deleted in the pass that retires it, since that row would only fence the name.\n * Pass `purgeTombstones: false` to keep every tombstone, that row included.\n *\n * Needs the store built with a **backend** (throws {@link UnsupportedError} otherwise),\n * because retiring a segment deletes its storage objects. `now` defaults to the store's clock.\n */\n async retireExpired(\n options: Omit<RetireExpiredOptions, 'now'> & { now?: number } = {},\n ): Promise<RetireExpiredResult> {\n const deps = this.lifecycleDeps('retireExpired');\n const result = await retireExpired(\n { registry: deps.registry, storage: deps.storage },\n { ...options, now: options.now ?? this.clock.now() },\n );\n // A retirement tombstones and reclaims segments this store may already have resolved. `dryRun` changes\n // nothing, so it invalidates nothing.\n if (options.dryRun !== true) {\n for (const entry of result.entries) {\n this.engine.invalidate({ segment: entry.segment, namespace: entry.namespace });\n }\n }\n return result;\n }\n\n /**\n * **Forget everything this store has cached about a segment.** Use it after destroying or retiring a segment\n * through a path this store did not perform itself.\n *\n * A store keeps two layers of derived state \u2014 a resolved snapshot per segment (an open `.crbm` reader, plus\n * the DEK it unwrapped) and decoded chunks keyed by generation. Both are built for one event: **a publish\n * that advances `currentGen`**, which the snapshot TTL notices and the generation-keyed cache misses on.\n * Neither notices an event that *destroys* what they were derived from.\n *\n * The store's own writes handle themselves: `load`, `rollback`, `eraseSubject`, `dropSegment` and `retireExpired`\n * here, and a segment's `*Into` verbs, invalidate what they touch. This method is for the cases they cannot see:\n *\n * - **`destroySegment` / `eraseNamespace`**, which are free functions over raw drivers rather than methods\n * here, so a crypto-shred performed beside this store invalidates nothing in it. It keeps its open reader and\n * the unwrapped DEK, and decrypts with them, chunks it had never fetched before the shred included, until its\n * snapshot re-resolves: within `cache.genTtlMs` when the store has a registry and a `genTtlMs` above 0, and\n * otherwise only when its caches let the segment go or a read has to fetch from a generation a sweep collected.\n * A pin answers with no timed bound, until it is told or both caches let it go.\n * - **Another process.** Erasing on one box invalidates nothing on the others; each store bounds its own\n * staleness by `cache.genTtlMs`, and a store with no registry (a bare `IStorageDriver`), with\n * `cache.genTtlMs: 0`, or on a storage source built with no clock has no bound at all: it converges only when a read happens to miss its caches. If a compliance deadline depends on every\n * reader converging, you need to signal them \u2014 this is the call to make when your own fan-out delivers.\n *\n * It also forgets any replacement this store found of a pin's object, so once it is called after a restore puts that\n * object back, the pin reads it again.\n *\n * Synchronous, best-effort, and safe to call for a segment this store has never read.\n *\n * ```ts\n * await destroySegment(ref, { registry: backend.registry }, { confirmSegment: ref.segment });\n * store.invalidate(ref); // this process\n * await bus.publish('cloudbitmaps.invalidate', ref); // and every other one\n * ```\n */\n invalidate(ref: SegmentRef): void {\n validateSegmentRef(ref);\n refuseReservedNamespace(ref.namespace);\n this.engine.invalidate(ref);\n }\n\n /**\n * Build a handle held at the generation `ref` resolves to right now. See {@link Segment.pin}.\n *\n * The pinned handle gets its own engine but **shares the store's chunk cache**, under keys of its own: the\n * pinned view reports the version captured at pin time, marked as a pin's, so its decoded chunks are never\n * those of a live read that fetched across a publish (see {@link PinnedStorageChunkSource.currentVersion}).\n */\n private async pinSegment(ref: SegmentRef, expiresAt?: number): Promise<Segment> {\n const crbm = this.crbmSource;\n if (crbm === undefined) {\n throw new UnsupportedError(\n 'pin() needs the `.crbm` storage source \u2014 pass a backend or a raw IStorageDriver as `storage` (a pre-built StorageChunkSource ' +\n 'that cannot resolve a generation has nothing to pin)',\n );\n }\n // Under the store's retries, as its reads are: a transient fault resolving the pin must not fail pin().\n const at = await this.withRetries(() => crbm.pinGeneration(ref));\n const pinnedAt: PinnedAt = {\n generation: at?.generation ?? null,\n version: at?.version ?? null,\n fingerprint: at?.fingerprint ?? null,\n };\n const pins = new Map([[segmentKey(ref), pinnedAt]]);\n return makeSegment({\n engine: this.engineWithPins(pins),\n ref,\n clock: this.clock,\n metrics: this.metrics,\n materialize: (dest, ids, op, options) => this.materialize(dest, ids, op, options),\n pinned: (r, e) => this.pinSegment(r, e),\n combineEngine: (handles) => this.engineForCombine(handles),\n expiresAt,\n pinnedAt,\n });\n }\n\n /**\n * An engine reading every segment in `pins` at its pinned generation and everything else live, with the store's\n * retries, so a transient fault on a pinned read is retried as it would be on a live one.\n *\n * It **shares the store's chunk cache and its memory bound**, under keys of its own for each pinned segment.\n */\n private engineWithPins(pins: ReadonlyMap<string, PinnedAt>): SegmentEngine {\n const crbm = this.crbmSource;\n if (crbm === undefined) {\n throw new UnsupportedError(\n 'pin() needs the `.crbm` storage source \u2014 pass a backend or a raw IStorageDriver as `storage` (a pre-built StorageChunkSource ' +\n 'that cannot resolve a generation has nothing to pin)',\n );\n }\n const pinned = new PinnedStorageChunkSource(crbm, pins);\n return new SegmentEngine({\n storage:\n this.retryOptions === undefined\n ? pinned\n : new RetryingStorageChunkSource(pinned, this.retryOptions),\n cache: this.cache,\n codec: roaringCodec,\n clock: this.clock,\n metrics: this.metrics,\n budget: this.budget,\n });\n }\n\n /**\n * The engine a combine should run on, given the handles involved.\n *\n * A pinned handle passed as an **operand** must still be read at its pin. Routing by \"which handle the call\n * was made on\" reads it live instead \u2014 `snap.intersect([other])` honours the pin while\n * `other.intersect([snap])` silently does not, and the two are the same question. So the combine collects\n * every pin in play and runs on an engine that honours all of them. With no pins anywhere this is the\n * store's own engine and costs nothing.\n *\n * One engine reads a segment at one generation, so a combine that holds the same segment at two \u2014 two pins of\n * it, or a pin and a live handle \u2014 is refused. Keeping one of them would answer the question for the wrong\n * instant, and say nothing: diffing two snapshots of a segment returned no ids at all.\n */\n private engineForCombine(handles: readonly Segment[]): SegmentEngine | undefined {\n // A combine that pins nothing \u2014 nearly every one \u2014 cannot hold a segment twice at two generations, so it pays\n // one pass over its handles and nothing more.\n if (!handles.some((h) => h.pinnedAt !== undefined)) return undefined;\n const pins = new Map<string, PinnedAt>();\n const held = new Map<string, PinnedAt | undefined>();\n for (const h of handles) {\n const key = h.key();\n const at = h.pinnedAt;\n if (held.has(key)) {\n const before = held.get(key);\n if (!samePin(before, at)) {\n throw new ValidationError(\n `the same segment is in this combine twice, ${twoPins(before, at)}: one call reads a segment at one ` +\n 'generation, so materialise one of them into a segment of its own first, with ' +\n '`intersectInto(dest, [])`',\n );\n }\n } else {\n held.set(key, at);\n }\n if (at !== undefined) pins.set(key, at);\n }\n return this.engineWithPins(pins);\n }\n\n /** `op` under the store's retries, as the store's own reads run; bare when the store has retries off. */\n private withRetries<T>(op: () => Promise<T>): Promise<T> {\n const r = this.retryOptions;\n return r === undefined ? op() : withRetry(op, r.policy ?? DEFAULT_RETRY_POLICY, r);\n }\n\n /** The store's registry, or a typed error naming the operation that needs one. */\n private requireRegistry(op: string): IRegistryDriver {\n if (this.registry === undefined) {\n throw new UnsupportedError(\n `${op} needs a storage backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or ` +\n `MemoryStorage. A bare IStorageDriver has no generation pointer to publish through, and there is ` +\n `no separate \\`registry\\` option: a backend carries it.`,\n );\n }\n return this.registry;\n }\n\n /**\n * **Cross-tier DR consistency check.** After a restore/failover, verify every registered segment's `currentGen`\n * actually has its `.crbm` present in Storage \u2014 catching a **torn restore** where the registry (`currentGen`) came\n * back ahead of the object store, so a pointer references a generation that isn't there (reads would then\n * throw). Read-only, bounded fan-out; run it at startup after a restore. Returns `{ checked, inconsistent,\n * errored }` \u2014 `inconsistent` empty \u21D2 coherent; otherwise it names the segments to recover (restore the object\n * store, or roll the registry back to a coherent point). Needs the store built with a **backend**\n * (throws {@link UnsupportedError} otherwise). `destroyed` (crypto-shredded) segments are skipped. Pair it with\n * the DR runbook (docs/guide/disaster-recovery.md).\n *\n * It holds the registry rows it enumerates resident, at most 250,000 of them, and throws\n * `BudgetExceededError` past that rather than report a partial scan as a whole one. This method takes no\n * ceiling of its own: narrow the scan with `namespace`, or call `runConsistencyCheck` over the backend's\n * `storage` and `registry` with a higher `maxScanSegments`.\n */\n async checkConsistency(\n options: { namespace?: string; concurrency?: number } = {},\n ): Promise<ConsistencyReport> {\n const deps = this.lifecycleDeps('checkConsistency');\n return runConsistencyCheck({ storage: deps.storage, registry: deps.registry }, options);\n }\n\n /**\n * **Export (\"eject\") every registered segment's current generation** through the injected `sink`, using only\n * public read APIs \u2014 so your data is readable **without CloudRoaring** (the exit path; see the README's \"Your\n * data stays yours\"). `format: 'roaring'` (default) writes one **portable RoaringBitmap32** per segment\n * (loadable by any roaring library); `'ndjson'` writes newline-delimited ids (zero-dependency, streaming).\n * Enumerates via the store's **own** registry (needs one \u2014 throws {@link UnsupportedError} otherwise) so the\n * enumeration and the read path provably share one registry. Encrypted segments are decrypted transparently\n * **iff** this store was wired with their keystore \u2014 the export is therefore **cleartext**; protect it.\n * Crypto-shredded segments are skipped. A segment that can't be read is isolated into the manifest's `failed[]`\n * (the run continues), so \"a manifest exists\" means the run finished \u2014 check `failed`. The `export-segments`\n * CLI wraps this with a filesystem sink.\n */\n async exportSegments(sink: ExportSink, options: ExportOptions = {}): Promise<ExportManifest> {\n const registry = this.requireRegistry('exportSegments');\n // Pass the codec: core's `runExport` is codec-agnostic and needs one for the `'roaring'` format.\n return runExport(this, registry, sink, {\n ...options,\n codec: options.codec ?? roaringCodec,\n });\n }\n\n /**\n * Planning cost estimate \u2014 pure, no instance/data needed: sizing, sales, what-if. For a real, grounded report\n * from live segment sizes, use `store.segment(name).costReport()`. See {@link CostReport}.\n */\n static estimateCost(input: EstimateInput): CostReport {\n return estimateCost(input);\n }\n}\n\n/**\n * Options common to every chunk-aligned combine (`intersect` / `union` / `andNot`), and the `*Into` verbs.\n *\n * The range, `after` and `through`, applies to every operand and every `exclude`: the combine yields only the ids\n * in `(after, through]` and fetches only the chunks the range overlaps, as {@link Segment.iterate} does.\n */\nexport interface BaseCombineOptions extends IdRange {\n /** Max chunk keys resolved concurrently \u2014 bounds the Storage footprint. A positive integer. */\n readonly concurrency?: number;\n /** Override the store's per-op denial-of-wallet budget for this call (`false` lifts it). */\n readonly budget?: BudgetOption;\n /**\n * Allow an operand naming a segment that does not exist. Default `false`: a combine **refuses** one, because\n * a misspelled or mis-namespaced operand is indistinguishable from a correct one in the result.\n *\n * Reading a segment that does not exist answers empty, and that is right \u2014 but passing one as an operand is\n * different. A suppression list with nobody on it correctly suppresses nothing; one whose `namespace` you\n * omitted *silently* suppresses nothing, and the result is not obviously-empty, it is the full audience and\n * plausibly right. The failure mode is mailing the people who opted out.\n *\n * ```ts\n * // `global-opt-out` lives in the `suppression` namespace. This addresses a DIFFERENT segment:\n * audience.andNot([store.segment('global-opt-out')]); // throws ValidationError\n * audience.andNot([store.segment('global-opt-out', { namespace: 'suppression' })]); // correct\n * ```\n *\n * Set `true` when you genuinely intend to combine against a name that may not exist yet. Checked only for an\n * operand that resolved to no chunks at all, so a normal combine pays nothing for it.\n */\n readonly allowAbsentOperands?: boolean;\n}\n\n/**\n * A combine that can also subtract.\n *\n * `exclude` is why suppression does not need an intermediate segment: applied here it folds into the same\n * chunk-aligned pass, and each exclude is read **only at the keys that survived** \u2014 so a large global opt-out\n * list costs reads proportional to the audience, not to itself.\n */\nexport interface CombineOptions extends BaseCombineOptions {\n /**\n * Segments whose ids are subtracted from the result. An **expired** handle here excludes nothing, in every\n * combine \u2014 it is skipped without being read, exactly as in {@link Segment.andNot}.\n */\n readonly exclude?: Segment[];\n}\n\n/**\n * A combine that WRITES its result \u2014 the extra options `intersect`/`union`/`andNot` have no use for.\n *\n * Separate from {@link CombineOptions} on purpose: `allowEmpty` and `guard` decide whether a generation is\n * published, and a read verb publishes nothing. Offering them on `intersect()` would be offering a parameter\n * that cannot do anything.\n */\nexport interface MaterializeOptions extends CombineOptions {\n /**\n * Audit sink. A materialisation publishes a generation, and a publish is an auditable event\n * (`segment.publish`, exactly as a load emits) \u2014 as is a refusal (`segment.load-refused`).\n *\n * It is on the call rather than on the store because that is where every other auditable operation takes it\n * (`eraseSubject`, `dropSegment`, `retireExpired`): the caller who performs the act decides where the record\n * goes. Without it a `*Into` would be the one write path in the library that could make a generation current\n * and leave no trace in the compliance trail.\n *\n * It sits HERE rather than on {@link BaseCombineOptions} for the reason this type exists: the streaming verbs\n * write nothing, so an audit sink on `intersect()` would be a parameter that could not do anything.\n */\n readonly audit?: IAuditSink;\n /**\n * Publish an empty result over a non-empty destination. Off by default, exactly as on {@link CloudRoaring.load}:\n * an empty combine is far more often a mistake upstream \u2014 a typo'd operand, a segment that has not loaded\n * yet, an `exclude` that swallowed everything \u2014 than an intent, and once it lands it is indistinguishable\n * from a correct run.\n */\n readonly allowEmpty?: boolean;\n /** Refuse an implausible result rather than publish it. Same bounds, and same meaning, as on `load()`. */\n readonly guard?: LoadGuard;\n /**\n * Generations to keep below the new pointer \u2014 see {@link LoadOptions.keep}. A value that is not a non-negative\n * integer throws `ValidationError`.\n *\n * **Defaults to keeping everything**, unlike `load()`, which keeps 1 and collects the rest. An operator's\n * recovery story can depend on a materialisation collecting nothing: `rollbackSegment` refuses a target that\n * has been collected. Pass a number to collect on the way through; `0` keeps only the\n * generation this call publishes.\n */\n readonly keep?: number;\n}\n\n/**\n * An id stream that fails when it is first read. A combine refuses its arguments this way, as the engine's own\n * checks do, so a caller's try/catch around the iteration catches it.\n */\nconst failing = (err: unknown): AsyncIterable<number> => ({\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(err) }),\n});\n\n/** Whether two handles of one segment read it at one generation: both live, or both pinned to one object. */\nconst samePin = (a: PinnedAt | undefined, b: PinnedAt | undefined): boolean =>\n a === undefined || b === undefined\n ? a === b\n : a.generation === b.generation && a.fingerprint === b.fingerprint;\n\n/** How a refusal names two handles of one segment that read it at two generations. */\nconst twoPins = (a: PinnedAt | undefined, b: PinnedAt | undefined): string => {\n const one = (p: PinnedAt | undefined): string =>\n p === undefined ? 'live' : `pinned at generation ${p.generation ?? 'none'}`;\n return a !== undefined && b !== undefined && a.generation === b.generation\n ? `pinned twice at generation ${a.generation ?? 'none'}, as two different objects`\n : `${one(a)} and ${one(b)}`;\n};\n\n/** Every key of `T`, each possibly `undefined`: a copy typed this way fails to compile until it names every field. */\ntype EveryField<T> = { [K in keyof Required<T>]: T[K] | undefined };\n\n/** A read's range, read once, now, from whatever object holds it: a getter or an inherited bound included. */\nconst rangeOf = (options: IdRange): EveryField<IdRange> => ({\n after: options.after,\n through: options.through,\n});\n\n/**\n * A combine's options, read once, now, field by field, for the same reason as {@link rangeOf}. Typed to name every\n * field, so an option added to {@link BaseCombineOptions} and not listed here fails to compile instead of being\n * dropped.\n */\nconst readOptions = (options: BaseCombineOptions): EveryField<BaseCombineOptions> => ({\n ...rangeOf(options),\n concurrency: options.concurrency,\n budget: options.budget,\n allowAbsentOperands: options.allowAbsentOperands,\n});\n\nconst NO_SEGMENTS: readonly Segment[] = [];\n\n/** The empty id stream every expired read path returns \u2014 allocated once, so an expired read costs nothing. */\nconst EMPTY_IDS: AsyncIterable<number> = {\n async *[Symbol.asyncIterator]() {\n // deliberately yields nothing\n },\n};\n\n/**\n * What `andNotInto` takes: the write options without `exclude`, because its `excludes` argument IS the\n * subtraction \u2014 a second one in the options would be two spellings of one thing.\n *\n * Named rather than left as an inline `Omit` so it can be imported and annotated. The read sibling `andNot`\n * solves the same problem the same way, by taking {@link BaseCombineOptions}.\n */\nexport type AndNotIntoOptions = Omit<MaterializeOptions, 'exclude'>;\n\n/**\n * The `keep` a materialisation passes when the caller does not: a grace window wide enough to collect nothing.\n *\n * The collection keeps the newest `keep` generations below the pointer and deletes the rest, so an\n * integer at the top of the range keeps all of them. It has to be an integer \u2014 `loadSegment` validates that,\n * and `Infinity` is rejected \u2014 which is why this is `MAX_SAFE_INTEGER` and not the value that reads more\n * naturally.\n */\nconst KEEP_EVERY_GENERATION = Number.MAX_SAFE_INTEGER;\n\n/** How a `Segment` hands a result stream back to its store to become a new generation of `dest`. */\n/** Build a pinned twin of a handle \u2014 injected into `Segment` so it stays free of store wiring. */\ntype Pin = (ref: SegmentRef, expiresAt?: number) => Promise<Segment>;\n\n/**\n * The engine a combine should run on, given every handle involved \u2014 `undefined` when none is pinned and the\n * store's own engine will do. Injected so `Segment` stays free of store wiring.\n */\ntype CombineEngine = (handles: readonly Segment[]) => SegmentEngine | undefined;\n\ntype Materialize = (\n dest: SegmentRef,\n ids: AsyncIterable<number>,\n op: string,\n options?: MaterializeOptions,\n) => Promise<MaterializeResult>;\n\n/** What a {@link Segment} is built from: the store's own wiring, which is why a handle is not constructible. */\ninterface SegmentParts {\n engine: SegmentEngine;\n ref: SegmentRef;\n clock: Clock;\n metrics: IMetricsSink;\n materialize: Materialize;\n /** Build a pinned twin of this handle \u2014 injected so `Segment` stays free of store wiring. */\n pinned: Pin;\n combineEngine: CombineEngine;\n expiresAt?: number;\n pinnedAt?: PinnedAt;\n}\n\n/** The store's one way to mint a {@link Segment}, bound by the class's static block. */\nlet makeSegment: (parts: SegmentParts) => Segment;\n/** True only while {@link makeSegment} is constructing, so a `new Segment(...)` from plain JS is refused. */\nlet minting = false;\n\n/**\n * A handle bound to one segment \u2014 the read verbs, plus the three `*Into` verbs that write a **new generation**\n * of another segment.\n *\n * **IDs must be integers in `[0, 2^32)`** (dense 32-bit). A non-integer / negative / out-of-range id\n * throws {@link ValidationError}.\n *\n * A handle has no per-id write: data enters a segment as a whole generation (`store.load()`, or one of the\n * `*Into` verbs), and leaves it the same way (`eraseSubject`, `dropSegment`).\n */\nexport class Segment {\n private readonly metricsOn: boolean;\n private readonly engine: SegmentEngine;\n private readonly ref: SegmentRef;\n private readonly clock: Clock;\n private readonly metrics: IMetricsSink;\n private readonly materialize: Materialize;\n private readonly pinned: Pin;\n private readonly combineEngine: CombineEngine;\n /** Absolute epoch-ms deadline from {@link SegmentOptions.expiresAt}; `undefined` \u21D2 this handle never expires. */\n readonly expiresAt?: number;\n /**\n * The generation this handle is held at, when it came from {@link Segment.pin}. Read by the store so a\n * pinned handle passed as an **operand** is still read at its pin rather than live.\n */\n readonly pinnedAt?: PinnedAt;\n\n static {\n makeSegment = (parts) => {\n minting = true;\n try {\n return new Segment(parts);\n } finally {\n minting = false;\n }\n };\n }\n\n /**\n * Not constructible: a handle comes from {@link CloudRoaring.segment}, which wires it to the store's engine,\n * caches and write path. The constructor takes those internals, so it is not part of the surface.\n */\n private constructor(parts: SegmentParts) {\n if (!minting) {\n throw new ValidationError(\n 'a Segment is not constructed directly; call `store.segment(name)`',\n );\n }\n this.engine = parts.engine;\n this.ref = parts.ref;\n this.clock = parts.clock;\n this.metrics = parts.metrics;\n this.materialize = parts.materialize;\n this.pinned = parts.pinned;\n this.combineEngine = parts.combineEngine;\n this.expiresAt = parts.expiresAt;\n this.pinnedAt = parts.pinnedAt;\n this.metricsOn = parts.metrics !== NOOP_METRICS;\n }\n\n /**\n * **Hold this segment at the generation that is current right now**, for as long as you keep the handle.\n *\n * An ordinary handle re-resolves on `cache.genTtlMs`, so a publish part-way through a long job means its second\n * half describes a different instant than its first \u2014 every chunk whole and verified, but the answer covering\n * two moments, with nothing in the result saying so. That is fine for a dashboard and wrong for an export, a\n * reconciliation, or a send that has to match the count you reported. A pin is how you get one instant.\n *\n * ```ts\n * const snap = await store.segment('active-30d').pin();\n * const total = await snap.count(); // the number you report\n * for await (const id of snap.iterate()) { \u2026 } // \u2026and the ids it counted, however long this takes\n * ```\n *\n * **Only this segment is pinned.** `snap.intersect([other])` reads `snap` at its pinned generation and\n * `other` at whatever is current \u2014 pin each segment if you want the whole query held. And a pinned handle\n * used as an *operand* is still read at its pin, never live.\n *\n * **One call reads a segment at one generation**, so a combine that holds this segment at two \u2014\n * `snap0.andNot([snap1])`, or `live.intersect([snap])` \u2014 throws {@link ValidationError} when it is read, and an\n * `*Into` of one throws before it reads anything. Materialise one side first, with `intersectInto(dest, [])`.\n *\n * **A pin knows its object, not only its number.** A name purged and loaded again starts again at generation\n * 0, so a pin of the old segment never reads the new one: what it has already read still answers, as the\n * instant it pinned, and anything it would have to fetch fails with `NotFoundError`, as a swept pin's does.\n *\n * **It is a hold, not a lease.** Nothing here stops a collection deleting the generation underneath\n * you: a pinned read deliberately does **not** heal forward, because silently serving a different generation\n * is the one thing a pin exists to prevent, so it fails instead. Size `keep` to cover your longest pinned\n * job \u2014 see [Generations and `keep`](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/loading.md#generations-and-keep) \u2014 or take the pin on a segment\n * you are not collecting.\n *\n * A segment with no current generation pins nothing and reads empty, exactly as it would unpinned. A pinned\n * segment whose row is later dropped or destroyed fails once it must open its object again, rather than go empty\n * part-way through a call. **A pin\n * keeps the key its reader unwrapped for as long as that reader stays open, and answers from the chunks it\n * decoded for as long as they stay cached.** This store invalidates a pin:\n *\n * - a `load`, a `rollback` or an `*Into` invalidates a pin of the segment it writes;\n * - `dropSegment` invalidates a pin of the segment it drops, and `retireExpired` a pin of each segment its ledger\n * lists, retired or not, neither on a dry run;\n * - `eraseSubject` invalidates a pin of each segment it scans that is not already destroyed.\n *\n * An invalidated pin opens its object again, and fails if that object is gone or replaced, or its row is gone or\n * destroyed.\n * Anything else leaves the pin as it is: after a `destroySegment` beside this store, or an erasure, a drop or a\n * retirement through another store, in this process or another, the pin answers from what it holds until this\n * store's reader cache evicts the pin's reader and its chunk cache evicts the chunks the pin decoded, or\n * {@link CloudRoaring.invalidate} is called on this store. Where the\n * object the pin reads has been deleted, by an erasure, a drop or a sweep, a chunk the pin has not cached fails at\n * once. No timed refresh bounds any of that, as none bounds anything else a pin holds.\n *\n * A replacement a pin has found is remembered, so its later chunk reads fail with no request, until the store\n * forgets it: an invalidation of the segment does, as does a later `pin()` of the same version that opens the object\n * again, and the store remembers at most `cache.readerMax` of them. So once a restore puts the pinned object back,\n * call {@link CloudRoaring.invalidate} on this store: the pin then reads the object again.\n *\n * `pin()` reads the registry row and opens the generation at once, so the pin knows its object before its first\n * read. With a registry, pins of one generation taken while its row is unchanged share one reader while the store\n * keeps it open, pins taken at the same moment included: the first costs a tail read, and a key unwrap for an\n * encrypted segment, whether or not it is read, and the rest cost the row read alone. Without a registry every\n * `pin()` lists the segment's objects and makes the tail read, since only the object can tell two incarnations of\n * a name apart there. It retries a\n * transient fault as the store's reads do, and heals a generation swept between the two, but it fails where the\n * generation cannot be opened: `NotFoundError` for a pointer at a missing object, `IntegrityError` for a damaged\n * or misfiled one.\n *\n * Needs a store built on the `.crbm` storage source (the default when you pass a backend or a raw driver). Throws\n * {@link UnsupportedError} on a store wired with a pre-built source that cannot pin.\n */\n async pin(): Promise<Segment> {\n return this.pinned(this.ref, this.expiresAt);\n }\n\n /**\n * An opaque string that names this handle's segment, namespace included: two handles of one segment have the\n * same key, a live handle and its pins among them. Use it as a `Map` key or a log field when you track handles\n * and have not kept the name you made them with. The format is not specified and is not a storage key, so\n * compare keys, never parse one.\n */\n key(): string {\n return segmentKey(this.ref);\n }\n\n /**\n * Has this handle's deadline passed? **The lazy half of expiry** \u2014 the whole check is one comparison against\n * the injected clock, so it costs nothing on a handle with no deadline and no I/O on one that has expired.\n *\n * Deliberately evaluated per call rather than cached: a long-lived handle created before its deadline must\n * start reading empty the moment the deadline passes, without the caller re-creating it.\n */\n private expired(): boolean {\n return this.expiresAt !== undefined && this.clock.now() >= this.expiresAt;\n }\n\n /**\n * Refuse a materialisation that involves an **expired** handle. Called by the three `*Into` verbs only.\n *\n * On the read verbs an expired handle answers empty, which is the point of lazy expiry. On a *write* the same\n * rule would be destructive in a way nobody asks for: `a.intersectInto(dest, [b])` where `b`'s deadline has\n * quietly passed would, unrefused, replace `dest` with an **empty generation** \u2014 a wipe, reported as a successful\n * write, with the cause (a deadline on a handle somewhere) nowhere in the result. Reads degrade to empty; writes must not.\n *\n * So every handle in the call is checked, `dest` included: an expired `dest` does not change the bytes written,\n * but a caller who put a deadline on the thing they are writing into has said something contradictory and is\n * better told than guessed at. Open a handle without `expiresAt` to write, or drop the deadline.\n *\n * (The broader guard \u2014 refusing to publish an empty or implausible generation over a non-empty one, with an\n * `allowEmpty` override \u2014 covers these verbs too: they route through the same guarded write path as\n * {@link CloudRoaring.load}. The two stay separate because they differ in kind. That one is a REPORTED\n * refusal a caller may legitimately override; an expired handle is a wiring mistake, so it THROWS, before\n * any object is written \u2014 and `allowEmpty: true` does not reach it.)\n *\n * The verbs are `async` so this surfaces as a **rejected promise**, like every other validation in the facade \u2014\n * a synchronous throw out of a promise-returning method escapes a caller who attached `.catch()` instead of\n * awaiting.\n */\n private refuseIfExpired(op: string, dest: Segment, operands: readonly Segment[]): void {\n const stale: string[] = [];\n for (const seg of [this, dest, ...operands]) {\n if (seg.expired())\n stale.push(seg.ref.namespace ? `${seg.ref.namespace}/${seg.ref.segment}` : seg.ref.segment);\n }\n if (stale.length > 0) {\n throw new ValidationError(\n `${op}: refusing to publish a generation while these handles have expired \u2014 ${[...new Set(stale)].join(', ')}. ` +\n `An expired handle reads as empty, so this would write an empty (or short) generation over \"${dest.ref.segment}\". ` +\n `Open the handles without \\`expiresAt\\` if you meant to materialise, or drop the deadline.`,\n );\n }\n }\n\n /**\n * Time an op with the injected clock and emit an `op` metric on completion (success or throw). Skipped\n * entirely when no sink is wired, so the default path pays nothing.\n */\n private async timed<T>(name: MetricOpName, fn: () => Promise<T>): Promise<T> {\n if (!this.metricsOn) return fn();\n const startedAt = this.clock.now();\n try {\n return await fn();\n } finally {\n this.metrics.onEvent({ kind: 'op', name, ms: Math.max(0, this.clock.now() - startedAt) });\n }\n }\n\n /** Membership: one chunk \u2014 the cache, else one ranged GET. Throws {@link ValidationError} on a bad id. */\n has(id: number): Promise<boolean> {\n if (this.expired()) return Promise.resolve(false);\n return this.timed('has', () => this.engine.has(this.ref, id));\n }\n /**\n * Cardinality \u2014 summed from the `.crbm` index with **zero payload reads** on a loaded segment.\n *\n * What this trusts: the answer is the sum of the per-chunk cardinalities the index records, and no payload is\n * decoded to confirm it. The index is checked for internal consistency when the object is opened (each key in\n * range and ascending, each cardinality in `1..65536`, each payload inside the payload region, and, on an\n * unencrypted object, the footer's chunk count and total agreeing with the index), and a corrupt index that is\n * still internally consistent yields a wrong count. `iterate()` and the combines decode the payloads, whose\n * structure is checked.\n */\n count(): Promise<number> {\n if (this.expired()) return Promise.resolve(0);\n return this.timed('count', () => this.engine.count(this.ref));\n }\n /**\n * Every id, ascending, streamed one chunk at a time. Pass a range to read part of the segment: the ids in\n * `(after, through]`, fetching only the chunks the range overlaps. The per-op budget is charged for every chunk in\n * the range, so give a page `through` as well as `after`. On a pinned handle it reads the pinned generation, as a\n * full read does.\n *\n * ```ts\n * // Keyset paging: each page resumes where the one before ended, and stops at its window's end.\n * for await (const id of seg.iterate({ after: previousEnd, through: windowEnd })) await send(id);\n * ```\n *\n * Each bound is optional and an integer in `0..4294967295`; a bad one throws {@link ValidationError} when the\n * stream is first read. `after >= through` is an empty range, which reads nothing. An expired handle reads empty\n * without checking its options, as every read of one does.\n */\n iterate(options?: IdRange): AsyncIterable<number> {\n if (this.expired()) return EMPTY_IDS;\n // Neither bound set is no range at all, which the engine reads on its full-read path.\n const range = options == null ? undefined : rangeOf(options);\n const none = range === undefined || (range.after === undefined && range.through === undefined);\n return this.engine.iterate(this.ref, none ? undefined : range);\n }\n\n /**\n * The options a combine hands the engine, read once, when it is called ({@link readOptions}), with the `exclude`\n * it was given, already reduced to its live handles ({@link liveExcludes}) and mapped down to the plain refs\n * `core` takes. A method rather than a module function because `ref` is class-private \u2014 the encapsulation is\n * worth more than the free function.\n *\n * Each field is named rather than copied with a rest spread: a rest copy takes only own enumerable properties, so\n * a bound held in a getter or inherited from a prototype was dropped, and the read silently widened to the whole\n * segment.\n */\n private refsIn(\n options: CombineOptions | null | undefined,\n exclude: readonly Segment[],\n ): (BaseCombineOptions & { exclude?: SegmentRef[] }) | undefined {\n if (options == null) return undefined;\n return {\n ...readOptions(options),\n exclude: exclude.length > 0 ? exclude.map((o) => o.ref) : undefined,\n };\n }\n\n /**\n * The handles in `options.exclude` that have not expired. **An expired exclusion excludes nothing**, in every\n * combine, so it is dropped here, before the engine is asked for anything: it is never fetched, never\n * checked for absence, and never counted in the pin-consistency check. `exclude` is read once, so a getter sees\n * one call.\n *\n * With no `exclude` this is one property read and a shared empty list, and with none expired it returns the\n * caller's own array, so the common case allocates nothing.\n */\n private liveExcludes(options: CombineOptions | null | undefined): readonly Segment[] {\n const exclude = options?.exclude;\n if (exclude == null || exclude.length === 0) return NO_SEGMENTS;\n return exclude.some((e) => e.expired()) ? exclude.filter((e) => !e.expired()) : exclude;\n }\n\n /**\n * Chunk-skipping intersection: stream the ids in **this** segment AND every segment in `others`, ascending.\n * Fetches only the Storage chunks present in *all* operands (a key absent from any operand contributes nothing\n * and is never downloaded), streaming under a bounded in-flight window \u2014 so the Storage footprint stays small\n * (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer).\n * AND is commutative, so `a.intersect([b])` and `b.intersect([a])` yield the same ids. Pass `budget` to\n * override the store's per-op denial-of-wallet budget for this call (or `false` to lift it).\n */\n intersect(others: Segment[], options?: CombineOptions): AsyncIterable<number> {\n // An expired operand is empty, and anything ANDed with the empty set is empty. Guarding here rather than\n // only in `count()` is what keeps the surface coherent: a segment whose `count()` is 0 must not still\n // contribute members to an intersection.\n if (this.expired() || others.some((o) => o.expired())) return EMPTY_IDS;\n const exclude = this.liveExcludes(options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...others, ...exclude]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.intersect([this.ref, ...others.map((o) => o.ref)], this.refsIn(options, exclude));\n }\n\n /**\n * Materialize `this \u2229 others\u2026` (minus `exclude`) as a **new generation of `dest`** \u2014 `dest`'s previous contents\n * are superseded, not added to. Streaming + bounded-memory; the result is one immutable object published\n * as a load is (the pointer advances to it, fenced on the row), so readers of `dest` see either the old generation\n * or the new one, never a partial. Needs the\n * store built with a backend (throws {@link UnsupportedError} otherwise).\n *\n * **An empty result does NOT overwrite a non-empty destination.** A combine that comes out empty is far more\n * often a mistake upstream \u2014 a typo'd operand, an `exclude` that swallowed everything, an operand that has\n * not loaded yet \u2014 than an intent, and once it publishes it is indistinguishable from a correct run. So the\n * write is **refused and reported**: `published: false`, `reason: 'empty'`, and `dest` keeps what it had.\n * Pass `allowEmpty: true` when emptying the destination is the point.\n *\n * `guard` adds the same plausibility bounds `load()` takes \u2014 `minCardinality` and `minRetained` \u2014 judged\n * against what `dest` held before. A refusal is **reported, not thrown**, exactly as on `load()`; branch on\n * `published`. A lost race is the one outcome that still throws ({@link WriteConflictError}), because a\n * materialisation that silently did not take effect is the one thing a caller cannot detect on its own.\n *\n * A call involving an **expired handle** is refused before any of this. See {@link refuseIfExpired}.\n */\n async intersectInto(\n dest: Segment,\n others: Segment[],\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('intersectInto', dest, [...others, ...(options?.exclude ?? [])]);\n // Refused here, before `materialize` reads anything of `dest`, rather than when the load reads the combine: a\n // broken destination would otherwise answer first, and hide the refusal behind its own error.\n this.combineEngine([this, ...others, ...(options?.exclude ?? [])]);\n return this.timed('intersectInto', () =>\n this.materialize(dest.ref, this.intersect(others, options), 'intersectInto', options),\n );\n }\n\n /**\n * `this \u222A others\u2026`, minus `options.exclude` \u2014 streamed ascending.\n *\n * **The one composite read with no chunk-skipping,** and that is inherent to union rather than a limitation\n * here: an id in *any* operand belongs to the result, so every chunk of every operand must be read.\n * `intersect` prunes any key missing from any operand; union has nothing to prune. It is charged against the\n * same per-op budget, so a wide union is refused rather than quietly billed \u2014 pass `budget` to raise it\n * deliberately. If you find yourself unioning the same segments on every read, materializing the combined\n * segment once (`unionInto`, or a load) is the cheaper shape.\n */\n union(others: Segment[], options?: CombineOptions): AsyncIterable<number> {\n // OR: drop the expired operands and union what is left. All expired \u21D2 empty.\n const live = others.filter((o) => !o.expired());\n if (this.expired()) {\n if (live.length === 0) return EMPTY_IDS;\n return (live[0] as Segment).union(live.slice(1), options);\n }\n if (live.length === 0 && others.length > 0) {\n // Every operand expired \u21D2 just us. But `exclude` is not an operand of the union, it is a subtraction\n // applied to the result, so it still applies: `(this \u222A nothing) \\ exclude` is `this \\ exclude`. Returning\n // a bare `iterate()` here dropped it silently \u2014 an opt-out list that does not apply, on a library whose\n // headline is composable suppression, and reachable from nothing more exotic than a segment handle aging\n // out. `andNot` reads each exclude only where it overlaps, so this is also the cheap spelling.\n // With no exclude it is this segment alone, read as a one-operand union rather than as `iterate()`, so the\n // call's own `budget`, `concurrency` and range apply exactly as they would have to the union.\n const exclude = this.liveExcludes(options);\n return exclude.length > 0 ? this.andNot([...exclude], options) : this.union([], options);\n }\n if (live.length !== others.length) return this.union(live, options);\n const exclude = this.liveExcludes(options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...others, ...exclude]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.union([this.ref, ...others.map((o) => o.ref)], this.refsIn(options, exclude));\n }\n\n /** Materialize `this \u222A others\u2026` (minus `exclude`) as a **new generation of `dest`** \u2014 see {@link intersectInto}. */\n async unionInto(\n dest: Segment,\n others: Segment[],\n options?: MaterializeOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('unionInto', dest, [...others, ...(options?.exclude ?? [])]);\n this.combineEngine([this, ...others, ...(options?.exclude ?? [])]); // as intersectInto: before any read\n return this.timed('unionInto', () =>\n this.materialize(dest.ref, this.union(others, options), 'unionInto', options),\n );\n }\n\n /**\n * `this \\ (excludes\u2026)` \u2014 streamed ascending. Suppression on its own.\n *\n * Reads every chunk of `this` (any of them may survive the subtraction) but each exclude **only where it\n * overlaps this segment**, so the cost tracks the segment being filtered rather than the size of the\n * suppression list: at most one read per surviving key of `this`, so subtracting a 61,000-chunk global\n * opt-out list from a 40-chunk audience costs at most 40 reads, not 61,000.\n *\n * An expired handle in `excludes` excludes nothing, and is skipped without being read; if every one has\n * expired the result is `this` whole. An expired `this` is empty. `exclude` on `intersect` and `union` follows\n * the same rule.\n *\n * To filter the *result of an intersection*, do not chain \u2014 pass `exclude` to {@link intersect} instead, so\n * the suppression folds into the same pass rather than materializing an intermediate segment first.\n */\n andNot(excludes: Segment[], options?: BaseCombineOptions): AsyncIterable<number> {\n // MINUS: an expired base is empty; an expired exclusion excludes nothing.\n if (this.expired()) return EMPTY_IDS;\n const liveExcludes = excludes.filter((e) => !e.expired());\n // Every exclusion expired \u21D2 nothing to subtract. Recursing with an empty list would throw, since `andNot`\n // requires at least one operand \u2014 a caller whose suppression list happened to age out must not get an error.\n // It is read as a one-operand union rather than as `iterate()`, so the call's own `budget`, `concurrency` and range\n // still apply.\n // Only the call's own options go on, not an `exclude` a caller routed here with it: the excludes that expired are\n // the ones this branch exists to drop, and an expired exclusion excludes nothing.\n if (liveExcludes.length === 0 && excludes.length > 0) {\n return this.union([], options == null ? undefined : readOptions(options));\n }\n if (liveExcludes.length !== excludes.length) return this.andNot(liveExcludes, options);\n let engine: SegmentEngine;\n try {\n engine = this.combineEngine([this, ...excludes]) ?? this.engine;\n } catch (err) {\n return failing(err);\n }\n return engine.andNot(\n this.ref,\n excludes.map((o) => o.ref),\n options == null ? undefined : readOptions(options),\n );\n }\n\n /** Materialize `this \\ (excludes\u2026)` as a **new generation of `dest`** \u2014 see {@link intersectInto}. */\n async andNotInto(\n dest: Segment,\n excludes: Segment[],\n options?: AndNotIntoOptions,\n ): Promise<MaterializeResult> {\n this.refuseIfExpired('andNotInto', dest, excludes);\n this.combineEngine([this, ...excludes]); // as intersectInto: before any read\n return this.timed('andNotInto', () =>\n this.materialize(dest.ref, this.andNot(excludes, options), 'andNotInto', options),\n );\n }\n\n /**\n * Grounded cost report for this segment: storage cost from its **real** `.crbm` size (exact, no payload\n * reads); request cost from the supplied `workload` rates. A segment with no Storage generation reports zero\n * storage. The pointer refresh is priced at the store's own `cache.genTtlMs`, or at none when the store never\n * refreshes, unless the workload sets `genTtlMs`. See {@link CostReport} \u2014 it always includes a verdict (incl.\n * the lose-zone).\n */\n async costReport(options?: {\n pricing?: PricingProfile;\n workload?: Workload;\n }): Promise<CostReport> {\n const canMeasure = this.engine.supportsStorageSize;\n const size = canMeasure ? await this.engine.segmentSize(this.ref) : null;\n const refreshMs = this.engine.pointerRefreshMs;\n const workload =\n refreshMs === undefined || options?.workload?.genTtlMs !== undefined\n ? options?.workload\n : { ...options?.workload, genTtlMs: refreshMs };\n return groundedReport({\n storageBytes: size?.sizeBytes ?? 0,\n grounded: canMeasure,\n workload,\n pricing: options?.pricing,\n extraNotes: canMeasure\n ? undefined\n : ['storage source has no sizeOf() \u2014 storage not measured, reported as $0.'],\n });\n }\n}\n\n// ---------------------------------------------------------------------------------------------------\n// What `@cloudbitmaps/roaring` re-exports from `@cloudbitmaps/core`, by name: the store's verbs' types, the errors,\n// the types its signatures name, the backends' shared types, and the constants and helpers an application calls.\n// An application installs this package and imports from it alone. Flavor and driver authors import everything\n// else (the engine, the free-function forms of the store's methods, the retry and budget internals) from\n// `@cloudbitmaps/core` and `@cloudbitmaps/core/driver-kit`. A name added here is a public name of this package, so\n// add one on purpose: `tests/docs/api-reference-sync.test.ts` fails until the API reference lists it.\n// ---------------------------------------------------------------------------------------------------\nexport {\n // Backends\n MemoryStorage,\n LocalFsStorage,\n CrbmStorageChunkSource,\n // Crypto-shred and the retention policy helpers\n destroySegment,\n eraseNamespace,\n excludingReservedRows,\n readRetentionPolicy,\n MIN_EXPIRES_AT_MS,\n // Encryption\n InProcessKeystore,\n NodeAead,\n aadFor,\n // Errors and their copy-safe predicates\n CloudRoaringError,\n ValidationError,\n WriteConflictError,\n IntegrityError,\n NotFoundError,\n UnsupportedError,\n CapabilityError,\n TransientError,\n KeyUnavailableError,\n BudgetExceededError,\n isCloudRoaringError,\n isWriteConflictError,\n isTransientError,\n isNotFoundError,\n isIntegrityError,\n isValidationError,\n // The `.crbm` reader and its blob source\n CrbmReader,\n BufferReader,\n // Metrics, audit and pricing\n CountingMetricsSink,\n RecordingAuditSink,\n DEFAULT_RETRY_POLICY,\n AWS_US_EAST_1_ONDEMAND,\n ELASTICACHE_REDIS_US_EAST_1_ONDEMAND,\n ONE_REDIS_HA_CLUSTER,\n} from '@cloudbitmaps/core';\nexport type {\n Aead,\n AeadSealed,\n AuditEvent,\n BlobReader,\n BlobSink,\n Budget,\n BudgetOption,\n ChunkRef,\n Clock,\n CodecBitmap,\n CodecInterface,\n ConsistencyErrorEntry,\n ConsistencyIssue,\n ConsistencyReport,\n CostReport,\n CrbmCrypto,\n CrbmReaderOptions,\n CrbmStorageChunkSourceOptions,\n DestroyResult,\n DropResult,\n EraseDeps,\n EstimateInput,\n ExportFailure,\n ExportFormat,\n ExportManifest,\n ExportOptions,\n ExportSink,\n ExportWriter,\n ExportedSegment,\n GenKey,\n GenerationEntry,\n GovernanceMeta,\n IAuditSink,\n IKeystore,\n IMetricsSink,\n IRegistryDriver,\n IStorageDriver,\n IdRange,\n InProcessKeystoreOptions,\n LoadGuard,\n LoadOptions,\n LoadRefusal,\n LoadResult,\n LocalFsStorageOptions,\n MemoryStorageOptions,\n MetricEvent,\n MetricOpName,\n MetricsSnapshot,\n NewRegistryRecord,\n PinnedAt,\n PinnedObject,\n PricingProfile,\n RedisNodeType,\n RedisSizing,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n RegistryStatus,\n RetentionPolicy,\n RetireEntry,\n RetireExpiredOptions,\n RetireExpiredResult,\n RetryPolicy,\n Rng,\n RollbackResult,\n SegmentInfo,\n SegmentRef,\n SegmentSize,\n SegmentSizing,\n SetRetentionResult,\n StorageBackend,\n StorageCaps,\n StorageChunkSource,\n Token,\n Workload,\n WrappedDek,\n} from '@cloudbitmaps/core';\n", "/**\n * A storage driver that charges every **generation open** to a per-op budget, for `eraseSubject`.\n *\n * The budget counts fan-out in units of one backend read. `eraseSubject`'s scan charges one unit per registered\n * segment, but a segment whose current generation lacks the id is searched anyway: every other generation in its\n * bucket is opened, one tail read each, and with the keep-everything default of the `*Into` verbs that is one per\n * generation the segment ever had. Those opens are the work the scan's own count leaves out. They are counted here,\n * at the storage port where they happen, so an open added to the erasure later is charged without anyone\n * remembering to charge it, and no option of the public erasure call had to grow.\n *\n * Two opens are never charged, because the segment's unit already pays for them: the generation the row named when\n * the scan listed it, which every erasure must read to decide membership, and an object this call wrote itself,\n * which it reads back to verify. A refusal here comes from a read, and in an erasure the reads that can be refused\n * come before the deletes.\n */\nimport type { GenKey, IStorageDriver, SegmentRef } from '@cloudbitmaps/core';\n\nexport class OpenChargingStorage implements IStorageDriver {\n private readonly free = new Set<number>();\n\n /**\n * @param inner the driver the erasure would otherwise use\n * @param current the generation the segment's row named when it was listed, or `null` when it named none\n * @param charge called once per charged open; it throws to refuse\n */\n constructor(\n private readonly inner: IStorageDriver,\n current: number | null,\n private readonly charge: () => void,\n ) {\n if (current !== null) this.free.add(current);\n }\n\n capabilities(): ReturnType<IStorageDriver['capabilities']> {\n return this.inner.capabilities();\n }\n\n async putImmutable(\n key: GenKey,\n write: Parameters<IStorageDriver['putImmutable']>[1],\n ): ReturnType<IStorageDriver['putImmutable']> {\n const written = await this.inner.putImmutable(key, write);\n this.free.add(key.generation);\n return written;\n }\n\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n return this.inner.getRange(key, offset, length);\n }\n\n /** One `getTail` is one open: a reader takes the footer and the index from it, and reads chunks with `getRange`. */\n async getTail(key: GenKey, maxBytes: number): ReturnType<IStorageDriver['getTail']> {\n if (!this.free.has(key.generation)) this.charge();\n return this.inner.getTail(key, maxBytes);\n }\n\n delete(key: GenKey): Promise<void> {\n return this.inner.delete(key);\n }\n\n list(ref: SegmentRef): AsyncIterable<GenKey> {\n return this.inner.list(ref);\n }\n}\n", "/**\n * The facade's refusal of the namespace the library keeps for its own rows.\n *\n * `cbm.due.` is where the due index stores its pointers, and every fleet-wide scan skips a row there as\n * bookkeeping, so a segment in it would be invisible to an erasure, a consistency check, an export and a retention\n * sweep. `@cloudbitmaps/core` refuses the prefix in every call that takes a ref or a `namespace` option; this is a\n * copy of that one constant, for the checks the facade makes itself before anything reaches core (`segment()`,\n * `invalidate()` and the scope of the two subject scans, which read the registry directly). A test holds the copy\n * equal to core's, so the two cannot drift.\n *\n * Internal: not exported from the package entry.\n */\nimport { ValidationError } from '@cloudbitmaps/core';\n\nexport const RESERVED_NAMESPACE_PREFIX = 'cbm.due.';\n\n/** Throw `ValidationError` for a namespace in the reserved prefix; `undefined` and every look-alike pass. */\nexport function refuseReservedNamespace(namespace: string | undefined): void {\n if (namespace !== undefined && namespace.startsWith(RESERVED_NAMESPACE_PREFIX)) {\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 * SafeBitmap \u2014 the thin wrapper around the `roaring` (CRoaring) engine that owns the\n * untrusted-bytes boundary.\n *\n * All (de)serialization uses the **portable** format \u2014 the stable, bounds-checked one. The\n * `unsafe_frozen_*` formats are never used (they are explicitly documented as crash/attack\n * vectors). Every deserialize is preceded by a hard size cap and a structural check, because the native\n * portable deserializer bounds its reads and checks nothing else (see `portable/layout.ts`).\n */\n// `roaring` is a CommonJS native addon. A *named* ESM import (`import { RoaringBitmap32 } from 'roaring'`)\n// crashes Node's ESM loader \u2014 its static lexer can't see the CJS module's exports \u2014 so we take the runtime\n// values off the module's default export (Node maps a CJS module's `module.exports` to `default`). This\n// keeps the shipped ESM bundle importable under Node ESM. The instance type is derived from the value so we\n// still get a `RoaringBitmap32` type without a (conflicting) second import.\nimport roaring from 'roaring';\nimport type { CodecBitmap, CodecInterface } from '@cloudbitmaps/core';\nimport { IntegrityError } from '@cloudbitmaps/core';\nimport { checkPortableLayout } from './portable/layout';\n\nconst { RoaringBitmap32, SerializationFormat, DeserializationFormat } = roaring;\ntype RoaringBitmap32 = InstanceType<typeof RoaringBitmap32>;\n\nexport class SafeBitmap implements CodecBitmap {\n private readonly bitmap: RoaringBitmap32;\n\n private constructor(bitmap: RoaringBitmap32) {\n this.bitmap = bitmap;\n }\n\n static empty(): SafeBitmap {\n return new SafeBitmap(new RoaringBitmap32());\n }\n\n static fromValues(values: Iterable<number>): SafeBitmap {\n return new SafeBitmap(new RoaringBitmap32(values));\n }\n\n /**\n * Cap the size, check the structure, then deserialize with the **portable** format.\n * Throws `IntegrityError` if the input exceeds `maxBytes`, is not a well-formed portable bitmap, or fails to\n * decode \u2014 the native addon is never handed unbounded, malformed or unsafe-format input.\n *\n * The structural check is what makes the decoded bitmap's answers mean anything. The native deserializer\n * bounds its reads and checks nothing else, so bytes of the right length and the wrong shape (containers or\n * values out of order, overlapping runs, a cardinality that disagrees with the bits) decode into a bitmap\n * whose `maximum()`, `has()` and `size` are wrong, and some of those shapes crash the process when used.\n */\n static safeDeserialize(bytes: Uint8Array, maxBytes: number): SafeBitmap {\n if (bytes.length > maxBytes) {\n throw new IntegrityError(`serialized bitmap is ${bytes.length}B, exceeds cap ${maxBytes}B`);\n }\n checkPortableLayout(bytes);\n try {\n return new SafeBitmap(RoaringBitmap32.deserialize(bytes, DeserializationFormat.portable));\n } catch (err) {\n throw new IntegrityError(`failed to deserialize bitmap: ${(err as Error).message}`);\n }\n }\n\n serialize(): Uint8Array {\n return this.bitmap.serialize(SerializationFormat.portable);\n }\n\n /**\n * Convert containers to run-encoding where that is smaller. Representation only \u2014 membership is untouched, and\n * the portable format still round-trips through {@link RoaringCodec.safeDeserialize}.\n *\n * Roaring's third container type is a RUN, and no implementation selects it on its own: it takes an explicit\n * `runOptimize()` pass. Nothing here made that call, so run-shaped ids paid array or bitset prices \u2014 measured\n * at **570\u00D7** for a contiguous 1M-id range (128.1 KiB \u2192 0.2 KiB) and **63\u00D7** for a 2,000-run shape\n * (536.5 KiB \u2192 8.5 KiB). Sparse ids come out byte-identical, so this is never a losing trade; roaring keeps\n * whichever encoding is smaller per container.\n *\n * Those two factors are THIS CALL's own before/after on the same ids. They are not the ones the site quotes\n * (543\u00D7 and 63\u00D7) \u2014 those compare the optimized encoding against the best *fixed* representation at its floor,\n * a different baseline that happens to land near 63\u00D7 on the run shape too. `pnpm bench:encoding` prints both\n * columns; don't carry a figure between them without checking which denominator it had.\n *\n * Called only when writing an immutable objects generation \u2014 see {@link CodecBitmap.optimize} for why the read\n * path deliberately does not.\n */\n optimize(): void {\n this.bitmap.runOptimize();\n }\n\n /**\n * Largest value, or `undefined` when empty. O(1) \u2014 roaring reads it off the last container, so the engine's\n * per-chunk range assertion costs one call per chunk rather than a walk per id. The last container holds the\n * largest value only because {@link SafeBitmap.safeDeserialize} refuses bytes whose containers or values are\n * out of order.\n */\n maximum(): number | undefined {\n return this.bitmap.isEmpty ? undefined : this.bitmap.maximum();\n }\n\n add(value: number): void {\n this.bitmap.add(value);\n }\n\n addMany(values: Iterable<number>): void {\n this.bitmap.addMany(values);\n }\n\n remove(value: number): void {\n this.bitmap.remove(value);\n }\n\n removeMany(values: Iterable<number>): void {\n this.bitmap.removeMany(values);\n }\n\n has(value: number): boolean {\n return this.bitmap.has(value);\n }\n\n get size(): number {\n return this.bitmap.size;\n }\n\n get isEmpty(): boolean {\n return this.bitmap.isEmpty;\n }\n\n clone(): SafeBitmap {\n return new SafeBitmap(this.bitmap.clone());\n }\n\n // The binary set ops take the `CodecBitmap` interface type (per the seam), but a single store is\n // single-codec (homogeneity contract), so `other` is always a `SafeBitmap` here \u2014 reach its private\n // `bitmap` (accessible on same-class instances) for the native op.\n /** In-place union: `this = this \u222A other`. */\n orInPlace(other: CodecBitmap): void {\n this.bitmap.orInPlace((other as SafeBitmap).bitmap);\n }\n\n /** In-place difference: `this = this \\ other`. */\n andNotInPlace(other: CodecBitmap): void {\n this.bitmap.andNotInPlace((other as SafeBitmap).bitmap);\n }\n\n /** In-place intersection: `this = this \u2229 other`. */\n andInPlace(other: CodecBitmap): void {\n this.bitmap.andInPlace((other as SafeBitmap).bitmap);\n }\n\n /** Ascending iterator over the set values. */\n [Symbol.iterator](): IterableIterator<number> {\n return this.bitmap[Symbol.iterator]();\n }\n\n toArray(): number[] {\n return this.bitmap.toArray();\n }\n}\n\n/**\n * The roaring {@link CodecInterface} \u2014 the flagship codec, delegating to {@link SafeBitmap}'s statics. This is\n * the default the `CloudRoaring` facade injects into the engine; `core/` itself never hard-references it once a\n * caller supplies a codec.\n */\nexport const roaringCodec: CodecInterface = {\n empty: () => SafeBitmap.empty(),\n fromValues: (values) => SafeBitmap.fromValues(values),\n safeDeserialize: (bytes, maxBytes) => SafeBitmap.safeDeserialize(bytes, maxBytes),\n};\n", "/**\n * The layout of a portable-roaring bitmap: parsed, and checked for the structure every reader of it assumes.\n *\n * WHY THIS EXISTS. `roaring` deserializes the portable format with CRoaring's\n * `roaring_bitmap_portable_deserialize_safe`, and that function makes exactly one promise: it never reads past the\n * buffer. CRoaring's header says the bitmap it returns must then pass `roaring_bitmap_internal_validate` before\n * anything uses it, and `roaring` neither calls that function nor exposes it. Every other invariant of the format\n * is therefore taken on trust from bytes that come off a storage tier, which hard invariant 5 says are hostile\n * until proven otherwise. What `roaring` 2.7.0 does with such bytes when nothing checks them first:\n *\n * - **Containers out of order.** `maximum()` reads the last container, so a chunk payload listing container 1\n * before container 0 passes the engine's 16-bit range check, and a read then yields container 1's values masked\n * into the chunk: ids the segment does not hold, which `has()` denies.\n * - **Values or runs out of order, duplicated or overlapping.** `has()` binary-searches, so it denies values that\n * iteration yields, `size` counts duplicates, and a range read stops early.\n * - **A run past the end of its container.** `maximum()` wraps to a small value, so the range check passes, and\n * iteration yields values from the next container's id space.\n * - **A run container with no runs.** Iterating it, or intersecting or unioning with it, crashes the process.\n * - **A bitset whose header cardinality disagrees with its bits.** `size` answers the header. Where the header\n * says fewer values than the bits hold, `remove()` converts the container into an array sized by the header and\n * writes every bit into it: a heap overflow in the native addon, and then a crash.\n *\n * None of those is caught by a CRC, which proves only that the bytes are the bytes that were written. Anyone who\n * can write the bucket writes those.\n *\n * WHAT IT CHECKS, which is what `roaring_bitmap_internal_validate` checks, stated on the serialized form: container\n * keys strictly ascend; array values strictly ascend; runs ascend, stay inside their container, and neither overlap\n * nor touch (a writer merges touching runs); a run container has at least one run; a bitset's popcount is the\n * cardinality its header states. And two things the native deserializer ignores and the pure-JS reader uses: every\n * offset in the offset header is where its container really starts, and a run container's header cardinality is\n * the number of values its runs cover. Anything a real writer produces passes, because a real writer produces\n * exactly this structure.\n *\n * WHAT IT COSTS. One pass over the bytes the decode is about to copy anyway, once per decode: never per id, and\n * never on a cache hit. Measured on an M3 Pro under Node 24, with the check, the native deserialize and a CRC32C\n * of the same bytes timed in alternating rounds: about 70 ns for a payload of one small container, 0.7 us for a\n * 2 KB array container, and 2.5 to 3.2 us for an 8 KB one of any kind. That is a third to a half of the CRC32C the\n * `.crbm` reader already computes over the stored payload before it gets here.\n *\n * Both decoders run it: `SafeBitmap.safeDeserialize` before the native addon sees a byte, and the pure-JS reader\n * in `decode.ts`, which builds on the layout it returns. One check in one place is what keeps the two decoders\n * from disagreeing about which bytes are a bitmap.\n *\n * @see https://github.com/RoaringBitmap/RoaringFormatSpec\n */\nimport { IntegrityError } from '@cloudbitmaps/core';\n\n/** Cookie for a bitmap with no run containers. Followed by a u32 container count. */\nconst SERIAL_COOKIE_NO_RUNCONTAINER = 12_346;\n/** Cookie (low 16 bits) for a bitmap that may contain run containers; the high 16 bits hold `count - 1`. */\nconst SERIAL_COOKIE = 12_347;\n/**\n * Below this many containers, a run-cookie bitmap omits the offset header and containers must be located by\n * walking their sizes. At or above it the header is present. (A `NO_RUNCONTAINER` bitmap always has it.)\n */\nconst NO_OFFSET_THRESHOLD = 4;\n/** A container holding more than this many values is stored as a flat 8 KiB bitset rather than a u16 array. */\nconst ARRAY_MAX_CARDINALITY = 4_096;\n/** 65,536 bits, flat. */\nconst BITMAP_CONTAINER_BYTES = 8_192;\n/** The largest value a container holds: its low 16 bits. */\nconst MAX_LOW = 0xffff;\n\n/** A container of sorted `u16` values. */\nexport const ARRAY = 0;\n/** A container of 65,536 bits. */\nexport const BITMAP = 1;\n/** A container of `(start, length)` runs. */\nexport const RUN = 2;\nexport type ContainerKind = typeof ARRAY | typeof BITMAP | typeof RUN;\n\nexport interface PortableContainer {\n /** High 16 bits of every value in this container. */\n readonly key: number;\n /** Number of values. Stored as `cardinality - 1` on the wire, normalized here. */\n readonly cardinality: number;\n readonly kind: ContainerKind;\n /** Absolute byte offset of this container's payload within the source buffer; a run container's run count. */\n readonly offset: number;\n}\n\n/**\n * The error for a field that runs past the buffer. Callers test the bound inline and call this only when it\n * fails, so a well-formed bitmap never builds the message: the test runs once per container, and a string built\n * on every pass would cost a bitmap of many small containers more than the check itself does.\n */\nfunction overrun(bytes: Uint8Array, offset: number, length: number, what: string): IntegrityError {\n return new IntegrityError(\n `portable roaring: ${what} needs bytes [${offset}, ${offset + length}) of a ${bytes.byteLength}-byte buffer`,\n );\n}\n\n/**\n * Parse the portable-format bitmap in `bytes`, and check its structure.\n *\n * An empty buffer is the empty bitmap, as it is to the native addon, which returns one without reading a byte.\n *\n * @throws {IntegrityError} if the cookie is unrecognized, any field runs past the buffer, or the structure is not\n * one a writer produces (see the module header for the list).\n */\nexport function parsePortableLayout(bytes: Uint8Array): PortableContainer[] {\n const containers: PortableContainer[] = [];\n walk(bytes, containers);\n return containers;\n}\n\n/**\n * {@link parsePortableLayout}'s check alone, for a caller that hands the bytes to another decoder afterwards and\n * so has no use for the layout: it allocates nothing per container.\n *\n * @throws {IntegrityError} exactly where {@link parsePortableLayout} does.\n */\nexport function checkPortableLayout(bytes: Uint8Array): void {\n walk(bytes, null);\n}\n\n/** Check every container of `bytes`, appending each one's layout to `out` when there is one to append to. */\nfunction walk(bytes: Uint8Array, out: PortableContainer[] | null): void {\n const length = bytes.byteLength;\n if (length === 0) return;\n const view = new DataView(bytes.buffer, bytes.byteOffset, length);\n\n if (length < 4) throw overrun(bytes, 0, 4, 'the cookie');\n const cookie = view.getUint32(0, true);\n let count: number;\n /** Where the run-container flag bits start, or -1 under the cookie that has none. */\n let runFlagsAt = -1;\n let pos: number;\n if (cookie === SERIAL_COOKIE_NO_RUNCONTAINER) {\n if (length < 8) throw overrun(bytes, 4, 4, 'the container count');\n count = view.getUint32(4, true);\n pos = 8;\n } else if ((cookie & 0xffff) === SERIAL_COOKIE) {\n // The count is packed into the cookie's high half as `count - 1`, so it can never be zero here.\n count = (cookie >>> 16) + 1;\n runFlagsAt = 4;\n const flagBytes = (count + 7) >>> 3;\n if (runFlagsAt + flagBytes > length) {\n throw overrun(bytes, runFlagsAt, flagBytes, 'the run-container bitmap');\n }\n pos = runFlagsAt + flagBytes;\n } else {\n throw new IntegrityError(\n `portable roaring: unrecognized cookie 0x${cookie.toString(16)}, not a portable-format bitmap`,\n );\n }\n\n // Descriptive header: (key, cardinality - 1) per container. Then the offset header, when this layout has one.\n const descriptiveAt = pos;\n if (pos + count * 4 > length) throw overrun(bytes, pos, count * 4, 'the descriptive header');\n pos += count * 4;\n let offsetsAt = -1;\n if (runFlagsAt < 0 || count >= NO_OFFSET_THRESHOLD) {\n if (pos + count * 4 > length) throw overrun(bytes, pos, count * 4, 'the offset header');\n offsetsAt = pos;\n pos += count * 4;\n }\n\n let previousKey = -1;\n // Containers lie back to back from here. That is how the native deserializer finds them (it never reads the\n // offset header), so the offsets are checked against it rather than followed.\n for (let i = 0; i < count; i++) {\n const key = view.getUint16(descriptiveAt + i * 4, true);\n if (key <= previousKey) {\n throw new IntegrityError(\n `portable roaring: container keys are not strictly ascending (${previousKey} then ${key} at index ${i})`,\n );\n }\n previousKey = key;\n const cardinality = view.getUint16(descriptiveAt + i * 4 + 2, true) + 1;\n const isRun =\n runFlagsAt >= 0 && ((bytes[runFlagsAt + (i >>> 3)] as number) & (1 << (i & 7))) !== 0;\n const kind: ContainerKind = isRun ? RUN : cardinality > ARRAY_MAX_CARDINALITY ? BITMAP : ARRAY;\n if (offsetsAt >= 0) {\n const stated = view.getUint32(offsetsAt + i * 4, true);\n if (stated !== pos) {\n throw new IntegrityError(\n `portable roaring: the offset header puts container ${i} at byte ${stated}, but it starts at ${pos}`,\n );\n }\n }\n\n let size: number;\n if (kind === ARRAY) {\n size = cardinality * 2;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (array)`);\n checkArray(view, pos, cardinality, i);\n } else if (kind === BITMAP) {\n size = BITMAP_CONTAINER_BYTES;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (bitmap)`);\n const bits = popcount(view, pos);\n if (bits !== cardinality) {\n throw new IntegrityError(\n `portable roaring: container ${i} (bitmap) holds ${bits} values, but its header says ${cardinality}`,\n );\n }\n } else {\n if (pos + 2 > length) throw overrun(bytes, pos, 2, `container ${i} (run count)`);\n const runs = view.getUint16(pos, true);\n size = 2 + runs * 4;\n if (pos + size > length) throw overrun(bytes, pos, size, `container ${i} (run)`);\n const covered = checkRuns(view, pos + 2, runs, i);\n // A header cannot state zero values, so this is also what refuses a run container with no runs, the shape\n // that crashes the native addon when anything iterates it.\n if (covered !== cardinality) {\n throw new IntegrityError(\n `portable roaring: container ${i} (run) covers ${covered} values, but its header says ${cardinality}`,\n );\n }\n }\n out?.push({ key, cardinality, kind, offset: pos });\n pos += size;\n }\n}\n\n/**\n * An array container's values must strictly ascend: `has` binary-searches them and iteration yields them in order.\n *\n * Read two values per `u32` (little-endian, so the first value is the low half): half the loads and half the loop\n * trips of reading them one at a time, which measured about twice as fast.\n */\nfunction checkArray(view: DataView, at: number, cardinality: number, index: number): void {\n let previous = -1;\n let p = at;\n const end = at + cardinality * 2;\n for (; p + 4 <= end; p += 4) {\n const pair = view.getUint32(p, true);\n const first = pair & 0xffff;\n const second = pair >>> 16;\n if (first <= previous || second <= first) throw unordered(index, (p - at) / 2);\n previous = second;\n }\n if (p < end && view.getUint16(p, true) <= previous) throw unordered(index, (p - at) / 2);\n}\n\nfunction unordered(index: number, element: number): IntegrityError {\n return new IntegrityError(\n `portable roaring: container ${index} (array) is not strictly ascending at or after element ${element}`,\n );\n}\n\n/**\n * Runs must ascend, stay inside the container, and leave at least one value between each other: overlapping runs\n * count their shared values twice, and touching ones are two runs a writer would have merged into one. Returns the\n * number of values the runs cover. Each run is one `u32`: its start in the low half, its length in the high.\n */\nfunction checkRuns(view: DataView, at: number, runs: number, index: number): number {\n let covered = 0;\n /** The lowest start the next run may have: one past the value after the previous run's last. */\n let lowest = 0;\n for (let r = 0; r < runs; r++) {\n const run = view.getUint32(at + r * 4, true);\n const start = run & 0xffff;\n const last = start + (run >>> 16);\n if (start < lowest) {\n throw new IntegrityError(\n `portable roaring: container ${index} (run) has run ${r} out of order, overlapping or touching the one before`,\n );\n }\n if (last > MAX_LOW) {\n throw new IntegrityError(\n `portable roaring: container ${index} (run) has run ${r} running past the end of the container`,\n );\n }\n covered += last - start + 1;\n lowest = last + 2;\n }\n return covered;\n}\n\n/** Set bits in a bitset container's 2,048 little-endian `u32` words. */\nfunction popcount(view: DataView, at: number): number {\n let bits = 0;\n for (let p = at, end = at + BITMAP_CONTAINER_BYTES; p < end; p += 4) {\n let w = view.getUint32(p, true);\n w -= (w >>> 1) & 0x5555_5555;\n w = (w & 0x3333_3333) + ((w >>> 2) & 0x3333_3333);\n bits += Math.imul((w + (w >>> 4)) & 0x0f0f_0f0f, 0x0101_0101) >>> 24;\n }\n return bits;\n}\n", "/**\n * The default real-time {@link Clock} \u2014 the production half of the determinism seam.\n *\n * It lives outside `core/`, so `Date.now()`, `setTimeout` and `setImmediate` are allowed here; that separation is\n * the whole point of the seam, and it is lint-enforced on the other side.\n *\n * It sits in its own module rather than in `index.ts` so the facade, the tests and anything else that needs a real\n * clock can import it without importing the whole barrel.\n */\nimport type { Clock } from '@cloudbitmaps/core';\n\n/** Default real-time clock \u2014 lives outside `core/`, so `Date.now()` + timers are allowed here. */\nexport class SystemClock implements Clock {\n now(): number {\n return Date.now();\n }\n\n sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n // A *ref'd* timer, deliberately. Every `sleep` on this clock backs a caller-awaited, bounded retry \u2014 today\n // the transient-retry loop (`withRetry`) that wraps the chunk source. A pending backoff therefore always means unfinished\n // awaited work, so the timer MUST keep the event loop alive until it resolves. An unref'd timer lets a\n // short-lived process \u2014 CLI, Lambda, a bare script \u2014 whose only remaining handle is the backoff timer exit 0\n // mid-retry, silently dropping the awaited operation with neither a result nor a thrown error. When a\n // transient fault repeats (a backend throttling a hot key, say), the backoff timer can be the last handle\n // standing.\n // Retries are bounded (`maxAttempts`/`maxRetries` + `maxDelayMs`), so a ref'd timer can only\n // extend a process by the small remaining backoff budget of work that is genuinely still in flight.\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n\n /**\n * `setImmediate`, and it has to be \u2014 this is the one place where the choice of primitive is the whole feature.\n *\n * A long CPU-bound loop in `core/` (bulk-load is the one that matters) periodically hands the loop back so a\n * co-resident HTTP server keeps answering. Measured on the **synthetic yield-primitive benchmark** \u2014 a\n * 61,035-iteration loop yielding every 1,024, isolating the primitive rather than timing a real load (the\n * end-to-end figures are 519 ms \u2192 24 ms; see `cooperative.ts`, which lists all three experiments):\n *\n * ```text\n * no yield 568 ms wall 568.0 ms worst event-loop gap\n * sleep(0) 555 ms wall 555.2 ms \u2190 a microtask. Yields NOTHING.\n * setImmediate 569 ms wall 13.8 ms \u2190 free, and 41x less starvation\n * setTimeout(1) 625 ms wall 15.0 ms \u2190 +10% wall for no extra relief\n * ```\n *\n * `sleep(0)` resolving on a microtask is correct for its own contract and useless for this: microtasks drain\n * before the loop ever advances a phase, so `await sleep(0)` in a tight loop never lets a single pending I/O\n * callback run. `setImmediate` fires in the check phase *after* pending I/O, which is exactly the ordering a\n * server wants \u2014 inbound requests are serviced before the loop resumes chewing.\n *\n * A timer is not ref'd here (unlike {@link sleep}): a yield expresses \"someone else may go first\", never\n * \"there is outstanding work\" \u2014 and `setImmediate` cannot outlive the turn that scheduled it anyway.\n */\n yieldNow(): Promise<void> {\n return new Promise((resolve) => {\n setImmediate(resolve);\n });\n }\n}\n", "/**\n * The keys `new CloudRoaring(options)` takes: at the top level, and inside each group whose value is an object. The\n * constructor refuses any other key by name, because an option it ignored would do nothing and look as if it had,\n * and the gates that read the docs' samples and the harnesses' option bags hold them to the same table. A test\n * holds the table to the option interfaces, in both directions.\n *\n * NOT part of the public API. It is its own module, rather than an `export` from the barrel, so the constructor\n * and those gates read one copy.\n */\nexport const OPTION_KEYS = {\n top: ['storage', 'cache', 'encryption', 'retry', 'metrics', 'budget', 'seams'],\n cache: ['maxChunks', 'ttlMs', 'genTtlMs', 'readerMax', 'readerMaxBytes'],\n encryption: ['keystore', 'required'],\n retry: ['maxAttempts', 'baseDelayMs', 'maxDelayMs', 'backoffFactor', 'jitter', 'onRetry'],\n budget: ['maxRequests'],\n seams: ['clock', 'rng'],\n} as const satisfies Record<string, readonly string[]>;\n\n/** The groups: the top-level keys whose value, when it is an object, has keys of its own. */\nexport type OptionGroup = Exclude<keyof typeof OPTION_KEYS, 'top'>;\n"],
5
+ "mappings": "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",
6
6
  "names": ["ValidationError", "IntegrityError", "IntegrityError", "CrbmStorageChunkSource", "excludingReservedRows", "MIN_EXPIRES_AT_MS", "ValidationError", "WriteConflictError", "IntegrityError", "UnsupportedError", "DEFAULT_RETRY_POLICY", "options", "exclude"]
7
7
  }