@cloudbitmaps/core 0.1.0-rc.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/LICENSE +202 -0
- package/NOTICE +12 -0
- package/README.md +22 -0
- package/dist/azure/index.cjs +368 -0
- package/dist/azure/index.cjs.map +1 -0
- package/dist/azure/index.d.cts +48 -0
- package/dist/azure/index.d.ts +48 -0
- package/dist/azure/index.js +304 -0
- package/dist/azure/index.js.map +1 -0
- package/dist/cassandra/index.cjs +265 -0
- package/dist/cassandra/index.cjs.map +1 -0
- package/dist/cassandra/index.d.cts +52 -0
- package/dist/cassandra/index.d.ts +52 -0
- package/dist/cassandra/index.js +204 -0
- package/dist/cassandra/index.js.map +1 -0
- package/dist/chunk-2YDULGXS.js +203 -0
- package/dist/chunk-2YDULGXS.js.map +1 -0
- package/dist/chunk-7LMLYSVJ.js +43 -0
- package/dist/chunk-7LMLYSVJ.js.map +1 -0
- package/dist/chunk-AS6ODRLT.js +6 -0
- package/dist/chunk-AS6ODRLT.js.map +1 -0
- package/dist/chunk-NUIDEEFZ.js +91 -0
- package/dist/chunk-NUIDEEFZ.js.map +1 -0
- package/dist/chunk-SNJVZ227.js +35 -0
- package/dist/chunk-SNJVZ227.js.map +1 -0
- package/dist/dynamodb/index.cjs +731 -0
- package/dist/dynamodb/index.cjs.map +1 -0
- package/dist/dynamodb/index.d.cts +106 -0
- package/dist/dynamodb/index.d.ts +106 -0
- package/dist/dynamodb/index.js +460 -0
- package/dist/dynamodb/index.js.map +1 -0
- package/dist/gcs/index.cjs +343 -0
- package/dist/gcs/index.cjs.map +1 -0
- package/dist/gcs/index.d.cts +46 -0
- package/dist/gcs/index.d.ts +46 -0
- package/dist/gcs/index.js +279 -0
- package/dist/gcs/index.js.map +1 -0
- package/dist/index.cjs +4031 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1945 -0
- package/dist/index.d.ts +1945 -0
- package/dist/index.js +3642 -0
- package/dist/index.js.map +1 -0
- package/dist/mongodb/index.cjs +260 -0
- package/dist/mongodb/index.cjs.map +1 -0
- package/dist/mongodb/index.d.cts +45 -0
- package/dist/mongodb/index.d.ts +45 -0
- package/dist/mongodb/index.js +199 -0
- package/dist/mongodb/index.js.map +1 -0
- package/dist/mysql/index.cjs +281 -0
- package/dist/mysql/index.cjs.map +1 -0
- package/dist/mysql/index.d.cts +56 -0
- package/dist/mysql/index.d.ts +56 -0
- package/dist/mysql/index.js +211 -0
- package/dist/mysql/index.js.map +1 -0
- package/dist/ports-D3BrJ6ax.d.cts +357 -0
- package/dist/ports-D3BrJ6ax.d.ts +357 -0
- package/dist/postgres/index.cjs +273 -0
- package/dist/postgres/index.cjs.map +1 -0
- package/dist/postgres/index.d.cts +54 -0
- package/dist/postgres/index.d.ts +54 -0
- package/dist/postgres/index.js +203 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/redis/index.cjs +257 -0
- package/dist/redis/index.cjs.map +1 -0
- package/dist/redis/index.d.cts +42 -0
- package/dist/redis/index.d.ts +42 -0
- package/dist/redis/index.js +197 -0
- package/dist/redis/index.js.map +1 -0
- package/dist/s3/index.cjs +891 -0
- package/dist/s3/index.cjs.map +1 -0
- package/dist/s3/index.d.cts +112 -0
- package/dist/s3/index.d.ts +112 -0
- package/dist/s3/index.js +555 -0
- package/dist/s3/index.js.map +1 -0
- package/package.json +172 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/errors.ts","../../src/core/validate.ts","../../src/drivers/_shared/keys.ts","../../src/drivers/s3/keys.ts","../../src/drivers/_shared/aws-errors.ts","../../src/drivers/s3/s3-errors.ts","../../src/drivers/s3/cold.ts","../../src/drivers/_shared/registry.ts","../../src/core/concurrency.ts","../../src/drivers/s3/registry.ts"],"names":["GetObjectCommand","HeadObjectCommand","DeleteObjectCommand","ListObjectsV2Command","createHash","res","CreateMultipartUploadCommand","UploadPartCommand","PutObjectCommand","CompleteMultipartUploadCommand","AbortMultipartUploadCommand"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Typed errors — callers learn *why* something failed, never by parsing strings. Retry is the driver\n * decorators' job, not the engine's: a driver classifies its backend's failures into this vocabulary, and\n * `withRetry` decides what is transient.\n */\n\n/**\n * Registry-symbol brands. The package ships as multiple bundles — the core entry and the `./s3` / `./dynamodb`\n * subpaths — and the builder inlines `core/errors` into each. A driver in a subpath bundle therefore throws a\n * *different* class object than the one the core engine/retry code would `instanceof`-check, so `instanceof`\n * silently returns false across that boundary in the published CJS package (defeating OCC/transient retry and\n * compaction race-handling). These `Symbol.for` brands are identity-stable across bundles/realms; classify\n * errors with the exported predicates below (never `instanceof`) anywhere an error may cross the boundary.\n */\nconst ERROR_BRAND: unique symbol = Symbol.for('cloud-roaring.error');\nconst TRANSIENT_BRAND: unique symbol = Symbol.for('cloud-roaring.error.transient');\n\n/** Base class for every error CloudRoaring throws. */\nexport class CloudRoaringError extends Error {\n /** Cross-bundle brand — see the predicates ({@link isCloudRoaringError}, …). Non-enumerable-ish (symbol key ⇒ not in JSON). */\n readonly [ERROR_BRAND] = true as const;\n constructor(message: string) {\n super(message);\n // Subclass name (works under transpilation since we set it explicitly). Also the discriminator the\n // predicates match on — a runtime string, so it survives bundling where the class identity does not.\n this.name = new.target.name;\n }\n}\n\n/** Invalid caller input (bad id, segment name, options). Raised before any storage call. */\nexport class ValidationError extends CloudRoaringError {}\n\n/** An OCC conditional write/delete lost the race — the row changed since it was read. */\nexport class WriteConflictError extends CloudRoaringError {}\n\n/** Bytes from a tier are corrupt, oversized, or fail a checksum/format check. */\nexport class IntegrityError extends CloudRoaringError {}\n\n/**\n * A requested object/row does not exist. Part of the driver error vocabulary; thrown by\n * persistent drivers from Phase 2 — the Phase-1 engine + in-memory drivers return `null` instead.\n */\nexport class NotFoundError extends CloudRoaringError {}\n\n/**\n * This build/configuration cannot perform the requested operation, though nothing is malformed. Two uses:\n * (1) **format** — the bytes are well-formed but unreadable here (an unknown `.crbm` major version, an\n * encrypted file before the crypto path exists) — distinct from `IntegrityError` (corruption); and (2)\n * **store configuration** — an operation this store's wiring doesn't support (e.g. a lifecycle helper like\n * `compact`/`eraseSubject` called on a store built without a raw cold driver + registry). Raised at\n * operation time, before any mutation.\n */\nexport class UnsupportedError extends CloudRoaringError {}\n\n/**\n * A driver cannot meet a capability the chosen topology requires (e.g. a Cold driver without range\n * reads). Raised fail-fast at wiring time, never mid-operation.\n */\nexport class CapabilityError extends CloudRoaringError {}\n\n/**\n * An operation would exceed its per-op **denial-of-wallet budget** — too many backend requests for a single\n * `count`/`iterate`/`intersect`/`subjectReport`/`eraseSubject` call — so it is refused **before** fanning out\n * (Decision #3 / invariant T3). Default-on but generous (normal ops never hit it); tune it\n * per store (`budget`) or per op, or disable with `budget: false`. Deterministic (never retried): the op is too\n * big by policy, not by luck. Each request's bytes are separately capped (the safe-deserialize ceiling), so\n * bounding the request count transitively bounds bytes. Carries the projected count + the limit, never data.\n */\nexport class BudgetExceededError extends CloudRoaringError {}\n\n/**\n * An encrypted segment's data key (DEK) cannot be unwrapped because the keystore holds none of the\n * key-encryption-keys (KEKs) its wrappings reference — the KEK was never configured, rotated away without\n * keeping the old key, or lost. Deterministic (never retried): without a KEK the ciphertext is unreadable by\n * design. The flip side of crypto-shred — when this is *intended* (a destroyed segment) the registry row is\n * already a `destroyed` tombstone; when it's *not*, restore the missing KEK (or its recovery KEK). Carries no\n * key material.\n */\nexport class KeyUnavailableError extends CloudRoaringError {}\n\n/**\n * A **transient** infrastructure fault that is safe to retry — throttling, a 5xx, a dropped connection,\n * a client-side request timeout. Drivers classify their backend's retryable faults and raise this (the\n * SDK-specific knowledge stays in the SDK-specific driver); the retry layer (`core/retry`) retries **only**\n * this class, never a deterministic error like {@link ValidationError}, {@link IntegrityError},\n * {@link NotFoundError}, or {@link WriteConflictError} (retrying those is pointless or wrong). The original\n * error is preserved in `cause` so callers can still inspect it.\n *\n * Note for logging hygiene (threat-model S12): `cause` is the **raw SDK error**, which may carry operational\n * metadata (endpoint host, request IDs, `$metadata`). The library's own `message` is identifier-only and safe\n * to log; if you serialize the whole error *chain*, be aware you're including that metadata.\n */\nexport class TransientError extends CloudRoaringError {\n /** A second brand so the whole transient subtree (incl. {@link TimeoutError}) is classifiable cross-bundle. */\n readonly [TRANSIENT_BRAND] = true as const;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n if (options && 'cause' in options) this.cause = options.cause;\n }\n}\n\n/**\n * A single attempt exceeded its time budget. Subclass of {@link TransientError} so the retry layer treats a\n * timeout as retryable by default — a stalled request often succeeds on a fresh connection. Raised by a\n * driver whose injected client reports a request timeout — setting one on your injected client is the\n * recommended way to bound a hang.\n */\nexport class TimeoutError extends TransientError {}\n\n/**\n * Bundle-safe error predicates — use these, not `instanceof`, wherever an error may cross the core↔driver\n * (`./s3` / `./dynamodb`) boundary (and prefer them in consumer `catch` blocks too, for the same reason). They\n * match the {@link ERROR_BRAND} registry brand + the runtime `name`, both of which survive separate bundling.\n */\nfunction hasBrand(err: unknown, brand: symbol): boolean {\n return (\n typeof err === 'object' && err !== null && (err as Record<symbol, unknown>)[brand] === true\n );\n}\n\n/** Any error thrown by CloudRoaring (any tier, any bundle). */\nexport function isCloudRoaringError(err: unknown): err is CloudRoaringError {\n return hasBrand(err, ERROR_BRAND);\n}\n\n/** An OCC conditional write/delete lost the race — retry the read-modify-write, don't fail. */\nexport function isWriteConflictError(err: unknown): err is WriteConflictError {\n return isCloudRoaringError(err) && err.name === 'WriteConflictError';\n}\n\n/** A retryable transient infrastructure fault (incl. {@link TimeoutError}). The retry layer keys on this. */\nexport function isTransientError(err: unknown): err is TransientError {\n return hasBrand(err, TRANSIENT_BRAND);\n}\n\n/** A requested object/row does not exist. */\nexport function isNotFoundError(err: unknown): err is NotFoundError {\n return isCloudRoaringError(err) && err.name === 'NotFoundError';\n}\n\n/** Corrupt/oversized/failed-checksum bytes from a tier. */\nexport function isIntegrityError(err: unknown): err is IntegrityError {\n return isCloudRoaringError(err) && err.name === 'IntegrityError';\n}\n\n/** Invalid caller input. */\nexport function isValidationError(err: unknown): err is ValidationError {\n return isCloudRoaringError(err) && err.name === 'ValidationError';\n}\n","/**\n * Boundary validation for segment / namespace names (finding S2).\n * Names become object keys, partition keys, and file paths — so they're validated before they\n * ever reach storage: strict charset, bounded length, no path traversal.\n */\nimport { ValidationError } from './errors';\nimport type { ChunkRef, SegmentRef } from './ports';\n\nconst CHUNK_KEY_MAX = 0xffff;\n\n// The locked name grammar: 1 leading alphanumeric + up to 255 more (max 256 chars).\nconst NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/;\n\nfunction validatePart(value: string, field: string): void {\n if (typeof value !== 'string' || !NAME.test(value) || value.includes('..')) {\n throw new ValidationError(\n `${field} must match ${String(NAME)} and contain no \"..\": got ${JSON.stringify(value)}`,\n );\n }\n}\n\nexport function validateSegmentRef(ref: SegmentRef): void {\n validatePart(ref.segment, 'segment');\n if (ref.namespace !== undefined) validatePart(ref.namespace, 'namespace');\n}\n\n/** Validate a chunk ref: the segment/namespace grammar plus `chunkKey` ∈ `[0, 65535]` (a u16). */\nexport function validateChunkRef(ref: ChunkRef): void {\n validateSegmentRef(ref);\n if (!Number.isInteger(ref.chunkKey) || ref.chunkKey < 0 || ref.chunkKey > CHUNK_KEY_MAX) {\n throw new ValidationError(\n `chunkKey must be an integer in [0, ${CHUNK_KEY_MAX}]; got ${ref.chunkKey}`,\n );\n }\n}\n","/**\n * Shared key-grammar fragments used by every driver's logical-ref → physical-key mapping (Phase 4c).\n *\n * Extracted once the registry drivers became the 4th/5th consumer of the same `_default` namespace sentinel\n * (it lived copy-pasted in `s3/keys`, `dynamodb/keys`, `localfs/paths`). Pure string logic, no SDK, no I/O —\n * lives in the SDK-free `_shared` bundle so any driver may import it.\n */\n\n/**\n * The physical stand-in for an **absent** namespace. The name grammar forbids a leading underscore\n * so `_default` can never collide with a real\n * namespace — `segment(\"s\")` and `segment(\"s\", { namespace: \"_default\" })` would be a grammar error, not an\n * aliasing hazard.\n */\nexport const DEFAULT_NAMESPACE = '_default';\n\n/** Map an optional namespace to its physical part: the namespace itself, or {@link DEFAULT_NAMESPACE}. */\nexport function namespacePart(namespace: string | undefined): string {\n return namespace ?? DEFAULT_NAMESPACE;\n}\n","/**\n * Logical-ref → S3 object-key mapping for {@link S3ColdDriver}.\n *\n * Pure string logic with no SDK dependency, so it's unit-testable without S3/MinIO. Mirrors the LocalFs\n * layout (`<namespace>/segments/<segment>.<gen>.crbm`) under an optional caller prefix, and re-validates\n * names at the boundary (defense in depth, even though the engine already validates — S2). The default\n * (absent) namespace maps to `_default`, which can't collide with a real namespace (the grammar forbids a\n * leading underscore).\n */\nimport { ValidationError } from '@/core/errors';\nimport { validateSegmentRef } from '@/core/validate';\nimport type { GenKey, SegmentRef } from '@/core/ports';\nimport { DEFAULT_NAMESPACE, namespacePart } from '../_shared/keys';\n\nconst SUFFIX = '.crbm';\nconst REGISTRY_SUFFIX = '.reg';\n\n/** Normalize an optional caller prefix to either `''` or `trimmed/` (no leading/trailing slashes). */\nfunction prefixPart(prefix: string | undefined): string {\n if (prefix === undefined) return '';\n const trimmed = prefix.replace(/^\\/+|\\/+$/g, '');\n return trimmed === '' ? '' : `${trimmed}/`;\n}\n\n/**\n * Validate the caller-supplied key prefix (trusted config, but make it a real containment boundary):\n * reject control characters and `.`/`..` path segments so a prefix can't traverse out of its intended space.\n * Returns it unchanged (the key builders normalize slashes). Shared by the S3 cold + registry drivers.\n */\nexport function normalizeS3Prefix(prefix: string | undefined): string | undefined {\n if (prefix === undefined) return undefined;\n for (const ch of prefix) {\n if (ch.charCodeAt(0) < 0x20) {\n throw new ValidationError('prefix must not contain control characters');\n }\n }\n for (const segment of prefix.split('/')) {\n if (segment === '.' || segment === '..') {\n throw new ValidationError(\n `prefix must not contain \".\" or \"..\" path segments: ${JSON.stringify(prefix)}`,\n );\n }\n }\n return prefix;\n}\n\n/**\n * The S3 key prefix shared by all of a segment's generations: `<prefix><ns>/segments/<segment>.`. Used\n * both as the `ListObjectsV2` prefix and as the string stripped by {@link parseGenerationFromKey}.\n */\nexport function segmentObjectPrefix(prefix: string | undefined, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return `${prefixPart(prefix)}${namespacePart(ref.namespace)}/segments/${ref.segment}.`;\n}\n\n/** The full S3 key of one `.crbm` generation: `<segmentPrefix><gen>.crbm`. */\nexport function coldObjectKey(prefix: string | undefined, key: GenKey): string {\n if (!Number.isInteger(key.generation) || key.generation < 0) {\n throw new ValidationError(`generation must be a non-negative integer; got ${key.generation}`);\n }\n return `${segmentObjectPrefix(prefix, key)}${key.generation}${SUFFIX}`;\n}\n\n// ─── Registry keys ({@link S3RegistryDriver}) ───────────────────────────────────────────────────────────\n// Registry objects live under a **registry-first** prefix (`<prefix>registry/<ns>/<segment>.reg`) — separate\n// from the namespace-first cold layout — so discovery is a single `ListObjectsV2` over `registry/` (all\n// namespaces) or `registry/<ns>/` (one), never entangled with the `.crbm` payload objects.\n\n/** The S3 key prefix under which every registry object lives: `<prefix>registry/`. */\nexport function registryPrefix(prefix: string | undefined): string {\n return `${prefixPart(prefix)}registry/`;\n}\n\n/** The full S3 key of one segment's registry object: `<prefix>registry/<ns>/<segment>.reg`. */\nexport function registryObjectKey(prefix: string | undefined, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return `${registryPrefix(prefix)}${namespacePart(ref.namespace)}/${ref.segment}${REGISTRY_SUFFIX}`;\n}\n\n/** The `ListObjectsV2` prefix for discovery: registry-wide, or scoped to one namespace. */\nexport function registryListPrefix(prefix: string | undefined, namespace?: string): string {\n const base = registryPrefix(prefix);\n return namespace === undefined ? base : `${base}${namespacePart(namespace)}/`;\n}\n\n/**\n * Parse a `<prefix>registry/<ns>/<segment>.reg` key back to its {@link SegmentRef}, or `null` if it doesn't\n * match (a stray/foreign object under the prefix, or one whose parsed ref fails the name grammar). `_default`\n * maps back to the absent namespace; a segment name can't contain `/`, so the split is unambiguous.\n */\nexport function parseRegistryKey(prefix: string | undefined, objectKey: string): SegmentRef | null {\n const base = registryPrefix(prefix);\n if (!objectKey.startsWith(base) || !objectKey.endsWith(REGISTRY_SUFFIX)) return null;\n const rest = objectKey.slice(base.length, objectKey.length - REGISTRY_SUFFIX.length);\n const slash = rest.indexOf('/');\n if (slash < 0) return null;\n const nsPart = rest.slice(0, slash);\n const segment = rest.slice(slash + 1);\n if (segment.length === 0 || segment.includes('/')) return null;\n const namespace = nsPart === DEFAULT_NAMESPACE ? undefined : nsPart;\n const ref: SegmentRef = { segment, namespace };\n try {\n validateSegmentRef(ref); // reject a hostile/foreign key that isn't a valid ref\n } catch {\n return null;\n }\n return ref;\n}\n\n/**\n * Parse a generation number out of a full object key, given its segment prefix, or `null` if it doesn't\n * match. Canonical decimal only — no leading zeros (so `…s.07.crbm` can't alias `…s.7.crbm`) and within\n * safe-integer range. This also rejects a *different* segment whose name merely shares the prefix (e.g. a\n * key for segment `s.x` won't parse under segment `s`'s prefix, since its middle isn't all digits).\n */\nexport function parseGenerationFromKey(segmentPrefix: string, objectKey: string): number | null {\n if (!objectKey.startsWith(segmentPrefix) || !objectKey.endsWith(SUFFIX)) return null;\n const middle = objectKey.slice(segmentPrefix.length, objectKey.length - SUFFIX.length);\n if (!/^(0|[1-9]\\d*)$/.test(middle)) return null;\n const generation = Number(middle);\n return Number.isSafeInteger(generation) ? generation : null;\n}\n","/**\n * Shared, SDK-free helpers for classifying AWS-style errors (used by the S3 + DynamoDB drivers, Phase 4b).\n *\n * These only read structural shapes an AWS SDK v3 error carries — `name`, `$metadata.httpStatusCode`, a\n * lower-level `code`/`errno`, and the SDK's own `$retryable` marker — so the (subtle, easy-to-get-wrong)\n * transient-vs-fatal decision is unit-testable without a live backend or even the SDK installed. They live\n * under `drivers/_shared` (part of the SDK-free core bundle): a driver may import them; they import no SDK.\n */\n\nexport function httpStatus(err: unknown): number | undefined {\n return (err as { $metadata?: { httpStatusCode?: number } } | null)?.$metadata?.httpStatusCode;\n}\n\nexport function errorName(err: unknown): string | undefined {\n return (err as { name?: string } | null)?.name;\n}\n\n/** A lower-level transport code (e.g. `ECONNRESET`) — the Node networking layer sets `code`. */\nexport function errorCode(err: unknown): string | undefined {\n return (err as { code?: string } | null)?.code;\n}\n\n/** The AWS SDK v3 tags retryable errors with a `$retryable` object (throttling faults carry `.throttling`). */\nexport function isSdkRetryable(err: unknown): boolean {\n return (err as { $retryable?: unknown } | null)?.$retryable != null;\n}\n\n/** Any 5xx is a server-side fault that's safe to retry (the request didn't deterministically fail). */\nexport function isServerSide(err: unknown): boolean {\n const status = httpStatus(err);\n return status !== undefined && status >= 500 && status <= 599;\n}\n\nconst NETWORK_NAMES = new Set([\n 'TimeoutError',\n 'RequestTimeout',\n 'RequestTimeoutException',\n 'NetworkingError',\n 'AbortError',\n]);\nconst NETWORK_CODES = new Set([\n 'ETIMEDOUT',\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ENOTFOUND',\n 'EAI_AGAIN',\n 'ECONNABORTED',\n]);\n\n// Message-text fallback for when the structural signals (name/code/$metadata/$retryable) are absent. Kept\n// SPECIFIC on purpose: a loose `/timed? ?out/` matches deterministic messages like \"value timed out of\n// range\" and would wrongly retry them, so we only match timeout/network phrases anchored to a transport word\n// (connection/request/socket/read/write) plus the unambiguous standalone phrases.\nconst NETWORK_MESSAGE =\n /socket hang up|network (error|failure)|(connection|request|socket|operation|read|write)\\s+tim(e|ed)\\s?out|connection (reset|refused|aborted|closed)/i;\n\n/** A dropped/timed-out connection — transient by nature; a retry on a fresh connection usually succeeds. */\nexport function isNetworkOrTimeout(err: unknown): boolean {\n if (NETWORK_NAMES.has(errorName(err) ?? '')) return true;\n if (NETWORK_CODES.has(errorCode(err) ?? '')) return true;\n return NETWORK_MESSAGE.test((err as { message?: string } | null)?.message ?? '');\n}\n","/**\n * Pure helpers for classifying S3 SDK errors + parsing response headers (Phase 3c; transient class 4b).\n *\n * Kept SDK-free and side-effect-free (they only read structural shapes — `err.name`,\n * `$metadata.httpStatusCode`, a `Content-Range` string) so the subtle S3-specific translation logic is\n * unit-testable without a live MinIO/S3 or even the AWS SDK. Shared AWS shapes come from `_shared/aws-errors`.\n */\nimport {\n errorName,\n httpStatus,\n isNetworkOrTimeout,\n isSdkRetryable,\n isServerSide,\n} from '../_shared/aws-errors';\n\n/** A conditional `If-None-Match: *` PUT lost the write-once race (the object already existed). */\nexport function isPreconditionFailed(err: unknown): boolean {\n return errorName(err) === 'PreconditionFailed' || httpStatus(err) === 412;\n}\n\n/**\n * A conditional write (`If-None-Match: *` / `If-Match: <etag>`) lost the race — **either** outcome S3 uses:\n * the precondition evaluated false (`412 PreconditionFailed`), **or** S3 rejected concurrent conditional\n * writes to the same key to prevent a lost update (`409 ConditionalRequestConflict`, which AWS documents and\n * asks you to retry). Both mean \"you lost; re-read and retry\" — so both must map to `WriteConflictError` and\n * route through the caller's OCC path, never a blind transient retry (which would just replay a doomed PUT).\n */\nexport function isConditionalConflict(err: unknown): boolean {\n return (\n isPreconditionFailed(err) ||\n errorName(err) === 'ConditionalRequestConflict' ||\n httpStatus(err) === 409\n );\n}\n\n/** The object / generation does not exist (GetObject → `NoSuchKey`, HeadObject → `NotFound`; both 404). */\nexport function isNotFound(err: unknown): boolean {\n const name = errorName(err);\n return name === 'NoSuchKey' || name === 'NotFound' || httpStatus(err) === 404;\n}\n\n/** A range request started past EOF (HTTP 416). */\nexport function isInvalidRange(err: unknown): boolean {\n return errorName(err) === 'InvalidRange' || httpStatus(err) === 416;\n}\n\n/**\n * A transient S3 fault that is safe to retry: throttling (`SlowDown` / 503), any 5xx, a dropped/timed-out\n * connection, or anything the SDK itself marks retryable. Excludes the deterministic outcomes above\n * (412/404/416) — those are caller-meaningful and must never be retried/reclassified.\n */\nexport function isTransient(err: unknown): boolean {\n // A conditional-write conflict (412/409) is caller-meaningful OCC, not a blind-retryable transient.\n if (isConditionalConflict(err) || isNotFound(err) || isInvalidRange(err)) return false;\n return (\n errorName(err) === 'SlowDown' ||\n isServerSide(err) ||\n isNetworkOrTimeout(err) ||\n isSdkRetryable(err)\n );\n}\n\n/**\n * Parse the total object size out of a `Content-Range: bytes <start>-<end>/<total>` header, or `undefined`\n * if absent/unparseable/unsafe. The total is the part after the final `/`.\n */\nexport function totalFromContentRange(contentRange: string | undefined): number | undefined {\n if (contentRange === undefined) return undefined;\n const match = /\\/(\\d+)\\s*$/.exec(contentRange);\n if (match === null) return undefined;\n const total = Number(match[1]);\n return Number.isSafeInteger(total) ? total : undefined;\n}\n","/**\n * `S3ColdDriver` — an {@link IColdDriver} over S3-compatible object storage (Phase 3c).\n *\n * Works with AWS S3 and any compatible backend (MinIO, etc.) via the official `@aws-sdk/client-s3`, which\n * is an **optional peer dependency** — only consumers of `cloud-roaring/s3` install it. The client is\n * **injected** (dependency injection): the driver owns no credential/region/endpoint logic, so it's thin,\n * testable against MinIO (point a client at its endpoint), and reuses the caller's existing client.\n *\n * Generations are write-once immutable objects: a conditional `PutObject` with `If-None-Match: *` makes the\n * publish atomic — a second write to the same key fails with `WriteConflictError`, never a silent overwrite\n * (C13), the cloud analogue of the LocalFs atomic `link`. **This requires a backend that honors\n * `If-None-Match: *`** (AWS S3 — GA Aug 2024; recent MinIO): a backend that silently ignored the\n * precondition would break write-once immutability. **Writes stream (Phase 4f):** the object is uploaded in\n * constant memory — a small object is a single conditional `PutObject`; a large one is a **multipart upload**\n * (parts flushed as the codec writes, freed as they go) finished with a conditional `CompleteMultipartUpload`,\n * so the daemon's footprint stays ~one part regardless of segment size, up to the advertised `maxObjectBytes`\n * (default `partBytes × 10,000` — S3's per-upload part limit). Drivers may use `node:crypto`; only `core/`\n * is bound by the determinism lint.\n */\nimport { createHash, type Hash } from 'node:crypto';\nimport {\n AbortMultipartUploadCommand,\n CompleteMultipartUploadCommand,\n CreateMultipartUploadCommand,\n DeleteObjectCommand,\n GetObjectCommand,\n HeadObjectCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n UploadPartCommand,\n type S3Client,\n} from '@aws-sdk/client-s3';\nimport type { BlobSink } from '@/core/blob';\nimport {\n NotFoundError,\n TransientError,\n ValidationError,\n WriteConflictError,\n isNotFoundError,\n isValidationError,\n isWriteConflictError,\n} from '@/core/errors';\nimport type { ColdCaps, GenKey, IColdDriver, SegmentRef } from '@/core/ports';\nimport {\n coldObjectKey,\n normalizeS3Prefix,\n parseGenerationFromKey,\n segmentObjectPrefix,\n} from './keys';\nimport {\n isConditionalConflict,\n isInvalidRange,\n isNotFound,\n isTransient,\n totalFromContentRange,\n} from './s3-errors';\n\n/** Part size for multipart uploads. ≥ the S3 5 MiB minimum; an object that fits in one part uses a single\n * conditional PUT instead (no multipart overhead, strongest write-once). Peak write memory ≈ one part. */\nconst S3_PART_BYTES = 8 * 1024 * 1024;\n/** S3 hard limit: a multipart upload has at most 10,000 parts. This × the part size is the real object ceiling. */\nconst S3_MAX_PARTS = 10_000;\n\nexport interface S3ColdDriverOptions {\n /** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */\n readonly client: S3Client;\n /** Target bucket (must already exist). */\n readonly bucket: string;\n /** Optional key prefix under which all objects live (e.g. `cloudroaring/`). */\n readonly prefix?: string;\n /**\n * Largest object this driver will write/advertise. Default = `partBytes × 10,000` (≈ 80 GiB at the default\n * 8 MiB part) — the honest ceiling reachable within S3's 10,000-part limit. Set it higher and `partBytes`\n * auto-grows so 10,000 parts still cover it (raising peak write memory to ~one part); up to the 5 TiB S3 max.\n */\n readonly maxObjectBytes?: number;\n /** Multipart part size in bytes (default 8 MiB; clamped to the S3 5 MiB minimum). Tunes peak write memory. */\n readonly partBytes?: number;\n}\n\nexport class S3ColdDriver implements IColdDriver {\n private readonly client: S3Client;\n private readonly bucket: string;\n private readonly prefix: string | undefined;\n private readonly maxObjectBytes: number;\n private readonly partBytes: number;\n\n constructor(options: S3ColdDriverOptions) {\n this.client = options.client;\n this.bucket = options.bucket;\n this.prefix = normalizeS3Prefix(options.prefix);\n const requestedPart = Math.max(options.partBytes ?? S3_PART_BYTES, 5 * 1024 * 1024);\n // Default the object cap to what the requested part size can actually cover within S3's 10,000-part limit;\n // if a larger cap is requested, grow the part size to keep it reachable (so the advertised cap is honest).\n this.maxObjectBytes = options.maxObjectBytes ?? requestedPart * S3_MAX_PARTS;\n this.partBytes = Math.max(requestedPart, Math.ceil(this.maxObjectBytes / S3_MAX_PARTS));\n }\n\n capabilities(): ColdCaps {\n return { rangeRead: true, maxObjectBytes: this.maxObjectBytes, conditionalPut: true };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const objectKey = coldObjectKey(this.prefix, key); // validates ref + generation\n const sink = new S3MultipartSink(\n this.client,\n this.bucket,\n objectKey,\n this.partBytes,\n this.maxObjectBytes,\n );\n try {\n await write(sink);\n return await sink.finish();\n } catch (err) {\n await sink.abort(); // best-effort cleanup of any in-flight multipart upload\n // A lost conditional-write race — the precondition failed (412) or S3 rejected concurrent conditional\n // writes to the key (409) — is the write-once conflict, never a silent overwrite.\n if (isConditionalConflict(err)) {\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n if (isValidationError(err) || isWriteConflictError(err) || isNotFoundError(err)) {\n throw err;\n }\n throw this.mapError(err);\n }\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0) {\n throw new ValidationError(`invalid range offset=${offset} length=${length}`);\n }\n const objectKey = coldObjectKey(this.prefix, key);\n if (length === 0) return new Uint8Array(0);\n try {\n const res = await this.client.send(\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: objectKey,\n Range: `bytes=${offset}-${offset + length - 1}`,\n }),\n );\n const bytes = await collect(res.Body);\n // A short read means the range ran past EOF — treat as out-of-bounds, never a partial result.\n if (bytes.length !== length) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds (got ${bytes.length}B)`,\n );\n }\n return bytes;\n } catch (err) {\n throw this.mapReadError(err, key);\n }\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const objectKey = coldObjectKey(this.prefix, key);\n if (maxBytes <= 0) {\n // No tail bytes wanted — just resolve the size via a HEAD.\n try {\n const head = await this.client.send(\n new HeadObjectCommand({ Bucket: this.bucket, Key: objectKey }),\n );\n return { bytes: new Uint8Array(0), size: head.ContentLength ?? 0 };\n } catch (err) {\n throw this.mapReadError(err, key);\n }\n }\n try {\n const res = await this.client.send(\n new GetObjectCommand({ Bucket: this.bucket, Key: objectKey, Range: `bytes=-${maxBytes}` }),\n );\n const bytes = await collect(res.Body);\n let size = totalFromContentRange(res.ContentRange);\n if (size === undefined) {\n // A spec-compliant backend omits Content-Range only on a 200 (whole object), where bytes.length\n // IS the size. If the body is exactly maxBytes we can't rule out a clamped partial from a\n // non-compliant backend — confirm the true size with a HEAD rather than trust a possibly-short read.\n if (bytes.length === maxBytes) {\n const head = await this.client.send(\n new HeadObjectCommand({ Bucket: this.bucket, Key: objectKey }),\n );\n size = head.ContentLength ?? bytes.length;\n } else {\n size = bytes.length;\n }\n }\n return { bytes, size };\n } catch (err) {\n throw this.mapReadError(err, key);\n }\n }\n\n async delete(key: GenKey): Promise<void> {\n // Idempotent: S3 DeleteObject succeeds even if the key is absent (GC may race / retry).\n try {\n await this.client.send(\n new DeleteObjectCommand({ Bucket: this.bucket, Key: coldObjectKey(this.prefix, key) }),\n );\n } catch (err) {\n throw this.mapError(err);\n }\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const prefix = segmentObjectPrefix(this.prefix, ref); // validates ref\n let token: string | undefined;\n do {\n let res;\n try {\n res = await this.client.send(\n new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n ContinuationToken: token,\n }),\n );\n } catch (err) {\n throw this.mapError(err);\n }\n for (const obj of res.Contents ?? []) {\n if (obj.Key === undefined) continue;\n const generation = parseGenerationFromKey(prefix, obj.Key);\n if (generation !== null) {\n yield { namespace: ref.namespace, segment: ref.segment, generation };\n }\n }\n token = res.IsTruncated === true ? res.NextContinuationToken : undefined;\n } while (token !== undefined);\n }\n\n /** Map S3 read errors to the driver vocabulary; pass everything else through {@link mapError}. */\n private mapReadError(err: unknown, key: GenKey): unknown {\n if (isValidationError(err)) return err;\n if (isNotFound(err)) {\n return new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n // A fully out-of-range request (start past EOF) — the BlobReader contract treats range errors as\n // ValidationError, never a short/empty read.\n if (isInvalidRange(err)) {\n return new ValidationError(`range out of bounds for ${key.segment}.${key.generation}`);\n }\n return this.mapError(err);\n }\n\n /**\n * Reclassify a transient S3 fault (throttle/5xx/dropped connection) as a retryable {@link TransientError}\n * so the retry decorator can ride it out; everything else propagates unchanged. The final fallback at every\n * `client.send` site, so callers and the decorator only ever see typed errors.\n */\n private mapError(err: unknown): unknown {\n if (isTransient(err)) {\n return new TransientError(\n `transient S3 fault: ${(err as { name?: string } | null)?.name ?? 'unknown'}`,\n { cause: err },\n );\n }\n return err;\n }\n}\n\n/** Concatenate a list of byte chunks of known total length into one buffer. */\nfunction concatBytes(parts: readonly Uint8Array[], total: number): Uint8Array {\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\n/**\n * Streaming {@link BlobSink} that uploads one S3 object in **constant memory** (Phase 4f). It buffers at most\n * one part: as the codec writes, full parts are flushed via `UploadPart` and freed. A small object that never\n * reaches one part is committed as a single conditional `PutObject`; a larger one is finished with a\n * conditional `CompleteMultipartUpload` — **both enforce write-once** via `If-None-Match: *`. SHA-256 is hashed\n * incrementally. On any error the caller invokes {@link abort} to clean up the in-flight multipart upload.\n */\nclass S3MultipartSink implements BlobSink {\n private readonly hash: Hash = createHash('sha256');\n private readonly pending: Uint8Array[] = [];\n private pendingLen = 0;\n private total = 0;\n private uploadId: string | undefined;\n private partNumber = 0;\n private readonly parts: { ETag: string | undefined; PartNumber: number }[] = [];\n\n constructor(\n private readonly client: S3Client,\n private readonly bucket: string,\n private readonly objectKey: string,\n private readonly partBytes: number,\n private readonly maxObjectBytes: number,\n ) {}\n\n async write(bytes: Uint8Array): Promise<void> {\n if (bytes.length === 0) return;\n this.total += bytes.length;\n if (this.total > this.maxObjectBytes) {\n // Fail fast + typed, rather than a late opaque S3 error (and abort the in-flight upload via the caller).\n throw new ValidationError(`object exceeds maxObjectBytes ${this.maxObjectBytes}`);\n }\n this.hash.update(bytes);\n this.pending.push(bytes);\n this.pendingLen += bytes.length;\n if (this.pendingLen >= this.partBytes) await this.flushPart();\n }\n\n /** Upload the buffered bytes (≥ one part) as a single part, freeing them. Starts the upload on first call. */\n private async flushPart(): Promise<void> {\n if (this.uploadId === undefined) {\n const res = await this.client.send(\n new CreateMultipartUploadCommand({ Bucket: this.bucket, Key: this.objectKey }),\n );\n if (res.UploadId === undefined) {\n throw new TransientError('S3 CreateMultipartUpload returned no UploadId');\n }\n this.uploadId = res.UploadId;\n }\n const body = concatBytes(this.pending, this.pendingLen);\n this.pending.length = 0;\n this.pendingLen = 0;\n this.partNumber += 1;\n if (this.partNumber > S3_MAX_PARTS) {\n // Unreachable for valid input (the maxObjectBytes byte-cap, sized to ≤ S3_MAX_PARTS parts, fires first) —\n // a typed guard so the S3 hard limit is never a raw 400.\n throw new ValidationError(`multipart upload exceeded the S3 ${S3_MAX_PARTS}-part limit`);\n }\n const res = await this.client.send(\n new UploadPartCommand({\n Bucket: this.bucket,\n Key: this.objectKey,\n UploadId: this.uploadId,\n PartNumber: this.partNumber,\n Body: body,\n }),\n );\n this.parts.push({ ETag: res.ETag, PartNumber: this.partNumber });\n }\n\n /** Commit the object: a single conditional PUT if it fit in one part, else complete the multipart upload. */\n async finish(): Promise<{ size: number; sha256: string }> {\n const sha256 = this.hash.digest('hex');\n if (this.uploadId === undefined) {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: this.objectKey,\n Body: concatBytes(this.pending, this.pendingLen),\n IfNoneMatch: '*', // write-once\n }),\n );\n return { size: this.total, sha256 };\n }\n if (this.pendingLen > 0) await this.flushPart(); // the final part may be < partBytes (allowed)\n await this.client.send(\n new CompleteMultipartUploadCommand({\n Bucket: this.bucket,\n Key: this.objectKey,\n UploadId: this.uploadId,\n MultipartUpload: { Parts: this.parts },\n IfNoneMatch: '*', // write-once: fail if the object already exists\n }),\n );\n this.uploadId = undefined; // completed — nothing left to abort\n return { size: this.total, sha256 };\n }\n\n /** Best-effort cleanup of an in-flight multipart upload after an error (a leaked MPU is reaped by a bucket\n * lifecycle rule; never a correctness issue). No-op if nothing was started or it already completed. */\n async abort(): Promise<void> {\n if (this.uploadId === undefined) return;\n const id = this.uploadId;\n this.uploadId = undefined;\n try {\n await this.client.send(\n new AbortMultipartUploadCommand({ Bucket: this.bucket, Key: this.objectKey, UploadId: id }),\n );\n } catch {\n // swallow — best-effort\n }\n }\n}\n\n/**\n * Collect an S3 response body into a `Uint8Array`. `transformToByteArray` is added at runtime to the SDK's\n * Node stream by `@aws-sdk`'s sdk-stream-mixin, so the structural cast is sound on Node.\n */\nasync function collect(body: GetObjectCommandBody): Promise<Uint8Array> {\n if (body === undefined) {\n throw new NotFoundError('S3 GetObject returned an empty body');\n }\n return body.transformToByteArray();\n}\n\n/** The S3 `GetObject` Body type, narrowed to the part we use (`transformToByteArray`). */\ntype GetObjectCommandBody = { transformToByteArray(): Promise<Uint8Array> } | undefined;\n","/**\n * Shared, SDK-free helpers for assembling + validating {@link RegistryRecord}s (Phase 4c).\n *\n * The registry's record-construction, patch-application, and field-validation are identical across every\n * backend (memory / LocalFs / DynamoDB) — only the *storage* + OCC mechanics differ. This is the one home\n * for that logic so the three drivers can't drift. Pure: no I/O, no SDK, no clock (the caller passes `now`).\n */\nimport { IntegrityError, UnsupportedError, ValidationError } from '@/core/errors';\nimport type {\n NewRegistryRecord,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n Token,\n} from '@/core/ports';\n\n/** The valid {@link RegistryStatus} values — used to validate both caller input and stored bytes. */\nconst STATUSES: readonly string[] = ['active', 'compacting', 'erasing', 'destroyed'];\n/** Cap on a serialized governance blob (retention/residency) — bounds row size so a row can't be bricked. */\nconst MAX_GOVERNANCE_BYTES = 64 * 1024;\n/** Bounds on the wrapped-DEK list (one DEK wrapped under a few KEKs) — keeps the row small + rejects abuse. */\nconst MAX_WRAPPED_DEKS = 8;\nconst MAX_WRAPPED_DEK_BYTES = 4 * 1024;\n\nfunction validateGeneration(gen: number): void {\n if (!Number.isInteger(gen) || gen < 0) {\n throw new ValidationError(`currentGen must be a non-negative integer; got ${gen}`);\n }\n}\n\nfunction validateCount(count: number, field = 'dirtyChunkCount'): void {\n if (!Number.isInteger(count) || count < 0) {\n throw new ValidationError(`${field} must be a non-negative integer; got ${count}`);\n }\n}\n\n/** Validate an epoch-ms timestamp (non-negative, finite). */\nfunction validateTimestamp(ms: number, field: string): void {\n if (!Number.isFinite(ms) || ms < 0) {\n throw new ValidationError(`${field} must be a non-negative finite number; got ${ms}`);\n }\n}\n\nfunction validateStatus(status: string): void {\n if (!STATUSES.includes(status)) {\n throw new ValidationError(`status must be one of ${STATUSES.join('/')}; got ${status}`);\n }\n}\n\n/**\n * Validate a governance blob (retention/residency) at the write boundary: it must be JSON-serializable\n * (a `BigInt`/function/circular value fails fast with a typed error instead of a cryptic one deep in a\n * driver) and within a size cap (so an oversized blob can't write a row that's later unreadable — a brick).\n */\nfunction validateGovernance(meta: unknown, field: string): void {\n if (meta === undefined) return;\n let json: string;\n try {\n json = JSON.stringify(meta);\n } catch {\n throw new ValidationError(`${field} must be JSON-serializable`);\n }\n if (json.length > MAX_GOVERNANCE_BYTES) {\n throw new ValidationError(`${field} is ${json.length}B, exceeds cap ${MAX_GOVERNANCE_BYTES}B`);\n }\n}\n\n/**\n * Validate the wrapped-DEK list at the write/read boundary: a bounded array of `{ keyId, wrapped }` with\n * non-empty string fields and a per-entry size cap (so a row can't be bricked, and corrupt bytes are rejected\n * rather than reaching the keystore). `isStored` toggles the error class (write = ValidationError; read =\n * IntegrityError, invariant 5).\n */\nfunction validateWrappedDeks(value: unknown, isStored: boolean): void {\n if (value === undefined) return;\n const fail = (msg: string): never => {\n throw isStored ? new IntegrityError(msg) : new ValidationError(msg);\n };\n if (!Array.isArray(value)) fail('wrappedDeks must be an array');\n const list = value as unknown[];\n if (list.length === 0) fail('wrappedDeks must be non-empty when present');\n if (list.length > MAX_WRAPPED_DEKS)\n fail(`wrappedDeks has ${list.length} entries, cap ${MAX_WRAPPED_DEKS}`);\n for (const w of list) {\n if (w === null || typeof w !== 'object') fail('wrappedDeks entry must be an object');\n const { keyId, wrapped } = w as { keyId?: unknown; wrapped?: unknown };\n if (typeof keyId !== 'string' || keyId.length === 0)\n fail('wrappedDeks entry needs a non-empty keyId');\n if (typeof wrapped !== 'string' || wrapped.length === 0)\n fail('wrappedDeks entry needs a non-empty wrapped blob');\n if ((wrapped as string).length > MAX_WRAPPED_DEK_BYTES)\n fail(`wrappedDeks entry is ${(wrapped as string).length}B, cap ${MAX_WRAPPED_DEK_BYTES}B`);\n }\n}\n\n/** Validate the caller-settable fields at `create`. */\nexport function validateNewRegistryRecord(rec: NewRegistryRecord): void {\n validateGeneration(rec.currentGen);\n if (rec.dirtyChunkCount !== undefined) validateCount(rec.dirtyChunkCount);\n if (rec.status !== undefined) validateStatus(rec.status);\n validateWrappedDeks(rec.wrappedDeks, false);\n validateGovernance(rec.retention, 'retention');\n validateGovernance(rec.residency, 'residency');\n}\n\n/** Validate the caller-settable fields in a `compareAndSwap` patch. */\nexport function validateRegistryPatch(patch: RegistryPatch): void {\n if (patch.currentGen !== undefined) validateGeneration(patch.currentGen);\n if (patch.dirtyChunkCount !== undefined) validateCount(patch.dirtyChunkCount);\n if (patch.consecutiveFailures !== undefined)\n validateCount(patch.consecutiveFailures, 'consecutiveFailures');\n if (patch.lastCompactedAt !== undefined)\n validateTimestamp(patch.lastCompactedAt, 'lastCompactedAt');\n if (patch.status !== undefined) validateStatus(patch.status);\n if ('wrappedDeks' in patch) validateWrappedDeks(patch.wrappedDeks, false);\n if ('retention' in patch) validateGovernance(patch.retention, 'retention');\n if ('residency' in patch) validateGovernance(patch.residency, 'residency');\n}\n\n/**\n * The persisted envelope for a registry row: the record plus a tombstone flag. A **deleted** row keeps its\n * record (with an advanced counter) rather than being removed, so the monotonic token survives a\n * delete→recreate — ABA-safety. Shared by the persistent drivers (LocalFs file, S3 object).\n *\n * `schemaVersion` is a wire-only concern — it stamps the persisted bytes, not the in-memory domain object —\n * so it lives on the serialize/parse boundary ({@link serializeRegistryEnvelope} /\n * {@link parseRegistryEnvelope}), never on this interface.\n */\nexport interface RegistryEnvelope {\n readonly deleted: boolean;\n readonly record: RegistryRecord;\n}\n\n/**\n * Current registry-row schema version — a pre-1.0 format-freeze prerequisite (Phase G, DECISIONS #41). Every persistent\n * registry driver — the LocalFs/S3 `{ deleted, record }` envelope and the DynamoDB body — stamps its rows\n * with this so a reader can fail-closed on a future, incompatible layout instead of misparsing it. Bump only\n * on a backward-incompatible change. Policy: a **higher** stamp than this build knows → `UnsupportedError`\n * (fail-closed); an **absent** stamp → legacy pre-freeze row, tolerated as v1.\n */\nexport const REGISTRY_SCHEMA_VERSION = 1;\n\n/**\n * Validate a persisted registry row's `schemaVersion` (untrusted bytes, invariant 5): absent → legacy v1\n * (tolerated); a malformed value → `IntegrityError`; a version newer than this build → `UnsupportedError`\n * (fail-closed rather than misread a format we don't understand).\n */\nexport function assertRegistrySchemaVersion(raw: unknown, ctx: string): void {\n if (raw === undefined) return; // pre-stamp rows are v1\n if (typeof raw !== 'number' || !Number.isInteger(raw) || raw < 1) {\n throw new IntegrityError(`registry row has a malformed schemaVersion (${String(raw)}): ${ctx}`);\n }\n if (raw > REGISTRY_SCHEMA_VERSION) {\n throw new UnsupportedError(\n `registry row schemaVersion ${raw} is newer than this build reads (v${REGISTRY_SCHEMA_VERSION}): ${ctx}`,\n );\n }\n}\n\n/** Serialize a registry envelope for persistence, stamping the current {@link REGISTRY_SCHEMA_VERSION}. */\nexport function serializeRegistryEnvelope(env: RegistryEnvelope): string {\n return JSON.stringify({\n schemaVersion: REGISTRY_SCHEMA_VERSION,\n deleted: env.deleted,\n record: env.record,\n });\n}\n\n/**\n * The OCC counter encoded in a record's token. A published row always has a **canonical decimal** token\n * (`String(counter)`), so anything else (`\"1e3\"`, `\"0x10\"`, `\" 5 \"`, `\"\"`, a >2^53 value) is corruption /\n * tampering — reject it (invariant 5) rather than let `Number()` coerce it and silently break monotonicity.\n */\nexport function registryCounterOf(record: RegistryRecord): number {\n if (!/^(0|[1-9]\\d*)$/.test(record.token)) {\n throw new IntegrityError(`registry row token is not a canonical counter: ${record.token}`);\n }\n const n = Number(record.token);\n if (!Number.isSafeInteger(n)) {\n throw new IntegrityError(`registry row token is out of safe-integer range: ${record.token}`);\n }\n return n;\n}\n\n/**\n * Parse + structurally validate a persisted `{ deleted, record }` envelope from stored bytes. A published row\n * is always whole (atomic write), so a parse failure or a missing/mistyped field means corruption/tampering —\n * fail fast (invariant 5), never silently report \"absent\". `ctx` names the source (path/key) for the message.\n */\nexport function parseRegistryEnvelope(text: string, ctx: string): RegistryEnvelope {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new IntegrityError(`registry row is not valid JSON: ${ctx}`);\n }\n // Guard before any property access: `JSON.parse` yields `null`/primitives for hostile bytes (e.g. `\"null\"`,\n // `\"5\"`), which would throw an *untyped* TypeError on the dereference below (invariant 5 wants a typed error).\n if (parsed === null || typeof parsed !== 'object') {\n throw new IntegrityError(`registry row has a malformed envelope: ${ctx}`);\n }\n const env = parsed as { schemaVersion?: unknown; deleted?: unknown; record?: unknown };\n assertRegistrySchemaVersion(env.schemaVersion, ctx);\n if (typeof env.deleted !== 'boolean' || env.record === null || typeof env.record !== 'object') {\n throw new IntegrityError(`registry row has a malformed envelope: ${ctx}`);\n }\n const r = env.record as Record<string, unknown>;\n assertStoredRecordShape(r, ctx);\n if (typeof r.token !== 'string') {\n throw new IntegrityError(`registry row is missing its token: ${ctx}`);\n }\n return { deleted: env.deleted, record: env.record as RegistryRecord };\n}\n\n/** Build a full record from a {@link NewRegistryRecord} plus identity, audit timestamps, and an OCC token. */\nexport function recordFromNew(\n ref: SegmentRef,\n rec: NewRegistryRecord,\n now: number,\n token: Token,\n): RegistryRecord {\n return {\n namespace: ref.namespace,\n segment: ref.segment,\n currentGen: rec.currentGen,\n wrappedDeks: rec.wrappedDeks,\n keyId: rec.keyId,\n dirtyChunkCount: rec.dirtyChunkCount ?? 0,\n status: rec.status ?? 'active',\n consecutiveFailures: 0, // daemon health (Phase D); lastCompactedAt stays absent until first compaction\n retention: rec.retention,\n residency: rec.residency,\n createdAt: now,\n updatedAt: now,\n token,\n };\n}\n\n/**\n * Fail-fast structural check on a record read back from a persistent tier (untrusted bytes, invariant 5):\n * a published row is always whole, so a missing/mistyped required field means corruption/tampering — reject\n * it rather than silently report \"absent\". `token` is checked by the caller (its source differs per backend:\n * an in-body field vs a derived OCC counter).\n */\nexport function assertStoredRecordShape(r: Record<string, unknown>, ctx: string): void {\n if (\n typeof r.segment !== 'string' ||\n (r.namespace !== undefined && typeof r.namespace !== 'string') ||\n typeof r.currentGen !== 'number' ||\n typeof r.dirtyChunkCount !== 'number' ||\n typeof r.status !== 'string' ||\n typeof r.createdAt !== 'number' ||\n typeof r.updatedAt !== 'number'\n ) {\n throw new IntegrityError(`registry record is missing required fields: ${ctx}`);\n }\n // Enforce the same value invariants the write path checks, so corrupt/tampered bytes are rejected at the\n // read boundary (invariant 5) rather than leaking a bad currentGen/status downstream.\n if (!Number.isInteger(r.currentGen) || r.currentGen < 0) {\n throw new IntegrityError(`registry record has an invalid currentGen (${r.currentGen}): ${ctx}`);\n }\n if (!Number.isInteger(r.dirtyChunkCount) || r.dirtyChunkCount < 0) {\n throw new IntegrityError(`registry record has an invalid dirtyChunkCount: ${ctx}`);\n }\n if (!STATUSES.includes(r.status)) {\n throw new IntegrityError(`registry record has an unknown status (${r.status}): ${ctx}`);\n }\n if (r.leaseOwner !== undefined && typeof r.leaseOwner !== 'string') {\n throw new IntegrityError(`registry record has an invalid leaseOwner: ${ctx}`);\n }\n if (r.leaseExpiresAt !== undefined && typeof r.leaseExpiresAt !== 'number') {\n throw new IntegrityError(`registry record has an invalid leaseExpiresAt: ${ctx}`);\n }\n if (\n r.consecutiveFailures !== undefined &&\n (!Number.isInteger(r.consecutiveFailures) || (r.consecutiveFailures as number) < 0)\n ) {\n throw new IntegrityError(`registry record has an invalid consecutiveFailures: ${ctx}`);\n }\n if (\n r.lastCompactedAt !== undefined &&\n (typeof r.lastCompactedAt !== 'number' ||\n !Number.isFinite(r.lastCompactedAt) ||\n (r.lastCompactedAt as number) < 0)\n ) {\n throw new IntegrityError(`registry record has an invalid lastCompactedAt: ${ctx}`);\n }\n if (r.keyId !== undefined && typeof r.keyId !== 'string') {\n throw new IntegrityError(`registry record has an invalid keyId: ${ctx}`);\n }\n validateWrappedDeks(r.wrappedDeks, true); // invariant 5: reject a corrupt wrapped-DEK list on read-back\n}\n\n/**\n * Apply a patch to an existing record, returning a new one with a fresh `updatedAt` + `token` (identity and\n * `createdAt` are preserved). Optional fields use `'k' in patch` so a patch can *clear* them (set to\n * `undefined`, e.g. dropping `keyId` on crypto-shred); required fields use `??` (they always have a value).\n */\nexport function applyRegistryPatch(\n prev: RegistryRecord,\n patch: RegistryPatch,\n now: number,\n token: Token,\n): RegistryRecord {\n return {\n namespace: prev.namespace,\n segment: prev.segment,\n currentGen: patch.currentGen ?? prev.currentGen,\n wrappedDeks: 'wrappedDeks' in patch ? patch.wrappedDeks : prev.wrappedDeks,\n keyId: 'keyId' in patch ? patch.keyId : prev.keyId,\n dirtyChunkCount: patch.dirtyChunkCount ?? prev.dirtyChunkCount,\n status: patch.status ?? prev.status,\n leaseOwner: 'leaseOwner' in patch ? patch.leaseOwner : prev.leaseOwner,\n leaseExpiresAt: 'leaseExpiresAt' in patch ? patch.leaseExpiresAt : prev.leaseExpiresAt,\n lastCompactedAt: 'lastCompactedAt' in patch ? patch.lastCompactedAt : prev.lastCompactedAt,\n consecutiveFailures: patch.consecutiveFailures ?? prev.consecutiveFailures ?? 0,\n retention: 'retention' in patch ? patch.retention : prev.retention,\n residency: 'residency' in patch ? patch.residency : prev.residency,\n createdAt: prev.createdAt,\n updatedAt: now,\n token,\n };\n}\n","/**\n * Bounded-concurrency fan-out — the missing primitive for running async work over many items without either\n * a thundering herd (unbounded `Promise.all` → N simultaneous S3/DynamoDB calls) or full serial latency\n * (`for await`). Pure + I/O-free, so it lives in `core/`; callers inject the async work.\n */\n\nimport { ValidationError } from './errors';\n\n/**\n * Run `fn` over `items` with at most `limit` promises in flight at once, returning results in **input order**\n * (regardless of completion order). If any `fn` rejects, the pool stops scheduling new work, lets the in-flight\n * tasks settle, and rejects with the **first** error — callers that must not abort on one failure (e.g. an\n * erasure ledger that records per-item faults) should catch inside `fn` so it never rejects.\n *\n * `items` is a materialized array on purpose: every caller here already enumerates its source (registry list,\n * S3 page, chunk map), so an array keeps the pool trivial and race-free (no shared-iterator hazard).\n */\nexport async function mapWithConcurrency<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n if (!Number.isInteger(limit) || limit < 1) {\n throw new ValidationError(`concurrency limit must be a positive integer; got ${limit}`);\n }\n const results = new Array<R>(items.length);\n let next = 0;\n let failed = false;\n let firstError: unknown;\n const worker = async (): Promise<void> => {\n while (!failed) {\n const i = next++;\n if (i >= items.length) return;\n try {\n results[i] = await fn(items[i]!, i);\n } catch (err) {\n if (!failed) {\n failed = true; // first failure wins; stop scheduling new items (in-flight ones still settle)\n firstError = err;\n }\n return;\n }\n }\n };\n const workers = Array.from({ length: Math.min(limit, items.length) }, () => worker());\n await Promise.all(workers);\n if (failed) throw firstError;\n return results;\n}\n","/**\n * `S3RegistryDriver` — an {@link IRegistryDriver} over S3-compatible object storage (Phase 7).\n *\n * Lets a **read-mostly deployment run on S3 alone** — cold `.crbm` generations + the registry in one bucket,\n * no DynamoDB. One tiny JSON object per segment at `<prefix>registry/<ns>/<segment>.reg` holding the\n * `{ deleted, record }` envelope (the same shape LocalFs persists). The OCC token is a monotonic counter,\n * advanced on every mutation and even across a `delete` (which **tombstones** rather than removes the object)\n * so a deleted-then-recreated row never re-issues an old token (ABA-safe) — identical semantics to the\n * LocalFs + DynamoDB registries, so it passes the same conformance suite.\n *\n * **The atomic swap is offloaded to S3's conditional writes** (GA Nov 2024): `create` uses `If-None-Match: *`\n * (write-once, or `If-Match` over a tombstone), and `compareAndSwap`/`delete` use `If-Match: <etag>` so a\n * concurrent writer between our read and our PUT loses with a `412` → {@link WriteConflictError}. No in-process\n * lock is needed (unlike LocalFs) — the ETag precondition fences writers *across processes*. Reads are\n * strongly consistent (S3, since 2020), satisfying the registry's `strongRead` contract. The client is\n * **injected**, exactly like {@link S3ColdDriver}.\n *\n * **Deployment requirements** (a backend/policy that violates these silently corrupts the registry):\n * - The backend **must honor `If-Match`** (AWS S3; recent MinIO). One that returns ETags but ignores the\n * precondition degrades compare-and-swap to last-write-wins → lost `currentGen` swaps. Verified against real\n * S3 semantics by the MinIO integration lane.\n * - The IAM principal needs **`s3:ListBucket`** on the bucket. Without it, `GetObject` on a missing key returns\n * `403` (not `404`), so the \"absent segment → `null`\" contract (and `create`'s bootstrap read) breaks — and\n * `list()` needs it regardless.\n * - **Do not apply an S3 lifecycle-expiration rule to the `registry/` prefix.** `delete` tombstones (keeps the\n * object with an advanced counter) for ABA-safety; expiring a tombstone would let a recreate reset the token\n * to 0 and re-issue a stale one.\n */\nimport {\n GetObjectCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n type S3Client,\n} from '@aws-sdk/client-s3';\nimport {\n IntegrityError,\n TransientError,\n ValidationError,\n WriteConflictError,\n isWriteConflictError,\n} from '@/core/errors';\nimport type {\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n Token,\n} from '@/core/ports';\nimport {\n applyRegistryPatch,\n parseRegistryEnvelope,\n recordFromNew,\n registryCounterOf,\n serializeRegistryEnvelope,\n validateNewRegistryRecord,\n validateRegistryPatch,\n type RegistryEnvelope,\n} from '../_shared/registry';\nimport { normalizeS3Prefix, parseRegistryKey, registryListPrefix, registryObjectKey } from './keys';\nimport { isConditionalConflict, isNotFound, isTransient } from './s3-errors';\nimport { mapWithConcurrency } from '@/core/concurrency';\n\n/** Defensive cap on a single registry object read from storage, before allocation (rows are tiny; ~1 KB). */\nconst MAX_ROW_BYTES = 1 * 1024 * 1024;\n/** Bounded retry for `delete`'s read→tombstone under cross-process contention (converges; then fails typed). */\nconst MAX_DELETE_ATTEMPTS = 8;\n/** In-flight `readRow` GETs per `list()` page — turns the serial N+1 into one LIST + bounded parallel GETs. */\nconst LIST_READ_CONCURRENCY = 16;\n\n/** A conditional-write precondition: exactly one of write-once (`If-None-Match: *`) or CAS (`If-Match: etag`). */\ntype PutCondition = { readonly ifNoneMatch: '*' } | { readonly ifMatch: string };\n\nexport interface S3RegistryDriverOptions {\n /** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */\n readonly client: S3Client;\n /** Target bucket (must already exist). */\n readonly bucket: string;\n /** Optional key prefix under which all registry objects live (e.g. `cloudroaring/`). */\n readonly prefix?: string;\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\nexport class S3RegistryDriver implements IRegistryDriver {\n private readonly client: S3Client;\n private readonly bucket: string;\n private readonly prefix: string | undefined;\n private readonly now: () => number;\n\n constructor(options: S3RegistryDriverOptions) {\n this.client = options.client;\n this.bucket = options.bucket;\n this.prefix = normalizeS3Prefix(options.prefix);\n this.now = options.now ?? ((): number => Date.now());\n }\n\n capabilities(): RegCaps {\n return { strongRead: true };\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n const current = await this.readRow(registryObjectKey(this.prefix, ref));\n return current && !current.env.deleted ? current.env.record : null;\n }\n\n async create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n validateNewRegistryRecord(record);\n const key = registryObjectKey(this.prefix, ref);\n const current = await this.readRow(key);\n if (current !== null && !current.env.deleted) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n // Advance across a tombstone so a recreate never re-issues an old token (ABA-safe).\n const token = String(current ? registryCounterOf(current.env.record) + 1 : 0);\n const env: RegistryEnvelope = {\n deleted: false,\n record: recordFromNew(ref, record, this.now(), token),\n };\n // Write-once when truly absent; overwrite the tombstone under its ETag when recreating. Either way a\n // concurrent create loses with a 412 → WriteConflictError.\n await this.putRow(key, env, current ? { ifMatch: current.etag } : { ifNoneMatch: '*' });\n return { token };\n }\n\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n validateRegistryPatch(patch);\n const key = registryObjectKey(this.prefix, ref);\n const current = await this.readRow(key);\n if (current === null || current.env.deleted || current.env.record.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = String(registryCounterOf(current.env.record) + 1);\n const env: RegistryEnvelope = {\n deleted: false,\n record: applyRegistryPatch(current.env.record, patch, this.now(), token),\n };\n // If-Match on the ETag we read fences a concurrent writer between our read and this PUT (412 → conflict).\n await this.putRow(key, env, { ifMatch: current.etag });\n return { token };\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n const prefix = registryListPrefix(this.prefix, namespace);\n let token: string | undefined;\n do {\n let res;\n try {\n res = await this.client.send(\n new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n ContinuationToken: token,\n }),\n );\n } catch (err) {\n throw this.mapError(err);\n }\n // Registry keys in this page (skipping stray/foreign objects). `readRow` is one GET each — a serial\n // await-in-loop made `list()` O(N) sequential round-trips (the N+1). Fan them out with a bounded pool:\n // one LIST + up to `LIST_READ_CONCURRENCY` parallel GETs per page, order-preserving so the yielded\n // stream stays deterministic.\n const keys = (res.Contents ?? [])\n .map((obj) => obj.Key)\n .filter((k): k is string => k !== undefined && parseRegistryKey(this.prefix, k) !== null);\n const rows = await mapWithConcurrency(keys, LIST_READ_CONCURRENCY, (key) =>\n this.readRow(key),\n );\n for (const current of rows) {\n if (current && !current.env.deleted) yield current.env.record;\n }\n token = res.IsTruncated === true ? res.NextContinuationToken : undefined;\n } while (token !== undefined);\n }\n\n async delete(ref: SegmentRef): Promise<void> {\n const key = registryObjectKey(this.prefix, ref);\n // Tombstone (advance the counter) rather than remove the object — keeps the token monotonic for\n // ABA-safety. Retry the read→tombstone on a cross-process race (a concurrent write bumps the ETag → 412);\n // it converges, then fails typed rather than silently leaving the row live.\n for (let attempt = 0; attempt < MAX_DELETE_ATTEMPTS; attempt++) {\n const current = await this.readRow(key);\n if (current === null || current.env.deleted) return; // idempotent — already gone\n const token = String(registryCounterOf(current.env.record) + 1);\n const env: RegistryEnvelope = {\n deleted: true,\n record: { ...current.env.record, token, updatedAt: this.now() },\n };\n try {\n await this.putRow(key, env, { ifMatch: current.etag });\n return;\n } catch (err) {\n if (isWriteConflictError(err)) continue; // raced — re-read and re-tombstone\n throw err;\n }\n }\n throw new WriteConflictError(\n `registry delete: contention tombstoning \"${ref.segment}\" — retry`,\n );\n }\n\n /** GET + parse a registry object, returning its envelope + ETag (for a later If-Match), or null if absent. */\n private async readRow(\n objectKey: string,\n ): Promise<{ env: RegistryEnvelope; etag: string } | null> {\n let res;\n try {\n res = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: objectKey }));\n } catch (err) {\n if (isNotFound(err)) return null;\n throw this.mapError(err);\n }\n if ((res.ContentLength ?? 0) > MAX_ROW_BYTES) {\n throw new IntegrityError(\n `registry object ${res.ContentLength}B exceeds cap ${MAX_ROW_BYTES}B`,\n );\n }\n if (res.Body === undefined) {\n throw new IntegrityError(`registry object has an empty body: ${objectKey}`);\n }\n const bytes = await (\n res.Body as { transformToByteArray(): Promise<Uint8Array> }\n ).transformToByteArray();\n if (bytes.length > MAX_ROW_BYTES) {\n throw new IntegrityError(`registry object ${bytes.length}B exceeds cap ${MAX_ROW_BYTES}B`);\n }\n const env = parseRegistryEnvelope(Buffer.from(bytes).toString('utf8'), objectKey);\n if (res.ETag === undefined || res.ETag.length === 0) {\n // The ETag is the OCC fence for CAS; a backend that omits it can't be used safely as a registry.\n throw new IntegrityError(\n `registry object has no ETag (needed for compare-and-swap): ${objectKey}`,\n );\n }\n return { env, etag: res.ETag };\n }\n\n /** Conditional PUT of an envelope; maps a `412` precondition failure to {@link WriteConflictError}. */\n private async putRow(\n objectKey: string,\n env: RegistryEnvelope,\n cond: PutCondition,\n ): Promise<void> {\n const Body = Buffer.from(serializeRegistryEnvelope(env), 'utf8');\n if (Body.length > MAX_ROW_BYTES) {\n // Belt-and-braces: the governance/DEK fields are already capped by validate*, so this can't fire for\n // valid input — but never write a row that would later be unreadable.\n throw new ValidationError(`registry object ${Body.length}B exceeds cap ${MAX_ROW_BYTES}B`);\n }\n try {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: objectKey,\n Body,\n ContentType: 'application/json',\n IfNoneMatch: 'ifNoneMatch' in cond ? cond.ifNoneMatch : undefined,\n IfMatch: 'ifMatch' in cond ? cond.ifMatch : undefined,\n }),\n );\n } catch (err) {\n // A lost conditional-write race (412 precondition, or 409 concurrent-conflict) is an OCC conflict.\n if (isConditionalConflict(err)) {\n throw new WriteConflictError(`registry OCC conflict for ${objectKey}`);\n }\n throw this.mapError(err);\n }\n }\n\n /** Reclassify a transient S3 fault as a retryable {@link TransientError}; pass everything else through. */\n private mapError(err: unknown): unknown {\n if (isTransient(err)) {\n return new TransientError(\n `transient S3 fault: ${(err as { name?: string } | null)?.name ?? 'unknown'}`,\n { cause: err },\n );\n }\n return err;\n }\n}\n"]}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { I as IColdDriver, C as ColdCaps, G as GenKey, B as BlobSink, S as SegmentRef, d as IRegistryDriver, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch } from '../ports-D3BrJ6ax.cjs';
|
|
3
|
+
|
|
4
|
+
interface S3ColdDriverOptions {
|
|
5
|
+
/** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
|
|
6
|
+
readonly client: S3Client;
|
|
7
|
+
/** Target bucket (must already exist). */
|
|
8
|
+
readonly bucket: string;
|
|
9
|
+
/** Optional key prefix under which all objects live (e.g. `cloudroaring/`). */
|
|
10
|
+
readonly prefix?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Largest object this driver will write/advertise. Default = `partBytes × 10,000` (≈ 80 GiB at the default
|
|
13
|
+
* 8 MiB part) — the honest ceiling reachable within S3's 10,000-part limit. Set it higher and `partBytes`
|
|
14
|
+
* auto-grows so 10,000 parts still cover it (raising peak write memory to ~one part); up to the 5 TiB S3 max.
|
|
15
|
+
*/
|
|
16
|
+
readonly maxObjectBytes?: number;
|
|
17
|
+
/** Multipart part size in bytes (default 8 MiB; clamped to the S3 5 MiB minimum). Tunes peak write memory. */
|
|
18
|
+
readonly partBytes?: number;
|
|
19
|
+
}
|
|
20
|
+
declare class S3ColdDriver implements IColdDriver {
|
|
21
|
+
private readonly client;
|
|
22
|
+
private readonly bucket;
|
|
23
|
+
private readonly prefix;
|
|
24
|
+
private readonly maxObjectBytes;
|
|
25
|
+
private readonly partBytes;
|
|
26
|
+
constructor(options: S3ColdDriverOptions);
|
|
27
|
+
capabilities(): ColdCaps;
|
|
28
|
+
putImmutable(key: GenKey, write: (sink: BlobSink) => Promise<void>): Promise<{
|
|
29
|
+
size: number;
|
|
30
|
+
sha256: string;
|
|
31
|
+
}>;
|
|
32
|
+
getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;
|
|
33
|
+
getTail(key: GenKey, maxBytes: number): Promise<{
|
|
34
|
+
bytes: Uint8Array;
|
|
35
|
+
size: number;
|
|
36
|
+
}>;
|
|
37
|
+
delete(key: GenKey): Promise<void>;
|
|
38
|
+
list(ref: SegmentRef): AsyncIterable<GenKey>;
|
|
39
|
+
/** Map S3 read errors to the driver vocabulary; pass everything else through {@link mapError}. */
|
|
40
|
+
private mapReadError;
|
|
41
|
+
/**
|
|
42
|
+
* Reclassify a transient S3 fault (throttle/5xx/dropped connection) as a retryable {@link TransientError}
|
|
43
|
+
* so the retry decorator can ride it out; everything else propagates unchanged. The final fallback at every
|
|
44
|
+
* `client.send` site, so callers and the decorator only ever see typed errors.
|
|
45
|
+
*/
|
|
46
|
+
private mapError;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `S3RegistryDriver` — an {@link IRegistryDriver} over S3-compatible object storage (Phase 7).
|
|
51
|
+
*
|
|
52
|
+
* Lets a **read-mostly deployment run on S3 alone** — cold `.crbm` generations + the registry in one bucket,
|
|
53
|
+
* no DynamoDB. One tiny JSON object per segment at `<prefix>registry/<ns>/<segment>.reg` holding the
|
|
54
|
+
* `{ deleted, record }` envelope (the same shape LocalFs persists). The OCC token is a monotonic counter,
|
|
55
|
+
* advanced on every mutation and even across a `delete` (which **tombstones** rather than removes the object)
|
|
56
|
+
* so a deleted-then-recreated row never re-issues an old token (ABA-safe) — identical semantics to the
|
|
57
|
+
* LocalFs + DynamoDB registries, so it passes the same conformance suite.
|
|
58
|
+
*
|
|
59
|
+
* **The atomic swap is offloaded to S3's conditional writes** (GA Nov 2024): `create` uses `If-None-Match: *`
|
|
60
|
+
* (write-once, or `If-Match` over a tombstone), and `compareAndSwap`/`delete` use `If-Match: <etag>` so a
|
|
61
|
+
* concurrent writer between our read and our PUT loses with a `412` → {@link WriteConflictError}. No in-process
|
|
62
|
+
* lock is needed (unlike LocalFs) — the ETag precondition fences writers *across processes*. Reads are
|
|
63
|
+
* strongly consistent (S3, since 2020), satisfying the registry's `strongRead` contract. The client is
|
|
64
|
+
* **injected**, exactly like {@link S3ColdDriver}.
|
|
65
|
+
*
|
|
66
|
+
* **Deployment requirements** (a backend/policy that violates these silently corrupts the registry):
|
|
67
|
+
* - The backend **must honor `If-Match`** (AWS S3; recent MinIO). One that returns ETags but ignores the
|
|
68
|
+
* precondition degrades compare-and-swap to last-write-wins → lost `currentGen` swaps. Verified against real
|
|
69
|
+
* S3 semantics by the MinIO integration lane.
|
|
70
|
+
* - The IAM principal needs **`s3:ListBucket`** on the bucket. Without it, `GetObject` on a missing key returns
|
|
71
|
+
* `403` (not `404`), so the "absent segment → `null`" contract (and `create`'s bootstrap read) breaks — and
|
|
72
|
+
* `list()` needs it regardless.
|
|
73
|
+
* - **Do not apply an S3 lifecycle-expiration rule to the `registry/` prefix.** `delete` tombstones (keeps the
|
|
74
|
+
* object with an advanced counter) for ABA-safety; expiring a tombstone would let a recreate reset the token
|
|
75
|
+
* to 0 and re-issue a stale one.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
interface S3RegistryDriverOptions {
|
|
79
|
+
/** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
|
|
80
|
+
readonly client: S3Client;
|
|
81
|
+
/** Target bucket (must already exist). */
|
|
82
|
+
readonly bucket: string;
|
|
83
|
+
/** Optional key prefix under which all registry objects live (e.g. `cloudroaring/`). */
|
|
84
|
+
readonly prefix?: string;
|
|
85
|
+
/** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */
|
|
86
|
+
readonly now?: () => number;
|
|
87
|
+
}
|
|
88
|
+
declare class S3RegistryDriver implements IRegistryDriver {
|
|
89
|
+
private readonly client;
|
|
90
|
+
private readonly bucket;
|
|
91
|
+
private readonly prefix;
|
|
92
|
+
private readonly now;
|
|
93
|
+
constructor(options: S3RegistryDriverOptions);
|
|
94
|
+
capabilities(): RegCaps;
|
|
95
|
+
get(ref: SegmentRef): Promise<RegistryRecord | null>;
|
|
96
|
+
create(ref: SegmentRef, record: NewRegistryRecord): Promise<{
|
|
97
|
+
token: Token;
|
|
98
|
+
}>;
|
|
99
|
+
compareAndSwap(ref: SegmentRef, expected: Token, patch: RegistryPatch): Promise<{
|
|
100
|
+
token: Token;
|
|
101
|
+
}>;
|
|
102
|
+
list(namespace?: string): AsyncIterable<RegistryRecord>;
|
|
103
|
+
delete(ref: SegmentRef): Promise<void>;
|
|
104
|
+
/** GET + parse a registry object, returning its envelope + ETag (for a later If-Match), or null if absent. */
|
|
105
|
+
private readRow;
|
|
106
|
+
/** Conditional PUT of an envelope; maps a `412` precondition failure to {@link WriteConflictError}. */
|
|
107
|
+
private putRow;
|
|
108
|
+
/** Reclassify a transient S3 fault as a retryable {@link TransientError}; pass everything else through. */
|
|
109
|
+
private mapError;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { S3ColdDriver, type S3ColdDriverOptions, S3RegistryDriver, type S3RegistryDriverOptions };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { I as IColdDriver, C as ColdCaps, G as GenKey, B as BlobSink, S as SegmentRef, d as IRegistryDriver, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch } from '../ports-D3BrJ6ax.js';
|
|
3
|
+
|
|
4
|
+
interface S3ColdDriverOptions {
|
|
5
|
+
/** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
|
|
6
|
+
readonly client: S3Client;
|
|
7
|
+
/** Target bucket (must already exist). */
|
|
8
|
+
readonly bucket: string;
|
|
9
|
+
/** Optional key prefix under which all objects live (e.g. `cloudroaring/`). */
|
|
10
|
+
readonly prefix?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Largest object this driver will write/advertise. Default = `partBytes × 10,000` (≈ 80 GiB at the default
|
|
13
|
+
* 8 MiB part) — the honest ceiling reachable within S3's 10,000-part limit. Set it higher and `partBytes`
|
|
14
|
+
* auto-grows so 10,000 parts still cover it (raising peak write memory to ~one part); up to the 5 TiB S3 max.
|
|
15
|
+
*/
|
|
16
|
+
readonly maxObjectBytes?: number;
|
|
17
|
+
/** Multipart part size in bytes (default 8 MiB; clamped to the S3 5 MiB minimum). Tunes peak write memory. */
|
|
18
|
+
readonly partBytes?: number;
|
|
19
|
+
}
|
|
20
|
+
declare class S3ColdDriver implements IColdDriver {
|
|
21
|
+
private readonly client;
|
|
22
|
+
private readonly bucket;
|
|
23
|
+
private readonly prefix;
|
|
24
|
+
private readonly maxObjectBytes;
|
|
25
|
+
private readonly partBytes;
|
|
26
|
+
constructor(options: S3ColdDriverOptions);
|
|
27
|
+
capabilities(): ColdCaps;
|
|
28
|
+
putImmutable(key: GenKey, write: (sink: BlobSink) => Promise<void>): Promise<{
|
|
29
|
+
size: number;
|
|
30
|
+
sha256: string;
|
|
31
|
+
}>;
|
|
32
|
+
getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;
|
|
33
|
+
getTail(key: GenKey, maxBytes: number): Promise<{
|
|
34
|
+
bytes: Uint8Array;
|
|
35
|
+
size: number;
|
|
36
|
+
}>;
|
|
37
|
+
delete(key: GenKey): Promise<void>;
|
|
38
|
+
list(ref: SegmentRef): AsyncIterable<GenKey>;
|
|
39
|
+
/** Map S3 read errors to the driver vocabulary; pass everything else through {@link mapError}. */
|
|
40
|
+
private mapReadError;
|
|
41
|
+
/**
|
|
42
|
+
* Reclassify a transient S3 fault (throttle/5xx/dropped connection) as a retryable {@link TransientError}
|
|
43
|
+
* so the retry decorator can ride it out; everything else propagates unchanged. The final fallback at every
|
|
44
|
+
* `client.send` site, so callers and the decorator only ever see typed errors.
|
|
45
|
+
*/
|
|
46
|
+
private mapError;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `S3RegistryDriver` — an {@link IRegistryDriver} over S3-compatible object storage (Phase 7).
|
|
51
|
+
*
|
|
52
|
+
* Lets a **read-mostly deployment run on S3 alone** — cold `.crbm` generations + the registry in one bucket,
|
|
53
|
+
* no DynamoDB. One tiny JSON object per segment at `<prefix>registry/<ns>/<segment>.reg` holding the
|
|
54
|
+
* `{ deleted, record }` envelope (the same shape LocalFs persists). The OCC token is a monotonic counter,
|
|
55
|
+
* advanced on every mutation and even across a `delete` (which **tombstones** rather than removes the object)
|
|
56
|
+
* so a deleted-then-recreated row never re-issues an old token (ABA-safe) — identical semantics to the
|
|
57
|
+
* LocalFs + DynamoDB registries, so it passes the same conformance suite.
|
|
58
|
+
*
|
|
59
|
+
* **The atomic swap is offloaded to S3's conditional writes** (GA Nov 2024): `create` uses `If-None-Match: *`
|
|
60
|
+
* (write-once, or `If-Match` over a tombstone), and `compareAndSwap`/`delete` use `If-Match: <etag>` so a
|
|
61
|
+
* concurrent writer between our read and our PUT loses with a `412` → {@link WriteConflictError}. No in-process
|
|
62
|
+
* lock is needed (unlike LocalFs) — the ETag precondition fences writers *across processes*. Reads are
|
|
63
|
+
* strongly consistent (S3, since 2020), satisfying the registry's `strongRead` contract. The client is
|
|
64
|
+
* **injected**, exactly like {@link S3ColdDriver}.
|
|
65
|
+
*
|
|
66
|
+
* **Deployment requirements** (a backend/policy that violates these silently corrupts the registry):
|
|
67
|
+
* - The backend **must honor `If-Match`** (AWS S3; recent MinIO). One that returns ETags but ignores the
|
|
68
|
+
* precondition degrades compare-and-swap to last-write-wins → lost `currentGen` swaps. Verified against real
|
|
69
|
+
* S3 semantics by the MinIO integration lane.
|
|
70
|
+
* - The IAM principal needs **`s3:ListBucket`** on the bucket. Without it, `GetObject` on a missing key returns
|
|
71
|
+
* `403` (not `404`), so the "absent segment → `null`" contract (and `create`'s bootstrap read) breaks — and
|
|
72
|
+
* `list()` needs it regardless.
|
|
73
|
+
* - **Do not apply an S3 lifecycle-expiration rule to the `registry/` prefix.** `delete` tombstones (keeps the
|
|
74
|
+
* object with an advanced counter) for ABA-safety; expiring a tombstone would let a recreate reset the token
|
|
75
|
+
* to 0 and re-issue a stale one.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
interface S3RegistryDriverOptions {
|
|
79
|
+
/** A constructed S3 client (point its `endpoint` at MinIO for local/integration use). */
|
|
80
|
+
readonly client: S3Client;
|
|
81
|
+
/** Target bucket (must already exist). */
|
|
82
|
+
readonly bucket: string;
|
|
83
|
+
/** Optional key prefix under which all registry objects live (e.g. `cloudroaring/`). */
|
|
84
|
+
readonly prefix?: string;
|
|
85
|
+
/** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */
|
|
86
|
+
readonly now?: () => number;
|
|
87
|
+
}
|
|
88
|
+
declare class S3RegistryDriver implements IRegistryDriver {
|
|
89
|
+
private readonly client;
|
|
90
|
+
private readonly bucket;
|
|
91
|
+
private readonly prefix;
|
|
92
|
+
private readonly now;
|
|
93
|
+
constructor(options: S3RegistryDriverOptions);
|
|
94
|
+
capabilities(): RegCaps;
|
|
95
|
+
get(ref: SegmentRef): Promise<RegistryRecord | null>;
|
|
96
|
+
create(ref: SegmentRef, record: NewRegistryRecord): Promise<{
|
|
97
|
+
token: Token;
|
|
98
|
+
}>;
|
|
99
|
+
compareAndSwap(ref: SegmentRef, expected: Token, patch: RegistryPatch): Promise<{
|
|
100
|
+
token: Token;
|
|
101
|
+
}>;
|
|
102
|
+
list(namespace?: string): AsyncIterable<RegistryRecord>;
|
|
103
|
+
delete(ref: SegmentRef): Promise<void>;
|
|
104
|
+
/** GET + parse a registry object, returning its envelope + ETag (for a later If-Match), or null if absent. */
|
|
105
|
+
private readRow;
|
|
106
|
+
/** Conditional PUT of an envelope; maps a `412` precondition failure to {@link WriteConflictError}. */
|
|
107
|
+
private putRow;
|
|
108
|
+
/** Reclassify a transient S3 fault as a retryable {@link TransientError}; pass everything else through. */
|
|
109
|
+
private mapError;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { S3ColdDriver, type S3ColdDriverOptions, S3RegistryDriver, type S3RegistryDriverOptions };
|