@cloudbitmaps/core 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/chunk-7GT632UF.js +641 -0
- package/dist/chunk-7GT632UF.js.map +7 -0
- package/dist/chunk-CGILDXGP.js +73 -0
- package/dist/chunk-CGILDXGP.js.map +7 -0
- package/dist/chunk-GKHERVVQ.js +121 -0
- package/dist/chunk-GKHERVVQ.js.map +7 -0
- package/dist/{chunk-OSU7W2Y3.js → chunk-MVUD4R72.js} +200 -756
- package/dist/chunk-MVUD4R72.js.map +7 -0
- package/dist/core/audit.d.ts +53 -15
- package/dist/core/bit-route.d.ts +2 -0
- package/dist/core/blob.d.ts +4 -0
- package/dist/core/budget.d.ts +8 -3
- package/dist/core/check.d.ts +49 -0
- package/dist/core/combine-many.d.ts +11 -0
- package/dist/core/consistency.d.ts +11 -2
- package/dist/core/cooperative.d.ts +7 -0
- package/dist/core/crbm-storage-source.d.ts +7 -4
- package/dist/core/crypto.d.ts +5 -0
- package/dist/core/discover.d.ts +5 -3
- package/dist/core/engine.d.ts +4 -4
- package/dist/core/erase-id.d.ts +35 -12
- package/dist/core/erasure.d.ts +61 -27
- package/dist/core/errors.d.ts +30 -0
- package/dist/core/leases.d.ts +2 -0
- package/dist/core/load-input.d.ts +48 -0
- package/dist/core/load.d.ts +23 -2
- package/dist/core/metrics.d.ts +21 -0
- package/dist/core/pinned-storage-source.d.ts +27 -8
- package/dist/core/pointer-id.d.ts +9 -0
- package/dist/core/ports.d.ts +100 -7
- package/dist/core/preflight.d.ts +80 -0
- package/dist/core/retention-sweep.d.ts +60 -15
- package/dist/core/retention.d.ts +17 -6
- package/dist/core/retry.d.ts +1 -2
- package/dist/core/rollback.d.ts +22 -12
- package/dist/core/validate.d.ts +33 -2
- package/dist/driver-kit.d.ts +3 -3
- package/dist/driver-kit.js +61 -20
- package/dist/driver-kit.js.map +2 -2
- package/dist/drivers/_shared/object-registry.d.ts +24 -1
- package/dist/drivers/_shared/options.d.ts +15 -7
- package/dist/drivers/backends.d.ts +17 -2
- package/dist/drivers/crypto.d.ts +17 -2
- package/dist/export/index.d.ts +16 -2
- package/dist/index.d.ts +10 -9
- package/dist/index.js +1743 -1701
- package/dist/index.js.map +4 -4
- package/dist/node.d.ts +14 -0
- package/dist/node.js +1064 -0
- package/dist/node.js.map +7 -0
- package/package.json +11 -2
- package/dist/chunk-OSU7W2Y3.js.map +0 -7
package/dist/node.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/drivers/backends.ts", "../src/drivers/memory.ts", "../src/drivers/localfs/storage.ts", "../src/drivers/localfs/paths.ts", "../src/drivers/localfs/exact-case.ts", "../src/drivers/localfs/fs-util.ts", "../src/drivers/localfs/registry.ts", "../src/drivers/crypto.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The two SDK-free backends, each as one object: `MemoryStorage` and `LocalFsStorage`.\n *\n * These ship from `@cloudbitmaps/core/node`, not the main entry: each reaches a Node builtin (`LocalFsStorage` the\n * filesystem, `MemoryStorage` `node:crypto` for the SHA-256 a write reports). Neither needs a cloud SDK. Their\n * cloud siblings (`S3Storage`, `GcsStorage`, `AzureBlobStorage`) ship in `@cloudbitmaps/s3`, `/gcs` and\n * `/azure-blob` for the opposite reason: each carries an SDK nobody should install for a service they do not use.\n *\n * Each one exists to state a location **once**. See {@link StorageBackend} for why that is worth a class.\n */\nimport { join } from 'node:path';\nimport { brandAsBackend, STORAGE_BACKEND } from '@/core/ports';\nimport type {\n IRegistryDriver,\n IStorageDriver,\n LifecycleVerdict,\n StorageBackend,\n} from '@/core/ports';\nimport { MemoryRegistryDriver, MemoryStorageDriver } from './memory';\nimport { LocalFsStorageDriver } from './localfs/storage';\nimport { LocalFsRegistryDriver } from './localfs/registry';\nimport { checkNow, refuseUnknownOptions } from './_shared/options';\nimport { ValidationError } from '@/core/errors';\n\nconst CLOCK_OPTION_KEYS = ['now'] as const;\n\n/** Options of {@link MemoryStorage}: only `now`, the clock for the registry's timestamps. */\nexport interface MemoryStorageOptions {\n /** Injected clock for the registry's `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\n/**\n * An in-process backend \u2014 nothing to install, nothing to clean up, and it disappears with the process.\n *\n * This is the one to reach for in tests and in the first five minutes. It is **not** a cache in front of\n * anything: it is the whole store, held in RAM, so a restart is a data loss.\n */\nexport class MemoryStorage implements StorageBackend {\n /** Cross-bundle brand, stamped non-enumerably in the constructor so a spread cannot carry it. */\n declare readonly [STORAGE_BACKEND]: true;\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n\n /**\n * Builds an empty in-process backend. `options.now` is the clock for the registry's timestamps, `Date.now` by\n * default; any other option throws `ValidationError`.\n */\n constructor(options: MemoryStorageOptions = {}) {\n refuseUnknownOptions('MemoryStorage', options, CLOCK_OPTION_KEYS);\n checkNow('MemoryStorage', options.now);\n this.storage = new MemoryStorageDriver();\n this.registry = new MemoryRegistryDriver(options.now === undefined ? {} : { now: options.now });\n brandAsBackend(this);\n }\n\n /** Nothing to check: process memory has no lifecycle rules. */\n checkLifecycle(): Promise<LifecycleVerdict> {\n return Promise.resolve({\n status: 'ok',\n detail: 'MemoryStorage keeps its objects in process memory, which has no lifecycle rules',\n });\n }\n}\n\n/** Options of {@link LocalFsStorage}: only `now`, the clock for the registry's timestamps. */\nexport interface LocalFsStorageOptions {\n /** Injected clock for the registry's `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\n/**\n * A local-filesystem backend rooted at one directory: generations under `<root>/storage`, pointers under\n * `<root>/registry`.\n *\n * The layout is stated here rather than by the caller, which is the point \u2014 two paths a caller wrote out\n * separately could name different roots, and nothing would stop them. It is also the layout\n * the `export-segments` CLI expects, so a store built this way can be ejected without being told where to look.\n *\n * A root is for **one process**. Every instance in a process that names the same root shares one lock per\n * registry row, however the root is spelled (relative path, symlink), so they cannot both advance a row from\n * one token. Two processes on one root are **not** fenced from each other.\n */\nexport class LocalFsStorage implements StorageBackend {\n /** Cross-bundle brand, stamped non-enumerably in the constructor so a spread cannot carry it. */\n declare readonly [STORAGE_BACKEND]: true;\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n\n /**\n * Builds a backend rooted at `root`, a non-empty directory path. `options.now` is the clock for the registry's\n * timestamps, `Date.now` by default; any other option throws `ValidationError`.\n */\n constructor(\n /** The directory the backend is rooted at. */\n readonly root: string,\n options: LocalFsStorageOptions = {},\n ) {\n if (typeof root !== 'string' || root.trim().length === 0) {\n throw new ValidationError(\n `LocalFsStorage needs a root directory: a non-empty string, got ${root === '' ? 'an empty string' : typeof root}`,\n );\n }\n refuseUnknownOptions('LocalFsStorage', options, CLOCK_OPTION_KEYS);\n checkNow('LocalFsStorage', options.now);\n this.storage = new LocalFsStorageDriver(join(root, 'storage'), { privateRoot: root });\n this.registry = new LocalFsRegistryDriver(\n join(root, 'registry'),\n options.now === undefined ? { privateRoot: root } : { now: options.now, privateRoot: root },\n );\n brandAsBackend(this);\n }\n\n /** Nothing to check: a local directory has no lifecycle rules. */\n checkLifecycle(): Promise<LifecycleVerdict> {\n return Promise.resolve({\n status: 'ok',\n detail: 'LocalFsStorage keeps its objects in a local directory, which has no lifecycle rules',\n });\n }\n}\n", "/**\n * In-memory drivers \u2014 the reference backing for tests and quick experiments.\n * They store **serialized bytes + an OCC token** (not live objects), so the engine's\n * safe-deserialize / size-cap paths and the registry's OCC paths are genuinely exercised.\n *\n * Not in `core/` (this is a driver), so it may hold concrete state.\n */\nimport { checkDeleteOptions } from './_shared/options';\nimport { checkRegistryWriteOptions } from './_shared/options';\nimport { createHash } from 'node:crypto';\nimport { BufferSink, checkTailLength } from '../core/blob';\nimport type { BlobSink } from '../core/blob';\nimport type { Entropy } from '../core/determinism';\nimport { NotFoundError, ValidationError, WriteConflictError } from '../core/errors';\nimport { segmentKey } from '../core/keys';\nimport { validateSegmentRef } from '../core/validate';\nimport type {\n StorageCaps,\n StorageDeleteOptions,\n TailRead,\n GenKey,\n IStorageDriver,\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n RegistryWriteOptions,\n SegmentRef,\n Token,\n} from '../core/ports';\nimport { requireInteger } from '../core/check';\nimport {\n applyRegistryPatch,\n drawIncarnation,\n drawWrite,\n incarnationOf,\n recordFromNew,\n validateNewRegistryRecord,\n validateRegistryPatch,\n} from './_shared/registry';\nimport { entropyIsAvailable, webCryptoEntropy } from './_shared/entropy';\n\ninterface MemoryRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now` (drivers may use ambient time). */\n readonly now?: () => number;\n /** Draws every token's random parts; defaults to Web Crypto. Inject one only to make a test replayable. */\n readonly entropy?: Entropy;\n}\n\n/**\n * In-memory {@link IRegistryDriver} \u2014 one record per segment under OCC. The token has the form every shipped driver\n * gives it, an incarnation id drawn at create, a counter and a per-write random part, but its counter is global to the\n * driver: monotonic and never reused, so a record recreated after `delete` never meets an earlier token, by\n * construction, even though `delete` removes the row physically.\n */\nexport class MemoryRegistryDriver implements IRegistryDriver {\n private readonly rows = new Map<string, RegistryRecord>();\n private readonly now: () => number;\n private readonly entropy: Entropy;\n private seq = 0;\n\n constructor(options: MemoryRegistryDriverOptions = {}) {\n this.now = options.now ?? (() => Date.now());\n this.entropy = options.entropy ?? webCryptoEntropy;\n }\n\n private nextToken(incarnation: string): Token {\n this.seq += 1;\n return `${incarnation}.${this.seq}.${drawWrite(this.entropy)}`;\n }\n\n /** `conditionalDelete`: a delete checks the token and removes the row in one step, with no await between. */\n capabilities(): RegCaps {\n return entropyIsAvailable(this.entropy)\n ? { strongRead: true, conditionalDelete: true }\n : { strongRead: true, canWrite: false, conditionalDelete: true };\n }\n\n /** Every write reports its token to `onToken` before it is applied. */\n get reportsWriteTokens(): true {\n return true;\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n validateSegmentRef(ref);\n const row = this.rows.get(segmentKey(ref));\n return row ? structuredClone(row) : null; // clone out: callers can't mutate stored (nested) state\n }\n\n async create(\n ref: SegmentRef,\n record: NewRegistryRecord,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }> {\n checkRegistryWriteOptions(options);\n validateSegmentRef(ref);\n const checked = validateNewRegistryRecord(record);\n const key = segmentKey(ref);\n if (this.rows.has(key)) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n const token = this.nextToken(drawIncarnation(this.entropy));\n options?.onToken?.(token);\n // clone in: the caller's (nested) retention/residency can't alias stored state (value semantics, parity\n // with the serialize-based persistent drivers).\n this.rows.set(key, structuredClone(recordFromNew(ref, checked, this.now(), token)));\n return { token };\n }\n\n /**\n * A caller's `held` row (see `RegistryWriteOptions`) has no read to spare here: the token is compared with the stored row in the same step\n * as the write, in memory, so a stale one fails exactly as a lost race does.\n */\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }> {\n checkRegistryWriteOptions(options);\n validateSegmentRef(ref);\n const checked = validateRegistryPatch(patch);\n const key = segmentKey(ref);\n const existing = this.rows.get(key);\n if (!existing || existing.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n // Every row here was created by this driver, so its token carries an incarnation, which every write keeps.\n const token = this.nextToken(incarnationOf(existing.token)!);\n options?.onToken?.(token);\n this.rows.set(key, structuredClone(applyRegistryPatch(existing, checked, this.now(), token)));\n return { token };\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n // A namespace that is given is checked as every other name is: `''` names none, and reads as an error, not as empty.\n if (namespace !== undefined) validateSegmentRef({ segment: 'x', namespace });\n // The rows as they stand now, as the generation listing takes its keys: a row created or deleted during the\n // listing does not change what it yields.\n for (const row of [...this.rows.values()]) {\n if (namespace === undefined || row.namespace === namespace) yield structuredClone(row);\n }\n }\n\n async delete(ref: SegmentRef, expected?: Token): Promise<void> {\n validateSegmentRef(ref);\n const key = segmentKey(ref);\n if (expected !== undefined && this.rows.get(key)?.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n this.rows.delete(key); // idempotent; token uniqueness is global so a recreate is ABA-safe\n }\n}\n\n/**\n * In-memory {@link IStorageDriver} \u2014 write-once immutable generation objects as opaque bytes. A \"dumb byte\n * mover\" (understands neither roaring nor `.crbm`), so it's a faithful storage backend for tests and a zero-setup\n * local storage tier. Mirrors the LocalFs/S3 contract (write-once, range/tail reads).\n *\n * Every object stored gets a version from a counter the driver never reuses, so two objects stored one after the other\n * under one key never share one, whatever their bytes. A delete given `ifVersion` compares it with the stored object's\n * and removes it in the same step, with no await between them: `conditionalDelete` is `true`.\n */\nexport class MemoryStorageDriver implements IStorageDriver {\n private readonly objects = new Map<\n string,\n { readonly body: Uint8Array; readonly version: string }\n >();\n private stored = 0;\n\n capabilities(): StorageCaps {\n return {\n rangeRead: true,\n maxObjectBytes: Number.MAX_SAFE_INTEGER,\n conditionalPut: true,\n conditionalDelete: true,\n };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const k = genObjectKey(key); // validates ref + generation\n const sink = new BufferSink();\n await write(sink);\n const body = sink.bytes();\n if (this.objects.has(k)) {\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n this.stored += 1;\n this.objects.set(k, { body, version: String(this.stored) });\n return { size: body.length, sha256: createHash('sha256').update(body).digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n requireInteger(offset, { min: 0, what: 'range offset' });\n requireInteger(length, { min: 0, what: 'range length' });\n const { body } = this.require(key);\n if (offset + length > body.length) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${body.length}B`,\n );\n }\n return body.slice(offset, offset + length);\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<TailRead> {\n checkTailLength(maxBytes);\n const { body, version } = this.require(key);\n const take = Math.min(Math.max(maxBytes, 0), body.length);\n return { bytes: body.slice(body.length - take), size: body.length, version };\n }\n\n async delete(key: GenKey, options?: StorageDeleteOptions): Promise<void> {\n const ifVersion = checkDeleteOptions(options);\n const k = genObjectKey(key);\n const stored = this.objects.get(k);\n // The check and the removal in one step: nothing can store another object under the key between them.\n if (ifVersion !== undefined && stored !== undefined && stored.version !== ifVersion) {\n throw new WriteConflictError(\n `generation ${key.segment}.${key.generation} is another object than the version given; not deleted`,\n );\n }\n this.objects.delete(k); // idempotent\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n validateSegmentRef(ref);\n const prefix = `${segmentKey(ref)} `;\n // The keys as they stand now: an object written during the listing is not yielded, and one deleted during it\n // still is, as the local-files driver's directory read and a single page of an S3 or Azure listing answer.\n for (const k of [...this.objects.keys()]) {\n if (k.startsWith(prefix)) {\n yield {\n namespace: ref.namespace,\n segment: ref.segment,\n generation: Number(k.slice(prefix.length)),\n };\n }\n }\n }\n\n private require(key: GenKey): { readonly body: Uint8Array; readonly version: string } {\n const stored = this.objects.get(genObjectKey(key));\n if (stored === undefined) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n return stored;\n }\n}\n\n/** Collision-proof object key for a generation: `<segmentKey> <generation>` (the name parts are encoded, so a space cannot appear inside one). */\nfunction genObjectKey(key: GenKey): string {\n validateSegmentRef(key);\n requireInteger(key.generation, { min: 0, what: 'generation' });\n return `${segmentKey(key)} ${key.generation}`;\n}\n", "/**\n * `LocalFsStorageDriver` \u2014 a zero-cloud {@link IStorageDriver} backed by the local filesystem.\n *\n * Generations are write-once immutable files. A new object is streamed to a temp file (with its content\n * hashed in-flight), `fsync`-ed, then published with an atomic `link` that fails if the destination\n * already exists \u2014 so a generation can never be silently overwritten (hard invariant 2), and a crash\n * leaves only an orphan temp file, never a torn object. Drivers do filesystem I/O and may use `node:crypto`; only `core/`\n * is bound by the determinism lint.\n *\n * **It has no conditional delete (`conditionalDelete: false`), and `delete` ignores `ifVersion`.** A filesystem offers\n * no unlink conditioned on which file is under the path: a check by `stat` and then an `unlink` is two steps, and another\n * writer can replace the file between them. Nor does `stat` name a file across a delete and a re-create: inode numbers\n * are reused once a file is unlinked, and timestamps are coarser than two writes in a row, so a version built from them\n * could match a file put under the path since. A lock in this process would close the gap between the two steps, but\n * there would still be no identity to compare, so the driver does not claim the capability. `getTail` reports no version.\n */\nimport { checkDeleteOptions } from '../_shared/options';\nimport { constants as FS } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { link, open, readdir, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport {\n IntegrityError,\n NotFoundError,\n TransientError,\n ValidationError,\n WriteConflictError,\n} from '@/core/errors';\nimport { checkTailLength, type BlobSink } from '@/core/blob';\nimport type {\n StorageCaps,\n GenKey,\n IStorageDriver,\n SegmentRef,\n StorageDeleteOptions,\n TailRead,\n} from '@/core/ports';\nimport { requireInteger } from '@/core/check';\nimport { assertStorageNamesFit, storageObjectPath, parseGeneration, segmentsDir } from './paths';\nimport { ExactCase } from './exact-case';\nimport {\n FILE_MODE,\n O_NOFOLLOW,\n fsyncDir,\n makeDirs,\n sweepOrphanTemps,\n tempPathFor,\n isAbsent,\n isCode,\n mapFsError,\n writeAll,\n} from './fs-util';\n\n/** Read exactly `length` bytes at `offset`, or throw: a short read is never returned zero-padded as real bytes. */\nasync function readWhole(\n handle: Awaited<ReturnType<typeof open>>,\n key: GenKey,\n length: number,\n offset: number,\n): Promise<Uint8Array> {\n const buf = new Uint8Array(length);\n let filled = 0;\n while (filled < length) {\n const { bytesRead } = await handle.read(buf, filled, length - filled, offset + filled);\n if (bytesRead === 0) {\n throw new IntegrityError(\n `short read of ${key.segment}.${key.generation}: wanted ${length}B at ${offset}, got ${filled}B`,\n );\n }\n filled += bytesRead;\n }\n return buf;\n}\n\nexport class LocalFsStorageDriver implements IStorageDriver {\n private readonly exactCase: ExactCase;\n\n /**\n * `options.privateRoot` is the directory this one lives under, from which down directories are created private; it\n * defaults to `root`.\n */\n constructor(\n private readonly root: string,\n private readonly options: { readonly privateRoot?: string } = {},\n ) {\n this.exactCase = new ExactCase(root);\n }\n\n capabilities(): StorageCaps {\n return {\n rangeRead: true,\n maxObjectBytes: Number.MAX_SAFE_INTEGER,\n conditionalPut: false,\n conditionalDelete: false,\n };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const finalPath = storageObjectPath(this.root, key);\n assertStorageNamesFit(key);\n await this.exactCase.refuseVariant(finalPath);\n await makeDirs(dirname(finalPath), this.options.privateRoot ?? this.root);\n void sweepOrphanTemps(dirname(finalPath));\n\n const tmpPath = tempPathFor(finalPath);\n // 'wx' = O_CREAT|O_EXCL|O_WRONLY; add O_NOFOLLOW so a pre-planted symlink can't redirect the write.\n const handle = await open(\n tmpPath,\n FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW,\n FILE_MODE,\n );\n const hash = createHash('sha256');\n let size = 0;\n const sink: BlobSink = {\n async write(bytes) {\n await writeAll(handle, bytes);\n hash.update(bytes);\n size += bytes.length;\n },\n };\n\n try {\n await write(sink);\n await handle.sync();\n } catch (err) {\n await handle.close().catch(() => {});\n await unlink(tmpPath).catch(() => {});\n throw mapFsError(err);\n }\n await handle.close();\n\n // Atomic write-once publish: link fails with EEXIST if the generation already exists.\n try {\n await link(tmpPath, finalPath);\n } catch (err) {\n await unlink(tmpPath).catch(() => {});\n if (isCode(err, 'ENOENT')) {\n // The temp file is gone: a sweep or an operator removed it while the write was open. Nothing was published.\n throw new TransientError(\n `the temporary file of ${key.segment}.${key.generation} was removed mid-write`,\n {\n cause: err,\n },\n );\n }\n if (isCode(err, 'EEXIST')) {\n // A generation is write-once; a collision is a concurrency/state condition, not bad input.\n // Identify it by the logical key only \u2014 never leak the absolute filesystem path.\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n await unlink(tmpPath).catch(() => {});\n await fsyncDir(dirname(finalPath));\n return { size, sha256: hash.digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n requireInteger(offset, { min: 0, what: 'range offset' });\n requireInteger(length, { min: 0, what: 'range length' });\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n if (offset + length > size) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${size}B`,\n );\n }\n return await readWhole(handle, key, length, offset);\n } finally {\n await handle.close();\n }\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<TailRead> {\n checkTailLength(maxBytes);\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n const take = Math.min(Math.max(maxBytes, 0), size);\n return { bytes: await readWhole(handle, key, take, size - take), size };\n } finally {\n await handle.close();\n }\n }\n\n /**\n * Idempotent. Ignores `options.ifVersion`, as `conditionalDelete: false` says: see the note on the class for why it\n * cannot apply one. The parameter is declared so that a wrapper of this driver can hand the port's options on.\n */\n async delete(key: GenKey, options?: StorageDeleteOptions): Promise<void> {\n checkDeleteOptions(options);\n // Idempotent: deleting an absent generation is a no-op (GC may race / retry).\n const path = storageObjectPath(this.root, key);\n if (await this.exactCase.differs(path)) return; // another case's object is not this one\n await unlink(path).catch((err) => {\n if (!isAbsent(err)) throw mapFsError(err);\n });\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const dir = segmentsDir(this.root, ref);\n if (await this.exactCase.differs(dir)) return; // another case's directory is not this one\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isAbsent(err)) return; // no generations yet\n throw mapFsError(err);\n }\n for (const name of names) {\n const generation = parseGeneration(ref.segment, name);\n if (generation !== null) {\n yield { namespace: ref.namespace, segment: ref.segment, generation };\n }\n }\n }\n\n private async openRead(key: GenKey): Promise<Awaited<ReturnType<typeof open>>> {\n const path = storageObjectPath(this.root, key);\n // Another case's object is not this one: absent, as if nothing were stored under this name.\n if (await this.exactCase.differs(path)) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n try {\n return await open(path, FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isAbsent(err)) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n // A symlink at the object path is rejected (ELOOP) \u2014 treat as not-found, don't follow it.\n if (isCode(err, 'ELOOP')) {\n throw new NotFoundError(\n `generation path is a symlink, refusing: ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n }\n}\n", "/**\n * Logical-ref \u2192 filesystem-path mapping for the LocalFs drivers.\n *\n * Names are re-validated here at the driver boundary \u2014 defense in depth, because a driver can be\n * constructed and driven directly rather than through the engine that would otherwise have validated for\n * it, and a path built from an unvalidated name is a traversal or injection. The default\n * (absent) namespace maps to `_default`, which cannot collide with a real namespace because a\n * caller's `_default` encodes to `%5Fdefault` while this sentinel is emitted literally.\n */\nimport { join } from 'node:path';\nimport { requireInteger } from '@/core/check';\nimport { ValidationError } from '@/core/errors';\nimport { validateSegmentRef } from '@/core/validate';\nimport type { GenKey, SegmentRef } from '@/core/ports';\nimport {\n DEFAULT_NAMESPACE,\n decodeNameFromPath,\n encodeNameForPath,\n namespacePathPart,\n} from '../_shared/keys';\n\n/** The longest file or directory name the common filesystems accept, in bytes. */\nconst MAX_COMPONENT_BYTES = 255;\n/** What a temp file adds to its final name: `.`, a 36-character uuid and `.tmp`. */\nconst TEMP_SUFFIX_BYTES = 1 + 36 + 4;\n\nfunction assertFits(component: string, extraBytes: number): void {\n // Encoded names are ASCII, so a character is a byte.\n if (component.length + extraBytes > MAX_COMPONENT_BYTES) {\n throw new ValidationError(\n `a name is too long for a file name on this backend: the namespace, or the segment with its generation and ` +\n `the temp file's suffix, must fit in ${MAX_COMPONENT_BYTES} bytes once encoded`,\n );\n }\n}\n\n/**\n * Refuse, before anything is written, a generation whose namespace directory or temp file name (the object's name and\n * the temp suffix) would be longer than a filesystem allows. A name inside the library's own cap can still be.\n */\nexport function assertStorageNamesFit(key: GenKey): void {\n validateSegmentRef(key);\n assertFits(namespacePathPart(key.namespace), 0);\n assertFits(storageObjectFilename(key.segment, key.generation), TEMP_SUFFIX_BYTES);\n}\n\n/** The same refusal for a registry row: the namespace directory, and the row file with the temp suffix. */\nexport function assertRegistryNamesFit(ref: SegmentRef): void {\n validateSegmentRef(ref);\n assertFits(namespacePathPart(ref.namespace), 0);\n assertFits(`${encodeNameForPath(ref.segment)}${REGISTRY_SUFFIX}`, TEMP_SUFFIX_BYTES);\n}\n\n/** Directory holding all of a namespace's segment objects. */\nexport function segmentsDir(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(root, namespacePathPart(ref.namespace), 'segments');\n}\n\n/** Absolute path of one `.crbm` generation object. */\nexport function storageObjectPath(root: string, key: GenKey): string {\n validateSegmentRef(key);\n requireInteger(key.generation, { min: 0, what: 'generation' });\n return join(\n segmentsDir(root, { segment: key.segment, namespace: key.namespace }),\n storageObjectFilename(key.segment, key.generation),\n );\n}\n\n/** Filename pattern for a segment's generations: `<segment>.<gen>.crbm`. */\nexport function storageObjectFilename(segment: string, generation: number): string {\n return `${encodeNameForPath(segment)}.${generation}.crbm`;\n}\n\n/** Parse a generation number out of a `<segment>.<gen>.crbm` filename, or `null` if it doesn't match. */\nexport function parseGeneration(segment: string, filename: string): number | null {\n const prefix = `${encodeNameForPath(segment)}.`;\n const suffix = '.crbm';\n if (!filename.startsWith(prefix) || !filename.endsWith(suffix)) return null;\n const middle = filename.slice(prefix.length, filename.length - suffix.length);\n // Canonical decimal only: no leading zeros (so `s.07.crbm` can't alias `s.7.crbm`), and within\n // safe-integer range. The writer only ever emits the canonical form.\n if (!/^(0|[1-9]\\d*)$/.test(middle)) return null;\n const gen = Number(middle);\n return Number.isSafeInteger(gen) ? gen : null;\n}\n\nconst REGISTRY_SUFFIX = '.reg';\n\n/** Directory holding a namespace's registry rows (one file per segment). */\nexport function registryDir(root: string, namespace: string | undefined): string {\n // Validated like every sibling builder here. It is the caller-facing entry for a namespace-scoped\n // `list()`, so without this a namespace of `../..` reaches `readdir` outside the storage root \u2014 no content\n // escapes (iteration aborts before yielding) but it answers \"does this directory exist?\", and the whole\n // point of re-validating at the driver boundary is that a driver driven directly must be safe on its own.\n if (namespace !== undefined) validateSegmentRef({ segment: 'x', namespace });\n return join(root, namespacePathPart(namespace), 'registry');\n}\n\n/** Absolute path of one segment's registry row file: `<ns>/registry/<segment>.reg`. */\nexport function registryRowPath(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(\n registryDir(root, ref.namespace),\n `${encodeNameForPath(ref.segment)}${REGISTRY_SUFFIX}`,\n );\n}\n\n/**\n * Parse a segment name out of a `<segment>.reg` filename, or `null` if it doesn't match \u2014 including any\n * file whose stem isn't a valid segment name. A strict parser means a stray or planted `.reg` file makes\n * `list()` *skip* it, never abort the whole enumeration on a boundary throw.\n */\nexport function parseRegistryRow(filename: string): string | null {\n if (!filename.endsWith(REGISTRY_SUFFIX)) return null;\n const stem = filename.slice(0, filename.length - REGISTRY_SUFFIX.length);\n const segment = decodeNameFromPath(stem);\n // The encoding must ROUND-TRIP, not merely decode. POSIX will happily hold a literal `dedup:foo.reg`\n // alongside the driver's own `dedup%3Afoo.reg`; both decode to `dedup:foo`, and reporting that name twice\n // would hand `list()` a segment whose row path resolves to only one of them. The driver never writes the\n // literal form, so anything that does not re-encode to exactly this filename was not written by us.\n if (encodeNameForPath(segment) !== stem) return null;\n try {\n validateSegmentRef({ segment });\n } catch {\n return null;\n }\n return segment;\n}\n\n/**\n * Parse a namespace out of a directory name under the storage root, or `null` if it was not written by us.\n *\n * The inverse of the `namespacePathPart(ns)` that {@link segmentsDir} and {@link registryDir}\n * write. A fleet-wide scan enumerates these directories, so getting it wrong does not fail one segment \u2014 it\n * aborts the whole enumeration, taking the consistency check, the retention sweep and subject erasure with it.\n *\n * Like {@link parseRegistryRow} this requires the encoding to **round-trip**, so a planted literal `tenant:acme`\n * directory sitting next to the driver's own `tenant%3Aacme` is skipped rather than reported as a namespace\n * whose rows then resolve to the other directory. `_default` maps back to \"no namespace\".\n */\nexport function parseNamespaceDir(entry: string): { namespace: string | undefined } | null {\n if (entry === DEFAULT_NAMESPACE) return { namespace: undefined };\n const namespace = decodeNameFromPath(entry);\n if (encodeNameForPath(namespace) !== entry) return null;\n try {\n validateSegmentRef({ segment: 'x', namespace });\n } catch {\n return null;\n }\n return { namespace };\n}\n", "/**\n * Exact-case path resolution for the LocalFs drivers.\n *\n * A name keeps its case in a path (`TenantA` and `tenanta` are two names), but a case-insensitive filesystem, the\n * macOS and Windows default, opens one file for both. The drivers therefore resolve the name actually on disk and\n * compare it with the one asked for: a path whose real name differs only by case is not the object asked for, so a\n * read finds nothing and a write is refused. No layout changes, and a case-sensitive filesystem pays nothing: it is\n * detected once, and the check is skipped from then on.\n */\nimport { readdir, realpath, stat } from 'node:fs/promises';\nimport { dirname, join, parse, relative, resolve, sep } from 'node:path';\nimport { ValidationError } from '@/core/errors';\nimport { isAbsent } from './fs-util';\n\n/**\n * The index of the first component of `actual` (the path as it is on disk, relative to the root) that equals the same\n * component of `expected` ignoring case but not exactly, or `-1` when there is none. A component that is a different\n * name altogether, or a path that is longer or shorter, is not a case difference.\n */\nexport function firstCaseDifference(\n expected: readonly string[],\n actual: readonly string[],\n): number {\n const shared = Math.min(expected.length, actual.length);\n for (let i = 0; i < shared; i++) {\n const want = expected[i]!;\n const have = actual[i]!;\n if (want !== have) return want.toLowerCase() === have.toLowerCase() ? i : -1;\n }\n return -1;\n}\n\nconst swapCase = (s: string): string =>\n [...s].map((c) => (c === c.toLowerCase() ? c.toUpperCase() : c.toLowerCase())).join('');\n\nconst components = (path: string): string[] => path.split(sep).filter((c) => c !== '');\n\n/** What a path-resolving call needs of the filesystem: the error to refuse a write with. */\nfunction caseVariantError(): ValidationError {\n return new ValidationError(\n 'names differ only by case on a case-insensitive filesystem: a name that differs only by case from one already ' +\n 'stored is the same file here, so it is refused rather than written over',\n );\n}\n\nexport class ExactCase {\n /** `undefined` until the root holds an entry to try; then fixed, as a filesystem does not change its mind. */\n private insensitive: boolean | undefined;\n\n constructor(private readonly root: string) {}\n\n /**\n * Whether the root's filesystem folds case, learned from an entry already in the root: the entry's name with its\n * case swapped is the same file or it is not. An empty or absent root holds nothing to alias, so it is not\n * insensitive yet, and is looked at again on the next call.\n */\n private async foldsCase(): Promise<boolean> {\n if (this.insensitive !== undefined) return this.insensitive;\n let names: string[];\n try {\n names = await readdir(this.root);\n } catch (err) {\n if (isAbsent(err)) return this.foldsAtAncestor();\n throw err;\n }\n for (const name of names) {\n const swapped = swapCase(name);\n if (swapped === name) continue;\n const own = await stat(join(this.root, name), { bigint: true }).catch(() => undefined);\n if (own === undefined) continue;\n const other = await stat(join(this.root, swapped), { bigint: true }).catch(() => undefined);\n this.insensitive = other !== undefined && other.ino === own.ino && other.dev === own.dev;\n return this.insensitive;\n }\n return this.foldsAtAncestor();\n }\n\n /**\n * The same question asked of the root's own name, or the nearest existing directory above it, when the root holds\n * nothing to try: a root with no entries has none to alias yet, but two names created at once still would. Not\n * remembered, since it is the volume above the root that answers.\n */\n private async foldsAtAncestor(): Promise<boolean> {\n let dir = resolve(this.root);\n for (;;) {\n const top = parse(dir).root;\n const parts = components(relative(top, dir));\n let at = parts.length - 1;\n while (at >= 0 && swapCase(parts[at]!) === parts[at]) at--;\n if (at === -1) return false;\n const swapped = [...parts];\n swapped[at] = swapCase(parts[at]!);\n let own;\n try {\n own = await stat(dir, { bigint: true });\n } catch (err) {\n if (!isAbsent(err)) return false;\n const parent = dirname(dir);\n if (parent === dir) return false;\n dir = parent;\n continue;\n }\n const other = await stat(join(top, ...swapped), { bigint: true }).catch(() => undefined);\n return other !== undefined && other.ino === own.ino && other.dev === own.dev;\n }\n }\n\n /** Whether the root's filesystem folds case: names that differ only by case are one file there. */\n folds(): Promise<boolean> {\n return this.foldsCase();\n }\n\n /**\n * `true` when `path` (inside the root) is, on disk, a path whose name differs only by case from the one given:\n * the deepest part of it that exists is resolved to its real name and compared exactly. A path that does not exist\n * yet, or that nothing differs from, is `false`.\n */\n async differs(path: string): Promise<boolean> {\n if (!(await this.foldsCase())) return false;\n const rootAbs = resolve(this.root);\n let probe = resolve(path);\n let real: string;\n for (;;) {\n if (\n probe === rootAbs ||\n !relative(rootAbs, probe) ||\n relative(rootAbs, probe).startsWith('..')\n ) {\n return false;\n }\n try {\n real = await realpath(probe);\n break;\n } catch (err) {\n if (!isAbsent(err)) throw err;\n probe = dirname(probe);\n }\n }\n const realRoot = await realpath(rootAbs).catch(() => undefined);\n if (realRoot === undefined) return false;\n const actual = relative(realRoot, real);\n // Outside the root once symlinks are resolved: a symlinked directory is outside this model, as the root is.\n if (actual.startsWith('..')) return false;\n return firstCaseDifference(components(relative(rootAbs, probe)), components(actual)) !== -1;\n }\n\n /** Refuse a write to `path` when its real name differs from it only by case. */\n async refuseVariant(path: string): Promise<void> {\n if (await this.differs(path)) throw caseVariantError();\n }\n}\n", "/**\n * Shared filesystem helpers for the LocalFs drivers (storage and registry) \u2014 one source\n * of truth for error-code matching, the symlink-refusal flag, and directory durability.\n */\nimport { constants as FS } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { lstat, mkdir, opendir, open, unlink } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport type { FileHandle } from 'node:fs/promises';\nimport { TransientError } from '@/core/errors';\n\ninterface NodeError extends Error {\n code?: string;\n}\n\n/** True when `err` is a Node system error with the given `code` (e.g. `'ENOENT'`, `'EEXIST'`). */\nexport const isCode = (err: unknown, code: string): boolean =>\n err instanceof Error && (err as NodeError).code === code;\n\n/**\n * True when `err` says nothing is at the path: it is not there, a parent is not a directory, or the name is longer than\n * the filesystem allows, so no such object can exist.\n */\nexport const isAbsent = (err: unknown): boolean =>\n isCode(err, 'ENOENT') || isCode(err, 'ENOTDIR') || isCode(err, 'ENAMETOOLONG');\n\n/**\n * Filesystem error codes that are transient \u2014 a retry after a brief backoff often succeeds: the resource is\n * busy (`EBUSY`), the OS asked us to retry (`EAGAIN`), or we hit the open-file-descriptor ceiling\n * (`EMFILE`/`ENFILE`, common under heavy concurrency once earlier handles close). A networked FS may also\n * surface `ETIMEDOUT`.\n */\nconst TRANSIENT_FS_CODES = new Set(['EBUSY', 'EAGAIN', 'EMFILE', 'ENFILE', 'ETIMEDOUT']);\n\nexport const isFsTransient = (err: unknown): boolean =>\n err instanceof Error && TRANSIENT_FS_CODES.has((err as NodeError).code ?? '');\n\n/**\n * Reclassify a transient filesystem fault as a retryable {@link TransientError}, so the store's read retry can\n * ride it out and a write's caller can tell it from a deterministic failure; everything else \u2014 including the\n * driver's own typed errors \u2014 propagates unchanged.\n */\nexport const mapFsError = (err: unknown): unknown =>\n isFsTransient(err)\n ? new TransientError(`transient filesystem fault: ${(err as NodeError).code}`, { cause: err })\n : err;\n\n/**\n * `O_NOFOLLOW` where the platform supports it (absent on Windows \u2192 0). OR it into an `open` flag set so a\n * symlink **at the final path component** is refused rather than followed outside the storage root.\n * Containment of symlinked *directory* components assumes the root itself is not attacker-writable.\n */\nexport const O_NOFOLLOW = FS.O_NOFOLLOW ?? 0;\n\n/**\n * The modes LocalFs creates what it stores with: files readable and writable by their owner alone, directories\n * searchable by it alone, so another user of the machine cannot read or list a segment. A process umask can only\n * remove bits from these, never add any. On Windows Node ignores a mode apart from the read-only bit, so passing\n * them there changes nothing.\n */\nexport const FILE_MODE = 0o600;\nconst DIR_MODE = 0o700;\n\n/**\n * Best-effort parent-directory fsync, so a just-published `rename`/`link` survives a crash. Without it the\n * directory entry can still be in the page cache when power goes: the generation's bytes are durable and\n * the name pointing at them is not, which is the one way a published generation can come back missing.\n */\nexport async function fsyncDir(dir: string): Promise<void> {\n try {\n const handle = await open(dir, 'r');\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n } catch {\n // Some platforms reject directory fsync; durability of the entry is then best-effort.\n }\n}\n\n/**\n * Write every byte of `bytes` at the handle's position. One `write` can write fewer bytes than it was asked to and not\n * fail (a full disk, a quota, some network filesystems), and a caller that took it for the whole would store a torn row\n * or object as a whole one. A write that makes no progress is a full device.\n */\nexport async function writeAll(handle: FileHandle, bytes: Uint8Array): Promise<void> {\n let offset = 0;\n while (offset < bytes.length) {\n const { bytesWritten } = await handle.write(bytes, offset, bytes.length - offset);\n if (bytesWritten <= 0) {\n throw Object.assign(new Error('a write made no progress: the device is full'), {\n code: 'ENOSPC',\n });\n }\n offset += bytesWritten;\n }\n}\n\n/**\n * Create `dir` and the directories missing above it, private from `top` down: what is missing above `top` is created\n * with the default mode (another service may need to traverse it), `top` and everything below it {@link DIR_MODE}. A\n * directory that exists keeps its mode.\n */\nexport async function makeDirs(dir: string, top: string): Promise<void> {\n if (!parentsMade.has(top)) {\n await mkdir(dirname(top), { recursive: true });\n parentsMade.add(top);\n }\n await mkdir(dir, { recursive: true, mode: DIR_MODE });\n}\nconst parentsMade = new Set<string>();\n\n/** The name of a temp file beside `finalPath`: `<finalPath>.<uuid>.tmp`. The only names {@link sweepOrphanTemps} removes. */\nexport const tempPathFor = (finalPath: string): string => `${finalPath}.${randomUUID()}.tmp`;\nconst TEMP_NAME = /\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\.tmp$/;\n\n/** A temp file this old belongs to no write in progress: a crash or a failed close left it behind. */\nconst ORPHAN_TEMP_AGE_MS = 24 * 60 * 60 * 1000;\n/** A directory is swept at most this often per process, so a save never lists a large directory every time. */\nconst SWEEP_INTERVAL_MS = 60 * 60 * 1000;\nconst lastSwept = new Map<string, number>();\n\n/**\n * Remove the temp files in `dir` named by {@link tempPathFor} that were last written more than a day ago, streaming the\n * directory, and at most once an hour per directory in this process. Only regular files go (a symlink is never followed\n * or removed). Best effort: a failure leaves the files for a later sweep and is never raised. Callers start it without\n * awaiting it.\n */\nexport async function sweepOrphanTemps(dir: string, now: number = Date.now()): Promise<void> {\n const last = lastSwept.get(dir);\n if (last !== undefined && now - last < SWEEP_INTERVAL_MS) return;\n lastSwept.set(dir, now);\n try {\n const entries = await opendir(dir);\n for await (const entry of entries) {\n if (!TEMP_NAME.test(entry.name)) continue;\n const path = join(dir, entry.name);\n const info = await lstat(path).catch(() => undefined);\n if (info?.isFile() === true && info.mtimeMs < now - ORPHAN_TEMP_AGE_MS) {\n await unlink(path).catch(() => {});\n }\n }\n } catch {\n // Nothing to sweep, or unreadable: the next interval tries again.\n }\n}\n", "/**\n * `LocalFsRegistryDriver` \u2014 a zero-cloud, persistent {@link IRegistryDriver}.\n *\n * One JSON file per segment at `<root>/<namespace>/registry/<segment>.reg`, holding `{ deleted, record }`.\n * OCC: the token is a random incarnation id drawn when the row is created, a counter advanced on every mutation, and a\n * random part drawn for every write, so with overwhelming probability a deleted-then-recreated row, or one restored from a backup, never\n * re-issues an old token (ABA-safe). A `delete` unlinks the row's file: a re-create draws a new incarnation, so nothing\n * of the old row is needed to keep its tokens apart. Every write is temp \u2192 fsync(file) \u2192 atomic rename \u2192 fsync(dir), and\n * read-modify-write is serialized per row across the whole process (the lock is keyed by the row's resolved\n * path, so every instance on one root shares it). A root is for one process: two processes on one root are not\n * fenced. Drivers do I/O; only `core/` is bound by determinism.\n */\nimport { checkRegistryWriteOptions } from '../_shared/options';\nimport { constants as FS } from 'node:fs';\nimport { open, opendir, readdir, realpath, rename, unlink } from 'node:fs/promises';\nimport type { Dir } from 'node:fs';\nimport { basename, dirname, join, relative, resolve } from 'node:path';\nimport { IntegrityError, TransientError, ValidationError, WriteConflictError } from '@/core/errors';\nimport type { Entropy } from '@/core/determinism';\nimport type {\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n RegistryWriteOptions,\n SegmentRef,\n Token,\n} from '@/core/ports';\nimport {\n applyRegistryPatch,\n newIncarnationToken,\n nextRegistryToken,\n parseRegistryEnvelope,\n recordFromNew,\n serializeRegistryEnvelope,\n validateNewRegistryRecord,\n validateRegistryPatch,\n type RegistryEnvelope,\n} from '../_shared/registry';\nimport { entropyIsAvailable, webCryptoEntropy } from '../_shared/entropy';\nimport {\n assertRegistryNamesFit,\n registryDir,\n registryRowPath,\n parseNamespaceDir,\n parseRegistryRow,\n} from './paths';\nimport { ExactCase } from './exact-case';\nimport {\n FILE_MODE,\n O_NOFOLLOW,\n fsyncDir,\n isAbsent,\n isCode,\n mapFsError,\n writeAll,\n makeDirs,\n sweepOrphanTemps,\n tempPathFor,\n} from './fs-util';\n\n/** Defensive cap on a single registry file read from storage, before allocation. */\nconst DEFAULT_MAX_ROW_BYTES = 1 * 1024 * 1024;\n\n/**\n * Per-row promise chains, shared by every driver instance in the process and keyed by the row's resolved path,\n * so two instances on one root (or one root reached through a symlink or a relative path) take one lock. An\n * entry is deleted when its chain drains, so the map holds only rows with an operation in flight.\n */\nconst rowChains = new Map<string, Promise<unknown>>();\n\n/** Entries in the process-wide row-lock map; the map is empty whenever no registry operation is in flight. */\nexport function localFsRowLockCount(): number {\n return rowChains.size;\n}\n\n/**\n * The row's identity for locking: the real path of the nearest directory that exists, plus the not-yet-created\n * tail. Resolving symlinks and relative roots makes every spelling of one row the same key.\n */\nasync function rowLockKey(path: string): Promise<string> {\n const abs = resolve(path);\n const tail: string[] = [basename(abs)];\n let dir = dirname(abs);\n for (;;) {\n try {\n return join(await realpath(dir), ...tail);\n } catch (err) {\n const parent = dirname(dir);\n if (!isAbsent(err) || parent === dir) throw mapFsError(err);\n tail.unshift(basename(dir));\n dir = parent;\n }\n }\n}\n\ninterface LocalFsRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n /** Draws every token's random parts; defaults to Web Crypto. Inject one only to make a test replayable. */\n readonly entropy?: Entropy;\n /** The directory this root lives under, from which down directories are created private; defaults to the root. */\n readonly privateRoot?: string;\n}\n\nexport class LocalFsRegistryDriver implements IRegistryDriver {\n private readonly now: () => number;\n private readonly entropy: Entropy;\n\n private readonly exactCase: ExactCase;\n\n constructor(\n private readonly root: string,\n private readonly options: LocalFsRegistryDriverOptions = {},\n ) {\n this.exactCase = new ExactCase(root);\n this.now = options.now ?? (() => Date.now());\n this.entropy = options.entropy ?? webCryptoEntropy;\n }\n\n /**\n * `conditionalDelete`: a delete reads the row, checks it, and unlinks it under the row's lock, which every writer on\n * the root in this process takes, so no write can land between the check and the unlink.\n */\n capabilities(): RegCaps {\n return entropyIsAvailable(this.entropy)\n ? { strongRead: true, conditionalDelete: true }\n : { strongRead: true, canWrite: false, conditionalDelete: true };\n }\n\n /** Every write reports its token to `onToken` before the row's file is written. */\n get reportsWriteTokens(): true {\n return true;\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n const env = await this.readRow(registryRowPath(this.root, ref), ref);\n return env && !env.deleted ? env.record : null;\n }\n\n async create(\n ref: SegmentRef,\n record: NewRegistryRecord,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }> {\n checkRegistryWriteOptions(options);\n const checked = validateNewRegistryRecord(record);\n const path = registryRowPath(this.root, ref);\n assertRegistryNamesFit(ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path, ref);\n if (current !== null && !current.deleted) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n // A new incarnation, whose counter continues across a tombstone (ABA-safe).\n const token = newIncarnationToken(this.entropy, current?.record);\n options?.onToken?.(token);\n await this.writeRow(path, recordFromNew(ref, checked, this.now(), token));\n return { token };\n });\n }\n\n /**\n * A caller's `held` row (see `RegistryWriteOptions`) has no read to spare here: the row's file is read under its lock and its token compared\n * there, a local read and no request, so a stale one fails exactly as a lost race does.\n */\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }> {\n checkRegistryWriteOptions(options);\n const checked = validateRegistryPatch(patch);\n const path = registryRowPath(this.root, ref);\n assertRegistryNamesFit(ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path, ref);\n if (current === null || current.deleted || current.record.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = nextRegistryToken(current.record, this.entropy);\n options?.onToken?.(token);\n await this.writeRow(path, applyRegistryPatch(current.record, checked, this.now(), token));\n return { token };\n });\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n for (const ns of await this.namespaceDirs(namespace)) {\n const dir = registryDir(this.root, ns);\n if (await this.exactCase.differs(dir)) continue; // another case's directory is not this one\n let entries: Dir;\n try {\n entries = await opendir(dir);\n } catch (err) {\n if (isAbsent(err)) continue; // no registry rows in this namespace yet\n throw mapFsError(err);\n }\n // Streamed a batch of names at a time, so a namespace of many rows is never held as one list; the directory is\n // closed when the loop ends, the consumer's stopping early included.\n for await (const entry of entries) {\n const segment = parseRegistryRow(entry.name);\n if (segment === null) continue;\n const ref = { namespace: ns, segment };\n const env = await this.readRow(registryRowPath(this.root, ref), ref);\n if (env && !env.deleted) yield env.record;\n }\n }\n }\n\n async delete(ref: SegmentRef, expected?: Token): Promise<void> {\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path, ref);\n if (expected !== undefined) {\n if (current === null || current.deleted || current.record.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n } else if (current === null || current.deleted) {\n return; // idempotent\n }\n await this.unlinkRow(path);\n });\n }\n\n /** Remove a row's file and make the removal durable (fsync the directory). */\n private async unlinkRow(path: string): Promise<void> {\n try {\n await unlink(path);\n } catch (err) {\n if (!isCode(err, 'ENOENT')) throw mapFsError(err);\n }\n await fsyncDir(dirname(path));\n }\n\n /** Namespaces to scan: just the one requested, or every namespace dir under the root. */\n private async namespaceDirs(namespace: string | undefined): Promise<Array<string | undefined>> {\n if (namespace !== undefined) return [namespace];\n let entries: string[];\n try {\n entries = await readdir(this.root);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return [];\n throw mapFsError(err);\n }\n // A namespace dir name is the namespace ENCODED for a path, so it has to be parsed back rather than used\n // as-is \u2014 `tenant:acme` lives in `tenant%3Aacme`, and `%` only ever appears in an escape we wrote, so an un-decoded directory name fails the round-trip check. Anything that does\n // not parse is skipped, never thrown on: this enumeration is fleet-wide, so one unrecognised directory\n // must not take the consistency check, the retention sweep and subject erasure down with it.\n const namespaces: Array<string | undefined> = [];\n for (const entry of entries) {\n const parsed = parseNamespaceDir(entry);\n if (parsed !== null) namespaces.push(parsed.namespace);\n }\n return namespaces;\n }\n\n /** Read the row at `path`, which must be the row of `ref`: one that names another segment is refused. */\n private async readRow(path: string, ref: SegmentRef): Promise<RegistryEnvelope | null> {\n let handle;\n try {\n if (await this.exactCase.differs(path)) return null; // another case's row is not this one\n handle = await open(path, FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isAbsent(err) || isCode(err, 'ELOOP')) return null;\n throw mapFsError(err);\n }\n try {\n const { size } = await handle.stat();\n if (size > DEFAULT_MAX_ROW_BYTES) {\n throw new IntegrityError(`registry row ${size}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`);\n }\n const text = (await handle.readFile()).toString('utf8');\n // Named by its path under the root, which says which file to look at without putting the host's layout in a log.\n return parseRegistryEnvelope(text, relative(this.root, path), ref);\n } finally {\n await handle.close();\n }\n }\n\n private async writeRow(path: string, record: RegistryRecord): Promise<void> {\n await this.exactCase.refuseVariant(path);\n await makeDirs(dirname(path), this.options.privateRoot ?? this.root);\n void sweepOrphanTemps(dirname(path));\n const out = Buffer.from(serializeRegistryEnvelope({ deleted: false, record }), 'utf8');\n // Cap on the write path too (the read path caps at the same size): never produce a row that would later\n // be unreadable. The governance fields are already capped by validate*, so this is a belt-and-braces guard.\n if (out.length > DEFAULT_MAX_ROW_BYTES) {\n throw new ValidationError(\n `registry row ${out.length}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`,\n );\n }\n\n const tmp = tempPathFor(path);\n let handle;\n try {\n handle = await open(tmp, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW, FILE_MODE);\n } catch (err) {\n throw mapFsError(err);\n }\n try {\n await writeAll(handle, out);\n await handle.sync();\n } catch (err) {\n // The temp file goes with the failed write, rather than accumulate beside the row.\n await handle.close().catch(() => {});\n await unlink(tmp).catch(() => {});\n throw mapFsError(err);\n }\n await handle.close();\n await rename(tmp, path).catch(async (err) => {\n await unlink(tmp).catch(() => {});\n if (isCode(err, 'ENOENT')) {\n throw new TransientError('the temporary file of a registry row was removed mid-write', {\n cause: err,\n });\n }\n throw mapFsError(err);\n });\n await fsyncDir(dirname(path));\n }\n\n /** Serialize callbacks for a row so read-modify-write is atomic across every instance in the process. */\n private async withRowLock<T>(path: string, fn: () => Promise<T>): Promise<T> {\n // On a case-insensitive root two spellings of a path are one row, so they take one lock.\n const resolved = await rowLockKey(path);\n const key = (await this.exactCase.folds()) ? resolved.toLowerCase() : resolved;\n const prev = rowChains.get(key) ?? Promise.resolve();\n const result = prev.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n rowChains.set(key, tail);\n void tail.then(() => {\n if (rowChains.get(key) === tail) rowChains.delete(key);\n });\n return result;\n }\n}\n", "/**\n * Concrete AES-256-GCM crypto (lives outside `core/`, which lint-bans `node:crypto`). Implements the injected\n * {@link Aead}/{@link IKeystore} seams from `core/crypto`: a `NodeAead` over `aes-256-gcm`, and an in-process\n * **BYOK** keystore that envelope-wraps a per-segment DEK under one or more operator-held KEKs.\n *\n * Default, dependency-free key management: you bring 32-byte KEK(s); we never call a cloud service. KMS/Vault\n * are future optional adapters against the same {@link IKeystore} interface. **The KEK is the\n * one secret to back up** \u2014 lose it and that segment's at-rest bytes are unrecoverable by design (re-seed the\n * segment from your source of truth); see the encryption guide.\n */\nimport { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport type { Aead, AeadSealed, IKeystore, WrappedDek } from '../core/crypto';\nimport { refuseUnknownOptions } from './_shared/options';\nimport { IntegrityError, KeyUnavailableError, ValidationError } from '../core/errors';\n\nconst UTF8 = new TextEncoder();\nconst KEY_BYTES = 32; // AES-256\nconst NONCE_BYTES = 12; // GCM standard nonce\nconst TAG_BYTES = 16; // GCM tag\n\n/** A `Uint8Array`, a `Buffer` among them, from this realm or another. */\nconst isBytes = (v: unknown): v is Uint8Array =>\n Object.prototype.toString.call(v) === '[object Uint8Array]';\n\n/**\n * A copy of key bytes in a buffer of their own. `Buffer.from` takes small buffers from a slab of Node's shared pool (8 KiB on Node 22,\n * 64 KiB on recent Node 24), so a held key would pin the whole slab it came from for as long as it lives, and keep key bytes beside unrelated data.\n */\nfunction ownKey(key: Uint8Array): Buffer {\n const own = Buffer.alloc(key.length);\n own.set(key);\n return own;\n}\n\n/** AES-256-GCM AEAD bound to one 32-byte key. A fresh CSPRNG 96-bit nonce per `seal`; `aad` is authenticated,\n * never stored. Nonce-reuse safety: the random-96-bit birthday bound is ~q\u00B2/2\u2079\u2077, negligible below ~2\u00B3\u00B2 seals\n * under one key. A per-segment DEK is **reused across all generations** (every load and rewrite encrypts under it), so\n * seal count is cumulative over the segment's life \u2014 a segment approaching ~2\u00B3\u00B2 lifetime chunk-seals should be\n * re-seeded (a fresh segment \u21D2 fresh DEK). A segment at the 65,536-chunk maximum reaches it after about 65,500 loads\n * or rewrites (230 days at one every 5 minutes): load into a fresh segment, or load less often, before then. */\nexport class NodeAead implements Aead {\n private readonly key: Buffer;\n\n constructor(key: Uint8Array) {\n if (!isBytes(key))\n throw new ValidationError('AEAD key must be a Uint8Array of key bytes, not text');\n if (key.length !== KEY_BYTES)\n throw new ValidationError(`AEAD key must be ${KEY_BYTES} bytes, got ${key.length}`);\n this.key = ownKey(key);\n }\n\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed {\n const nonce = randomBytes(NONCE_BYTES);\n const cipher = createCipheriv('aes-256-gcm', this.key, nonce);\n cipher.setAAD(aad);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n return { nonce, ciphertext, tag: cipher.getAuthTag() };\n }\n\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array {\n if (sealed.nonce.length !== NONCE_BYTES || sealed.tag.length !== TAG_BYTES)\n throw new IntegrityError('AEAD nonce/tag have the wrong length');\n const decipher = createDecipheriv('aes-256-gcm', this.key, sealed.nonce);\n decipher.setAAD(aad);\n decipher.setAuthTag(Buffer.from(sealed.tag));\n try {\n return Buffer.concat([decipher.update(sealed.ciphertext), decipher.final()]);\n } catch {\n // Wrong key, tampered ciphertext/tag, or mismatched AAD \u2014 never leak which, never return plaintext.\n throw new IntegrityError(\n 'AEAD authentication failed (wrong key, tampered data, or wrong context)',\n );\n }\n }\n}\n\n/** Wrap/unwrap a DEK under a KEK with AES-256-GCM, binding the wrapping to its `keyId` via AAD so a wrapping\n * can't be relabelled to another KEK. Stored blob = nonce \u2016 ciphertext \u2016 tag, base64. */\nfunction wrapKey(dek: Uint8Array, kek: Uint8Array, keyId: string): string {\n const sealed = new NodeAead(kek).seal(dek, UTF8.encode(keyId));\n return Buffer.concat([sealed.nonce, sealed.ciphertext, sealed.tag]).toString('base64');\n}\n\nfunction unwrapKey(wrapped: string, kek: Uint8Array, keyId: string): Uint8Array {\n const blob = Buffer.from(wrapped, 'base64');\n if (blob.length < NONCE_BYTES + TAG_BYTES)\n throw new IntegrityError('wrapped DEK is too short to be valid');\n const nonce = blob.subarray(0, NONCE_BYTES);\n const tag = blob.subarray(blob.length - TAG_BYTES);\n const ciphertext = blob.subarray(NONCE_BYTES, blob.length - TAG_BYTES);\n return new NodeAead(kek).open({ nonce, ciphertext, tag }, UTF8.encode(keyId));\n}\n\n/**\n * Options for {@link InProcessKeystore}. `keys` maps a `keyId` \u2192 its 32-byte KEK; `activeKeyId` names the KEK\n * new DEKs are wrapped under; an optional `recoveryKeyId` additionally wraps each new DEK under a second\n * (e.g. offline) KEK, so losing the active KEK isn't fatal. Rotating the active KEK needs no data\n * re-encryption: add the new KEK, point `activeKeyId` at it, keep the old one to unwrap existing segments. An option\n * it does not take, such as a misspelt `recoveryKeyId`, throws `ValidationError`.\n */\nexport interface InProcessKeystoreOptions {\n /** Each key-encryption key (KEK) by its id: 32 bytes each, at least one. */\n readonly keys: Readonly<Record<string, Uint8Array>>;\n /** The id of the KEK new data keys are wrapped under. It must be in `keys`. */\n readonly activeKeyId: string;\n /**\n * The id of a second KEK each new data key is also wrapped under, such as an offline one. Absent for none, and the\n * same id as `activeKeyId` means none too; it must be in `keys` when given.\n */\n readonly recoveryKeyId?: string;\n}\n\n/**\n * Dependency-free BYOK keystore: envelope-wraps a fresh random per-segment DEK under the active (and optional\n * recovery) KEK using `node:crypto`. No external service. The raw DEK never leaves the `Aead` it returns.\n */\nexport class InProcessKeystore implements IKeystore {\n private readonly keys: Map<string, Uint8Array>;\n private readonly activeKeyId: string;\n private readonly recoveryKeyId: string | undefined;\n\n /**\n * Builds a keystore from `options`; throws `ValidationError` for no options object, an option it does not take\n * (a misspelt `recoveryKeyId` would otherwise leave no recovery wrapping), a `keys` that is not an object, an\n * `activeKeyId` or `recoveryKeyId` that is not a string, no keys, a key given as text rather than a\n * `Uint8Array`, a key that is not 32 bytes, or an `activeKeyId` or `recoveryKeyId` that is not in `keys`. A\n * `recoveryKeyId` equal to `activeKeyId` means no recovery key.\n */\n constructor(options: InProcessKeystoreOptions) {\n refuseUnknownOptions('InProcessKeystore', options, ['keys', 'activeKeyId', 'recoveryKeyId']);\n const keys: unknown = options.keys;\n const proto: unknown =\n keys === null || typeof keys !== 'object' ? null : Object.getPrototypeOf(keys);\n if (\n keys === null ||\n typeof keys !== 'object' ||\n (proto !== Object.prototype && proto !== null)\n ) {\n throw new ValidationError(\n 'InProcessKeystore: `keys` must be a plain object of key id to 32-byte Uint8Array KEK, not a Map or an array',\n );\n }\n if (typeof options.activeKeyId !== 'string') {\n throw new ValidationError(\n 'InProcessKeystore: `activeKeyId` must be a string naming one of `keys`',\n );\n }\n if (options.recoveryKeyId !== undefined && typeof options.recoveryKeyId !== 'string') {\n throw new ValidationError(\n 'InProcessKeystore: `recoveryKeyId` must be a string naming one of `keys`, or absent for none',\n );\n }\n const entries = Object.entries(keys);\n if (entries.length === 0) throw new ValidationError('keystore needs at least one KEK');\n for (const [id, k] of entries) {\n // Text of the right length would pass the length check and become a key of printable characters, with no key\n // derivation: an environment variable passed as it is.\n if (!isBytes(k))\n throw new ValidationError(`KEK \"${id}\" must be a Uint8Array of key bytes, not text`);\n if (k.length !== KEY_BYTES)\n throw new ValidationError(`KEK \"${id}\" must be ${KEY_BYTES} bytes, got ${k.length}`);\n }\n this.keys = new Map(entries.map(([id, k]) => [id, ownKey(k)]));\n // Membership is against the keys given, not the names an object inherits (`constructor`, `toString`).\n if (!this.keys.has(options.activeKeyId))\n throw new ValidationError(`activeKeyId \"${String(options.activeKeyId)}\" is not in keys`);\n if (options.recoveryKeyId !== undefined && !this.keys.has(options.recoveryKeyId))\n throw new ValidationError(`recoveryKeyId \"${String(options.recoveryKeyId)}\" is not in keys`);\n this.activeKeyId = options.activeKeyId;\n this.recoveryKeyId =\n options.recoveryKeyId === options.activeKeyId ? undefined : options.recoveryKeyId;\n }\n\n // async to satisfy the IKeystore seam (a KMS adapter awaits a network call here); the in-process path is\n // synchronous, but staying async keeps unwrap failures as rejections, matching a remote keystore.\n async createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }> {\n const dek = randomBytes(KEY_BYTES);\n const ids = this.recoveryKeyId ? [this.activeKeyId, this.recoveryKeyId] : [this.activeKeyId];\n const wrapped = ids.map((keyId) => ({\n keyId,\n wrapped: wrapKey(dek, this.keys.get(keyId)!, keyId),\n }));\n return { wrapped, aead: new NodeAead(dek) };\n }\n\n // async for the same reason as createDek \u2014 a synchronous unwrap failure surfaces as a promise rejection.\n async openDek(wrapped: readonly WrappedDek[]): Promise<Aead> {\n // Try EVERY held wrapping, not just the first: a DEK is wrapped under both the active KEK and (if\n // configured) the offline recovery KEK precisely so a damaged/tampered active-KEK wrapping can be\n // recovered from the other. Returning on the first held keyId and letting a corrupt unwrap throw would\n // defeat that insurance \u2014 the recovery wrapping would never be attempted. So catch a failed unwrap and\n // fall through to the next held wrapping; only give up once none succeeds.\n let anyKekHeld = false;\n let lastUnwrapError: unknown;\n for (const w of wrapped) {\n const kek = this.keys.get(w.keyId);\n if (kek === undefined) continue;\n anyKekHeld = true;\n try {\n return new NodeAead(unwrapKey(w.wrapped, kek, w.keyId));\n } catch (err) {\n lastUnwrapError = err; // held KEK but this wrapping is corrupt/tampered \u2014 try the next one\n }\n }\n // A KEK WAS held but every held wrapping failed to unwrap \u2192 the wrapping(s) are corrupt/tampered, not\n // missing. Surface that integrity failure in its original type rather than masking it as \"no held KEK\".\n if (anyKekHeld) throw lastUnwrapError;\n // The ids the wrappings name, not the ids this keystore holds: the message reaches ledgers and logs, and the held\n // keys are not the reader's to see.\n const need = wrapped.map((w) => w.keyId).join(', ') || '(none)';\n throw new KeyUnavailableError(\n `no held KEK can unwrap this DEK \u2014 the wrappings reference [${need}]. ` +\n `Restore the missing KEK (or its recovery KEK), or rebuild the segment from source.`,\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["join", "FS", "createHash", "open", "readdir", "unlink", "dirname", "dirname", "join", "join", "join", "join", "dirname", "dirname", "open", "FS", "createHash", "unlink", "readdir", "FS", "open", "opendir", "readdir", "realpath", "unlink", "dirname", "join", "relative", "resolve", "resolve", "dirname", "join", "realpath", "opendir", "unlink", "readdir", "open", "FS", "relative", "join"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbitmaps/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Internal engine of CloudBitmaps, which the other @cloudbitmaps packages are built on. Its main entry is outside the stability promise; the public contract for writing a driver is @cloudbitmaps/core/driver-kit. No cloud SDK.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"roaring",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"sideEffects": false,
|
|
41
41
|
"cloudbitmaps": {
|
|
42
42
|
"internalEntries": [
|
|
43
|
-
"."
|
|
43
|
+
".",
|
|
44
|
+
"./node"
|
|
44
45
|
]
|
|
45
46
|
},
|
|
46
47
|
"main": "./dist/index.js",
|
|
@@ -53,6 +54,11 @@
|
|
|
53
54
|
"./driver-kit": {
|
|
54
55
|
"types": "./dist/driver-kit.d.ts",
|
|
55
56
|
"default": "./dist/driver-kit.js"
|
|
57
|
+
},
|
|
58
|
+
"./package.json": "./package.json",
|
|
59
|
+
"./node": {
|
|
60
|
+
"types": "./dist/node.d.ts",
|
|
61
|
+
"default": "./dist/node.js"
|
|
56
62
|
}
|
|
57
63
|
},
|
|
58
64
|
"files": [
|
|
@@ -72,6 +78,9 @@
|
|
|
72
78
|
"*": {
|
|
73
79
|
"driver-kit": [
|
|
74
80
|
"./dist/driver-kit.d.ts"
|
|
81
|
+
],
|
|
82
|
+
"node": [
|
|
83
|
+
"./dist/node.d.ts"
|
|
75
84
|
]
|
|
76
85
|
}
|
|
77
86
|
},
|