@cloudbitmaps/core 0.18.3 → 0.19.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.
Files changed (38) hide show
  1. package/dist/{chunk-ML6AT53O.js → chunk-TNWTIAON.js} +50 -9
  2. package/dist/chunk-TNWTIAON.js.map +7 -0
  3. package/dist/core/audit.d.ts +13 -3
  4. package/dist/core/bit-route.d.ts +5 -5
  5. package/dist/core/blob.d.ts +4 -1
  6. package/dist/core/budget.d.ts +7 -2
  7. package/dist/core/combine-feed.d.ts +3 -7
  8. package/dist/core/combine-many.d.ts +22 -29
  9. package/dist/core/consistency.d.ts +0 -1
  10. package/dist/core/cost.d.ts +13 -2
  11. package/dist/core/crbm/reader.d.ts +4 -3
  12. package/dist/core/crbm-storage-source.d.ts +86 -13
  13. package/dist/core/discover.d.ts +3 -5
  14. package/dist/core/engine.d.ts +15 -0
  15. package/dist/core/erase-id.d.ts +7 -5
  16. package/dist/core/erasure.d.ts +22 -2
  17. package/dist/core/errors.d.ts +10 -2
  18. package/dist/core/load-input.d.ts +1 -2
  19. package/dist/core/load.d.ts +48 -3
  20. package/dist/core/metrics.d.ts +19 -7
  21. package/dist/core/ports.d.ts +21 -62
  22. package/dist/core/retention-sweep.d.ts +9 -4
  23. package/dist/core/retention.d.ts +17 -0
  24. package/dist/core/retry.d.ts +6 -0
  25. package/dist/driver-kit.d.ts +1 -1
  26. package/dist/driver-kit.js +8 -101
  27. package/dist/driver-kit.js.map +2 -2
  28. package/dist/drivers/_shared/object-registry.d.ts +1 -19
  29. package/dist/drivers/_shared/registry.d.ts +5 -2
  30. package/dist/drivers/localfs/fs-util.d.ts +7 -0
  31. package/dist/drivers/localfs/registry.d.ts +1 -0
  32. package/dist/index.d.ts +5 -9
  33. package/dist/index.js +864 -600
  34. package/dist/index.js.map +4 -4
  35. package/package.json +1 -1
  36. package/dist/chunk-ML6AT53O.js.map +0 -7
  37. package/dist/core/combine-held.d.ts +0 -43
  38. package/dist/core/registry-reap.d.ts +0 -22
@@ -1,12 +1,13 @@
1
1
  // src/core/errors.ts
2
2
  var ERROR_BRAND = /* @__PURE__ */ Symbol.for("cloudbitmaps.error");
3
3
  var TRANSIENT_BRAND = /* @__PURE__ */ Symbol.for("cloudbitmaps.error.transient");
4
+ var NAMES = /* @__PURE__ */ new WeakMap();
4
5
  var CloudRoaringError = class extends Error {
5
6
  /** Cross-bundle brand — see the predicates ({@link isCloudRoaringError}, …). Non-enumerable-ish (symbol key ⇒ not in JSON). */
6
7
  [ERROR_BRAND] = true;
7
8
  constructor(message) {
8
9
  super(message);
9
- this.name = new.target.name;
10
+ this.name = NAMES.get(new.target) ?? new.target.name;
10
11
  }
11
12
  };
12
13
  var ValidationError = class extends CloudRoaringError {
@@ -58,6 +59,19 @@ var TransientError = class extends CloudRoaringError {
58
59
  if (options && "cause" in options) this.cause = options.cause;
59
60
  }
60
61
  };
62
+ NAMES.set(CloudRoaringError, "CloudRoaringError");
63
+ NAMES.set(ValidationError, "ValidationError");
64
+ NAMES.set(WriteConflictError, "WriteConflictError");
65
+ NAMES.set(IntegrityError, "IntegrityError");
66
+ NAMES.set(NotFoundError, "NotFoundError");
67
+ NAMES.set(LeaseExpiredError, "LeaseExpiredError");
68
+ NAMES.set(LeaseLimitError, "LeaseLimitError");
69
+ NAMES.set(StaleOperandError, "StaleOperandError");
70
+ NAMES.set(UnsupportedError, "UnsupportedError");
71
+ NAMES.set(CapabilityError, "CapabilityError");
72
+ NAMES.set(BudgetExceededError, "BudgetExceededError");
73
+ NAMES.set(KeyUnavailableError, "KeyUnavailableError");
74
+ NAMES.set(TransientError, "TransientError");
61
75
  function hasBrand(err, brand) {
62
76
  return typeof err === "object" && err !== null && err[brand] === true;
63
77
  }
@@ -88,6 +102,18 @@ function isIntegrityError(err) {
88
102
  function isValidationError(err) {
89
103
  return isCloudRoaringError(err) && err.name === "ValidationError";
90
104
  }
105
+ function isUnsupportedError(err) {
106
+ return isCloudRoaringError(err) && err.name === "UnsupportedError";
107
+ }
108
+ function isCapabilityError(err) {
109
+ return isCloudRoaringError(err) && err.name === "CapabilityError";
110
+ }
111
+ function isBudgetExceededError(err) {
112
+ return isCloudRoaringError(err) && err.name === "BudgetExceededError";
113
+ }
114
+ function isKeyUnavailableError(err) {
115
+ return isCloudRoaringError(err) && err.name === "KeyUnavailableError";
116
+ }
91
117
 
92
118
  // src/core/name-codec.ts
93
119
  var KEY_SAFE = /[A-Za-z0-9._:-]/;
@@ -854,7 +880,7 @@ function assertRegistrySchemaVersion(raw, ctx) {
854
880
  throw new IntegrityError(`registry row has no schemaVersion: ${ctx}`);
855
881
  }
856
882
  if (typeof raw !== "number" || !Number.isInteger(raw) || raw < OLDEST_REGISTRY_SCHEMA_VERSION) {
857
- throw new IntegrityError(`registry row has a malformed schemaVersion (${String(raw)}): ${ctx}`);
883
+ throw new IntegrityError(`registry row has a malformed schemaVersion (${shown(raw)}): ${ctx}`);
858
884
  }
859
885
  if (raw > REGISTRY_SCHEMA_VERSION) {
860
886
  throw new UnsupportedError(
@@ -880,7 +906,7 @@ function tokenParts(token, schemaVersion, ctx) {
880
906
  const match = bare ?? written;
881
907
  if (match === null) {
882
908
  throw new IntegrityError(
883
- `registry row token is not one a schema-${schemaVersion ?? REGISTRY_SCHEMA_VERSION} row holds (${JSON.stringify(token)}): ${ctx}`
909
+ `registry row token is not one a schema-${schemaVersion ?? REGISTRY_SCHEMA_VERSION} row holds (${shown(JSON.stringify(token))}): ${ctx}`
884
910
  );
885
911
  }
886
912
  const born = match.length === 4;
@@ -916,7 +942,11 @@ function newIncarnationToken(entropy, tombstone) {
916
942
  const counter = tombstone === void 0 ? 0 : tokenParts(tombstone.token, void 0, tombstone.segment).counter + 1;
917
943
  return `${drawIncarnation(entropy)}.${counter}.${drawWrite(entropy)}`;
918
944
  }
919
- function parseRegistryEnvelope(text, ctx) {
945
+ function shown(v) {
946
+ const text = String(v);
947
+ return text.length > 64 ? `${text.slice(0, 64)}\u2026` : text;
948
+ }
949
+ function parseRegistryEnvelope(text, ctx, expected) {
920
950
  let parsed;
921
951
  try {
922
952
  parsed = JSON.parse(text);
@@ -931,7 +961,7 @@ function parseRegistryEnvelope(text, ctx) {
931
961
  const extra = Object.keys(env).filter((k) => !ENVELOPE_FIELDS.includes(k));
932
962
  if (extra.length > 0) {
933
963
  throw new IntegrityError(
934
- `registry row has fields its envelope does not declare (${extra.join(", ")}): ${ctx}`
964
+ `registry row has fields its envelope does not declare (${shown(extra.join(", "))}): ${ctx}`
935
965
  );
936
966
  }
937
967
  if (typeof env.deleted !== "boolean" || env.record === null || typeof env.record !== "object") {
@@ -943,6 +973,11 @@ function parseRegistryEnvelope(text, ctx) {
943
973
  throw new IntegrityError(`registry row is missing its token: ${ctx}`);
944
974
  }
945
975
  tokenParts(r.token, schemaVersion, ctx);
976
+ if (expected !== void 0 && (r.segment !== expected.segment || (r.namespace ?? void 0) !== (expected.namespace ?? void 0))) {
977
+ throw new IntegrityError(
978
+ `registry row names another segment than the one it is stored for: ${ctx}`
979
+ );
980
+ }
946
981
  return { deleted: env.deleted, record: env.record };
947
982
  }
948
983
  function recordFromNew(ref, rec, now, token) {
@@ -969,16 +1004,18 @@ function assertStoredRecordShape(r, ctx, schemaVersion = REGISTRY_SCHEMA_VERSION
969
1004
  throw new IntegrityError(`registry record is missing required fields: ${ctx}`);
970
1005
  }
971
1006
  if (r.currentGen !== null && (!Number.isSafeInteger(r.currentGen) || r.currentGen < 0)) {
972
- throw new IntegrityError(`registry record has an invalid currentGen (${r.currentGen}): ${ctx}`);
1007
+ throw new IntegrityError(
1008
+ `registry record has an invalid currentGen (${shown(r.currentGen)}): ${ctx}`
1009
+ );
973
1010
  }
974
1011
  if (!STATUSES.includes(r.status)) {
975
- throw new IntegrityError(`registry record has an unknown status (${r.status}): ${ctx}`);
1012
+ throw new IntegrityError(`registry record has an unknown status (${shown(r.status)}): ${ctx}`);
976
1013
  }
977
1014
  const declared = fieldsOf(schemaVersion);
978
1015
  const extra = Object.keys(r).filter((k) => !declared.includes(k));
979
1016
  if (extra.length > 0) {
980
1017
  throw new IntegrityError(
981
- `registry record has fields a schema-${schemaVersion} row does not declare (${extra.join(", ")}): ${ctx}`
1018
+ `registry record has fields a schema-${schemaVersion} row does not declare (${shown(extra.join(", "))}): ${ctx}`
982
1019
  );
983
1020
  }
984
1021
  if (r.keyId !== void 0 && typeof r.keyId !== "string") {
@@ -1084,6 +1121,10 @@ export {
1084
1121
  isNotFoundError,
1085
1122
  isIntegrityError,
1086
1123
  isValidationError,
1124
+ isUnsupportedError,
1125
+ isCapabilityError,
1126
+ isBudgetExceededError,
1127
+ isKeyUnavailableError,
1087
1128
  encodeNameForKey,
1088
1129
  decodeNameFromKey,
1089
1130
  encodeNameForPath,
@@ -1137,4 +1178,4 @@ export {
1137
1178
  namespaceKeyPart,
1138
1179
  namespacePathPart
1139
1180
  };
1140
- //# sourceMappingURL=chunk-ML6AT53O.js.map
1181
+ //# sourceMappingURL=chunk-TNWTIAON.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/errors.ts", "../src/core/name-codec.ts", "../src/core/token.ts", "../src/core/leases.ts", "../src/core/validate.ts", "../src/core/concurrency.ts", "../src/core/ports.ts", "../src/drivers/_shared/keys.ts", "../src/core/kept-generations.ts", "../src/core/metadata.ts", "../src/drivers/_shared/registry.ts", "../src/drivers/_shared/entropy.ts"],
4
+ "sourcesContent": ["/**\n * Typed errors \u2014 callers learn *why* something failed, never by parsing strings. Retry is not the engine's job: a\n * driver classifies its backend's failures into this vocabulary, and the store's read wrapper retries the\n * transient ones through `withRetry`.\n */\n\n/**\n * Registry-symbol brands, so an error stays classifiable when the class object is not shared.\n *\n * In an ordinary install there is ONE copy of these classes and `instanceof` holds everywhere \u2014 across the\n * flavor, the driver packages and core itself \u2014 because every package leaves `@cloudbitmaps/*` external and\n * resolves core at runtime rather than inlining it.\n *\n * What still breaks it is a SECOND copy: a version skew between our packages that the installer could not\n * dedupe, or a bundler that emits core twice. Then a driver throws a class the catching side's `instanceof`\n * does not match \u2014 and silently, because a `catch` that stops matching just falls through, defeating\n * transient retry and the publish path's conflict handling with no error of its own.\n *\n * `Symbol.for` is identity-stable across copies, bundles and realms, so classify errors with the exported\n * predicates below (never `instanceof`) anywhere an error may cross that boundary.\n */\nconst ERROR_BRAND: unique symbol = Symbol.for('cloudbitmaps.error');\nconst TRANSIENT_BRAND: unique symbol = Symbol.for('cloudbitmaps.error.transient');\n\n/**\n * Each class's name as written. A minifying bundler renames the classes themselves, so the name an error carries, which\n * the predicates match on and a log prints, comes from here: strings no minifier touches. A class not listed (an\n * application's own subclass) keeps the name its class has.\n */\nconst NAMES = new WeakMap<abstract new (...args: never[]) => unknown, string>();\n\n/** Base class for every error CloudRoaring throws. */\nexport class CloudRoaringError extends Error {\n /** Cross-bundle brand \u2014 see the predicates ({@link isCloudRoaringError}, \u2026). Non-enumerable-ish (symbol key \u21D2 not in JSON). */\n readonly [ERROR_BRAND] = true as const;\n constructor(message: string) {\n super(message);\n // Also the discriminator the predicates match on: a runtime string, so it survives a second copy of the package\n // where the class identity does not, and a minifier where the class's own name does not.\n this.name = NAMES.get(new.target) ?? new.target.name;\n }\n}\n\n/** 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 \u2014 the row changed since it was read. */\nexport class WriteConflictError extends CloudRoaringError {}\n\n/** Bytes from a tier are corrupt, oversized, or fail a checksum/format check. */\nexport class IntegrityError extends CloudRoaringError {}\n\n/**\n * A requested object/row does not exist. Part of the driver error vocabulary: every storage driver this\n * library ships, the in-memory one included, throws it for a read of a generation object that is not there.\n * A registry `get` of a row that is not there returns `null` instead.\n */\nexport class NotFoundError extends CloudRoaringError {}\n\n/**\n * A read of a leased pin came after its lease ended, by `until` or by `release()`. Thrown at every read site of the\n * handle, including a leased handle used as an operand or an exclude of a combine, and never answered empty: a\n * handle that read empty here would be an opt-out list that suppresses nobody. Carries the instant the lease ended\n * and why; never an id or a key.\n */\nexport class LeaseExpiredError extends CloudRoaringError {\n /** Epoch-ms the lease was taken until. */\n readonly until: number;\n /** `'expired'` when the clock reached `until`, `'released'` after `release()`. */\n readonly reason: 'expired' | 'released';\n constructor(message: string, until: number, reason: 'expired' | 'released') {\n super(message);\n this.until = until;\n this.reason = reason;\n }\n}\n\n/**\n * A segment already has as many live leases as one row records, so another cannot be taken. Nothing was written.\n * Release one, wait for one to end, or share one lease across the tasks of a job.\n */\nexport class LeaseLimitError extends CloudRoaringError {}\n\n/**\n * An operand a call relied on changed while the call ran, so what the call built from it is not published. Carries the\n * operand's name in the call and why it is stale (`'moved'`: it was pinned at a generation and its pointer has since\n * moved; `'erased'`: an erasure ran in the store after a call with a feed began, so what the feed gave it may hold an\n * erased id), under the stable `code`\n * `'stale-operand'`. Deterministic: run the call again against the current operand.\n */\nexport class StaleOperandError extends CloudRoaringError {\n readonly code = 'stale-operand' as const;\n /** The operand's name in the call that found it stale. */\n readonly operand: string;\n /** Why it is stale. */\n readonly reason: 'moved' | 'erased';\n constructor(message: string, operand: string, reason: 'moved' | 'erased') {\n super(message);\n this.operand = operand;\n this.reason = reason;\n }\n}\n\n/**\n * This build/configuration cannot perform the requested operation, though nothing is malformed. Two uses:\n * (1) **format** \u2014 the bytes are well-formed but unreadable here (an unknown `.crbm` major version) \u2014\n * distinct from `IntegrityError` (corruption); and (2)\n * **store configuration** \u2014 an operation this store's wiring doesn't support (e.g. a lifecycle helper like\n * `eraseSubject`/`retireExpired` called on a store built without a storage backend). Raised at\n * operation time, before any mutation.\n */\nexport class UnsupportedError extends CloudRoaringError {}\n\n/**\n * A driver cannot meet a capability the chosen topology requires (e.g. a Storage driver without range\n * reads). Raised fail-fast at wiring time, never mid-operation.\n */\nexport class CapabilityError extends CloudRoaringError {}\n\n/**\n * An operation would exceed its per-op **denial-of-wallet budget** \u2014 too many backend requests for a single\n * `count`/`iterate`/`intersect`/`subjectReport`/`eraseSubject` call \u2014 so it is refused **before** fanning out\n * (hard invariant 6). 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 \u2014 the KEK was never configured, rotated away without\n * keeping the old key, or lost. Deterministic (never retried): without a KEK the ciphertext is unreadable by\n * design. The flip side of crypto-shred \u2014 when this is *intended* (a destroyed segment) the registry row is\n * already a `destroyed` tombstone; when it's *not*, restore the missing KEK (or its recovery KEK). Carries no\n * key material.\n */\nexport class KeyUnavailableError extends CloudRoaringError {}\n\n/**\n * A **transient** infrastructure fault \u2014 throttling, a 5xx, a dropped connection, a client-side request\n * timeout. Retrying a read that failed this way is safe; a write that failed this way may still have landed, so\n * its caller re-runs the call rather than replaying the request. Drivers classify their backend's retryable faults and raise this (the\n * SDK-specific knowledge stays in the SDK-specific driver); the retry layer (`core/retry`) retries **only**\n * this class, never a deterministic error like {@link ValidationError}, {@link IntegrityError},\n * {@link NotFoundError}, or {@link WriteConflictError} (retrying those is pointless or wrong). The original\n * error is preserved in `cause` so callers can still inspect it.\n *\n * Note for logging hygiene: `cause` is the **raw SDK error**, which may carry operational\n * metadata (endpoint host, request IDs, `$metadata`). The library's own `message` is identifier-only and safe\n * to log; if you serialize the whole error *chain*, be aware you're including that metadata.\n */\nexport class TransientError extends CloudRoaringError {\n /** A second brand so a transient fault is classifiable cross-bundle. */\n readonly [TRANSIENT_BRAND] = true as const;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n if (options && 'cause' in options) this.cause = options.cause;\n }\n}\n\n// The names, registered once the classes exist. A class added above and left out here is named by the minifier.\nNAMES.set(CloudRoaringError, 'CloudRoaringError');\nNAMES.set(ValidationError, 'ValidationError');\nNAMES.set(WriteConflictError, 'WriteConflictError');\nNAMES.set(IntegrityError, 'IntegrityError');\nNAMES.set(NotFoundError, 'NotFoundError');\nNAMES.set(LeaseExpiredError, 'LeaseExpiredError');\nNAMES.set(LeaseLimitError, 'LeaseLimitError');\nNAMES.set(StaleOperandError, 'StaleOperandError');\nNAMES.set(UnsupportedError, 'UnsupportedError');\nNAMES.set(CapabilityError, 'CapabilityError');\nNAMES.set(BudgetExceededError, 'BudgetExceededError');\nNAMES.set(KeyUnavailableError, 'KeyUnavailableError');\nNAMES.set(TransientError, 'TransientError');\n\n/**\n * Bundle-safe error predicates \u2014 use these, not `instanceof`, wherever an error may cross the core\u2194driver\n * package 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 \u2014 retry the read-modify-write, don't fail. */\nexport function isWriteConflictError(err: unknown): err is WriteConflictError {\n return isCloudRoaringError(err) && err.name === 'WriteConflictError';\n}\n\n/** A retryable transient infrastructure fault. The retry layer keys on this. */\nexport function isTransientError(err: unknown): err is TransientError {\n return hasBrand(err, TRANSIENT_BRAND);\n}\n\n/** A read came after its pin's lease ended. */\nexport function isLeaseExpiredError(err: unknown): err is LeaseExpiredError {\n return isCloudRoaringError(err) && err.name === 'LeaseExpiredError';\n}\n\n/** An operand a call relied on changed while it ran. */\nexport function isStaleOperandError(err: unknown): err is StaleOperandError {\n return isCloudRoaringError(err) && err.name === 'StaleOperandError';\n}\n\n/** A segment has no room for another live lease. */\nexport function isLeaseLimitError(err: unknown): err is LeaseLimitError {\n return isCloudRoaringError(err) && err.name === 'LeaseLimitError';\n}\n\n/** A requested object/row does not exist. */\nexport function isNotFoundError(err: unknown): err is NotFoundError {\n return isCloudRoaringError(err) && err.name === 'NotFoundError';\n}\n\n/** Corrupt/oversized/failed-checksum bytes from a tier. */\nexport function isIntegrityError(err: unknown): err is IntegrityError {\n return isCloudRoaringError(err) && err.name === 'IntegrityError';\n}\n\n/** Invalid caller input. */\nexport function isValidationError(err: unknown): err is ValidationError {\n return isCloudRoaringError(err) && err.name === 'ValidationError';\n}\n\n/** This build or this store's wiring cannot do what was asked, though nothing is malformed. */\nexport function isUnsupportedError(err: unknown): err is UnsupportedError {\n return isCloudRoaringError(err) && err.name === 'UnsupportedError';\n}\n\n/** A driver lacks a capability the store's wiring needs. */\nexport function isCapabilityError(err: unknown): err is CapabilityError {\n return isCloudRoaringError(err) && err.name === 'CapabilityError';\n}\n\n/** A call would pass its per-op request budget, so it was refused before fanning out. */\nexport function isBudgetExceededError(err: unknown): err is BudgetExceededError {\n return isCloudRoaringError(err) && err.name === 'BudgetExceededError';\n}\n\n/** No key the keystore holds can unwrap an encrypted segment's data key. */\nexport function isKeyUnavailableError(err: unknown): err is KeyUnavailableError {\n return isCloudRoaringError(err) && err.name === 'KeyUnavailableError';\n}\n", "/**\n * Name \u2192 physical-key encoding. The library validates *length*, and encodes everything else.\n *\n * Lives in `core/` rather than beside the drivers because it is pure string logic \u2014 no I/O, no SDK, no\n * `node:` builtin \u2014 and because `validate.ts` needs it to measure a name against the key budget. Core may\n * not import a driver (invariant 7), and a driver may import core, so this is the only layer both can see.\n *\n * A name is **any non-empty string**, and each physical boundary escapes what *it* cannot take literally. An\n * allowlist of characters would reject names for the storage layer's convenience, and the storage layer's\n * convenience is the library's job, not the caller's. It would also let through the names that are actually\n * dangerous: `con`, `nul` and `com1` are Windows device names made only of letters and digits, which pass any\n * allowlist and fail only on a user's machine. A grammar can be both too narrow and too permissive at once,\n * which is the argument against having one.\n *\n * Percent-encoding, because it is the one escape everybody already reads. `%` escapes itself as `%25` and is\n * encoded **first**, which is what makes the transform injective: every `%` in an encoded string starts an\n * escape, so decoding is unambiguous and two distinct names can never collide on one key.\n *\n * There are two alphabets, because the boundaries differ:\n *\n * - **Object keys** (S3, GCS, Azure Blob) take almost anything. They need `/` escaped so a name cannot\n * invent hierarchy or break a key parser that splits on it, and control characters because they are not\n * legal in the XML an S3 LIST returns. Every other character outside `[A-Za-z0-9._:-]` is escaped as well.\n * - **Filesystem paths** need all of that plus `:` (an NTFS alternate-data-stream separator, where a write can\n * *succeed* while `readdir` never lists the result), plus three hazards that are about the component as a\n * whole rather than its characters \u2014 see {@link encodeNameForPath}.\n *\n * **The key alphabet is fixed for good.** Adding a character to it would change what `encodeNameForKey` emits\n * for every name containing that character, silently moving those segments to keys nothing looks up. A test pins\n * it, one printable ASCII character at a time.\n *\n * **A plain name encodes to itself on the OBJECT-KEY alphabet** \u2014 one made only of `[A-Za-z0-9._:-]` that\n * starts with a letter or digit \u2014 so S3, GCS and Azure keys read as the names that made them. That is the\n * property to preserve if this file is ever edited, and a property test asserts it over every plain name.\n *\n * The **path** alphabet escapes more. Besides `:`, two classes of plain name are escaped on a path: a Windows\n * device-name stem (`con`, `nul`, `com1`, `con.backup`) and a trailing dot (`a.`), since both silently alias\n * or fail on Windows.\n */\n\n/** Characters safe in an object key, left literal so a plain name reads as itself in the bucket. */\nconst KEY_SAFE = /[A-Za-z0-9._:-]/;\n/** Characters safe in a path component. As {@link KEY_SAFE} minus `:`. */\nconst PATH_SAFE = /[A-Za-z0-9._-]/;\n\nconst UTF8 = new TextEncoder();\n\n/**\n * Percent-encode one character's UTF-8 bytes: `\u00E9` \u2192 `%C3%A9`.\n *\n * Only ever called with a WELL-FORMED code point. `TextEncoder` maps an unpaired surrogate to U+FFFD, which\n * would make every surrogate \u2014 and U+FFFD itself \u2014 encode identically and silently break injectivity, so\n * `validate.ts` refuses a name that is not well-formed UTF-16 before any of this runs.\n */\nfunction escapeChar(ch: string): string {\n let out = '';\n for (const byte of UTF8.encode(ch)) {\n out += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;\n }\n return out;\n}\n\nfunction encodeWith(name: string, safe: RegExp): string {\n let out = '';\n // Iterate by code POINT, not code unit: a surrogate pair is one character and must encode as one UTF-8\n // sequence. Indexing by `charAt` would split an emoji into two unpaired halves and produce garbage bytes.\n for (const ch of name) {\n out += ch !== '%' && safe.test(ch) ? ch : escapeChar(ch);\n }\n // A LEADING underscore is escaped, which is what keeps the reserved namespaces reachable only by us.\n //\n // `_default` is the physical stand-in for an absent namespace. Unescaped, it would hand any caller a way to\n // name a namespace `_default` and have it resolve to everyone else's un-namespaced data. Escaping the first\n // `_` makes the sentinel unreachable by construction rather than by a blocklist that has to be maintained.\n return out.startsWith('_') ? `%5F${out.slice(1)}` : out;\n}\n\nfunction decodePercent(encoded: string): string {\n const bytes: number[] = [];\n for (let i = 0; i < encoded.length;) {\n if (encoded[i] === '%' && i + 2 < encoded.length + 1) {\n const hex = encoded.slice(i + 1, i + 3);\n if (!/^[0-9A-Fa-f]{2}$/.test(hex)) return encoded; // not an escape we wrote\n bytes.push(parseInt(hex, 16));\n i += 3;\n } else {\n for (const b of new TextEncoder().encode(encoded[i])) bytes.push(b);\n i += 1;\n }\n }\n // `ignoreBOM: true` is load-bearing, not a tidy-up. Without it `TextDecoder` STRIPS a leading U+FEFF, so\n // `%EF%BB%BForders` decodes to `orders` \u2014 a different, probably existing, segment. That is a collision in\n // the one direction everything else here rests on, and it is reachable: `validatePart` accepts U+FEFF, and\n // a BOM-prefixed name is what any spreadsheet export or CSV read without BOM stripping hands you.\n //\n // The visible symptom was worse than a failed round-trip. Each parser (`parseRegistryRow`,\n // `parseNamespaceDir`, `parseRegistryKey`) re-encodes what it decoded and refuses a spelling it cannot\n // reproduce, so a BOM-prefixed row could be WRITTEN and then silently skipped by `list()`,\n // `checkConsistency`, `exportSegments`, the retention sweep and subject erasure \u2014 present in the bucket and\n // invisible to every sweep over it.\n //\n // Decode-only, so nothing that works today changes: `encode` is untouched, no stored key moves, and the\n // only names whose decoding changes are ones that are currently rejected by that round-trip guard anyway.\n return new TextDecoder('utf-8', { fatal: false, ignoreBOM: true }).decode(new Uint8Array(bytes));\n}\n\n/**\n * Encode a name for use inside an **object key** (S3, GCS, Azure Blob).\n *\n * Leaves `[A-Za-z0-9._:-]` literal, except a leading `_` and a name that is only `.` or `..`, so a plain name\n * reads as itself, and escapes everything else \u2014 including `/` (which would invent hierarchy and break a parser\n * that splits on it) and control characters (not legal in S3's XML responses).\n */\nexport function encodeNameForKey(name: string): string {\n return defuseDotComponent(encodeWith(name, KEY_SAFE));\n}\n\n/**\n * Escape a component that is exactly `.` or `..`.\n *\n * Applied to **both** alphabets. It is obviously needed for a filesystem path, and it is needed for an object\n * key too: the library's own S3/GCS/Azure calls treat the key space as flat, but the moment those keys touch\n * something hierarchical the component resolves. `aws s3 sync`, `gsutil -m cp -r` and `azcopy` all write\n * `dest/tenant/../segments/\u2026`, which lands *outside* `tenant/`; s3fs and gcsfuse mounts do the same; and on\n * ADLS Gen2, where the namespace really is hierarchical, `prefix/../x` and `x` are the same object. Those are\n * the DR-restore and eject paths this library documents.\n *\n * `normalizeS3Prefix` refuses `.`/`..` segments in a **prefix**, which is trusted config; the name, the input an\n * attacker can influence, is escaped here instead.\n *\n * Every dot is escaped rather than just the first, so the result cannot end in one either.\n */\nfunction defuseDotComponent(encoded: string): string {\n return encoded === '.' || encoded === '..' ? encoded.replaceAll('.', '%2E') : encoded;\n}\n\n/** Inverse of {@link encodeNameForKey}. */\nexport function decodeNameFromKey(encoded: string): string {\n return decodePercent(encoded);\n}\n\n/**\n * Encode a name for use as a **filesystem path component**.\n *\n * Everything {@link encodeNameForKey} escapes, plus `:`, plus three hazards that are properties of the whole\n * component rather than of any character in it. All three are silent corruption rather than errors, which is\n * why they are handled here instead of being left to the OS:\n *\n * 1. **`.` and `..`** are traversal. `join(root, '..')` leaves the storage root.\n * 2. **Windows reserved device names** \u2014 `CON`, `PRN`, `AUX`, `NUL`, `COM1`\u2013`COM9`, `LPT1`\u2013`LPT9`, case\n * insensitive and *with or without an extension*, so `con.0.crbm` is reserved too. Opening one addresses a\n * device rather than a file, so `store.segment('con')` would break only on a user's Windows box.\n * 3. **A trailing `.` or space**, which Windows silently strips \u2014 so `a.` and `a` would become the same\n * directory, quietly merging two segments.\n *\n * Each is fixed by escaping the one character that defuses it, which keeps the encoding injective: a name that\n * needed defusing produces a `%XX` no other name produces.\n */\nexport function encodeNameForPath(name: string): string {\n let encoded = encodeWith(name, PATH_SAFE);\n\n // The traversal case may return on its own only because `defuseDotComponent` escapes EVERY dot. Escaping just\n // the first would turn `..` into `%2E.`, which ends in a dot: hazard 3, reintroduced by the fix for hazard 1.\n const dotted = defuseDotComponent(encoded);\n if (dotted !== encoded) return dotted;\n\n // A Windows device name is reserved with OR without an extension, so the test is on the stem.\n const stem = encoded.split('.')[0] ?? '';\n if (/^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(stem)) {\n encoded = escapeChar(encoded[0] as string) + encoded.slice(1);\n }\n\n // Windows strips a trailing dot, which would alias two distinct names onto one path. A trailing SPACE is the\n // same hazard but needs no arm here: space is not in `PATH_SAFE`, so the charset already escaped it to `%20`.\n if (encoded.endsWith('.')) encoded = `${encoded.slice(0, -1)}%2E`;\n\n return encoded;\n}\n\n/** Inverse of {@link encodeNameForPath}. */\nexport function decodeNameFromPath(encoded: string): string {\n return decodePercent(encoded);\n}\n", "/**\n * The registry token's incarnation: the part of a token that says which incarnation of a name a row is.\n *\n * A shipped registry gives a row it creates a token `<incarnation>.<counter>.<write>`: 32 lowercase hex digits drawn\n * from injected entropy when the row is created, a decimal counter, and 16 hex digits drawn for each write. Every write\n * of the row keeps the incarnation, and a name created again draws a new one, so two incarnations are told apart by it\n * even when their rows were created in the same millisecond or one is gone. A row a 0.11 build wrote has no incarnation\n * for as long as it lives (`\"7\"`, then `\"8.<write>\"`), and a registry of someone else's issues tokens in any form.\n *\n * This lives in `core/` so the publish can read it, and the registry drivers, which build the tokens, import it from\n * here: the form has one definition.\n */\nimport type { Token } from './ports';\n\n/** An incarnation-form token: the incarnation id, the counter and a write part, `.`-separated, in lowercase hex. */\nexport const INCARNATION_TOKEN = /^([0-9a-f]{32})\\.(0|[1-9]\\d*)\\.([0-9a-f]{16})$/;\n\n/**\n * The incarnation id in a token, or `undefined` for one that has none: a schema-1-born row's, or any token another\n * driver issues. Two tokens with the same incarnation are writes of one incarnation of a row.\n */\nexport function incarnationOf(token: Token): string | undefined {\n return INCARNATION_TOKEN.exec(token)?.[1];\n}\n\n/**\n * Whether two reads of one name's row are one incarnation of it.\n *\n * - Both tokens carry an incarnation id: the ids decide, and the clock stamps do not enter.\n * - Only one does: different incarnations. A name created again is always given an incarnation id, and a write never\n * takes one away, so a row without an id never becomes a row with one, nor the reverse.\n * - Neither does (a row 0.11 wrote, or a registry of someone else's): there is no id to compare, and the creation stamp\n * is the only signal left. It is a clock reading, so a caller that acts on this answer proves its own object too.\n */\nexport function sameIncarnation(\n a: { readonly token: Token; readonly createdAt: number },\n b: { readonly token: Token; readonly createdAt: number },\n): boolean {\n const ia = incarnationOf(a.token);\n const ib = incarnationOf(b.token);\n if (ia !== undefined || ib !== undefined) return ia === ib;\n return a.createdAt === b.createdAt;\n}\n", "/**\n * Leases: a bounded hold on one generation, recorded in the segment's registry row, that keeps the generation out of a\n * load's collection until the lease ends.\n *\n * The row holds a list of `{ holder, generation, until }`. A collector that honours leases reads the list from the row\n * it already has and spares a live entry; erasure, shred, drop and retention expiry never look at it. The entry names\n * no fingerprint: a collector spares a generation by number and cannot compare an object without reading it, a purge\n * and re-create drops the list with the row, and the row's token names the incarnation. The pin's own fingerprint,\n * which its reads check, is what stops a number retaken after a rollback and an erasure being read as the leased\n * object; the entry then spares a different object from collection until it ends, at most the longest lease.\n *\n * Clocks. The holder ends a lease at `until` by its own clock. A collector holds it for {@link LEASE_SKEW_MS} longer, by\n * its own. The hold is safe while the two clocks differ by at most that margin, whichever way: a reader behind by `r`\n * serves until `until + r` of real time and a collector ahead by `c` stops holding at `until + margin - c`, so the\n * generation is there for every read the reader makes iff `r + c <= margin`. Pure orchestration over the registry port\n * and the injected clock and rng: no I/O, time or randomness of its own.\n */\nimport {\n LeaseLimitError,\n NotFoundError,\n WriteConflictError,\n isTransientError,\n isWriteConflictError,\n} from './errors';\nimport type { Clock, Rng } from './determinism';\nimport { sameIncarnation } from './token';\nimport type { IRegistryDriver, LeaseEntry, RegistryRecord, SegmentRef, Token } from './ports';\n\n/** The longest lease: a `leaseUntil` further than this from the clock is refused. */\nexport const MAX_LEASE_MS = 14 * 86_400_000;\n\n/**\n * How much longer than `until` a collector holds a lease, and the most a collector will believe a lease runs past\n * its own clock. It is the tolerated difference between the holder's clock and the collector's, in either direction.\n */\nexport const LEASE_SKEW_MS = 60_000;\n\n/** The most live leases a writer records on one segment; the next one is refused with {@link LeaseLimitError}. */\nexport const MAX_LEASES_PER_SEGMENT = 64;\n\n/** The most entries a stored row may hold: four times what a writer writes, so a release can raise the cap. */\nexport const MAX_STORED_LEASES = 256;\n\n/**\n * Read-modify-write attempts of one take or release before it reports contention. Takers of one row serialise: each\n * round exactly one write lands, so the slowest of `k` simultaneous takers needs `k` attempts. The bound is the cap\n * plus a few, so that the most a segment can hold, all arriving at once, can all land.\n */\nexport const LEASE_CAS_ATTEMPTS = MAX_LEASES_PER_SEGMENT + 8;\n\n/** Fresh writes sent after one that got no answer and left the row as it was. */\nconst UNANSWERED_RESENDS = 3;\n/** The upper bound of the first of those waits, in ms; each next one doubles it. */\nconst UNANSWERED_BASE_MS = 500;\n/** The upper bound of the first wait after a lost race, in ms; each next doubles it, to the cap. */\nconst CONFLICT_BASE_MS = 25;\nconst CONFLICT_CAP_MS = 400;\n\n/**\n * Whether an entry holds its generation against a collector reading `now`: it has not ended (`until` plus the margin\n * is ahead), and it does not run further past `now` than any honest holder with a clock inside the margin could have\n * written (`until` at most the longest lease plus the margin ahead). The second clause bounds a corrupt or forged\n * `until` without refusing the row: an entry past it is read and not honoured.\n */\nexport function isLive(entry: LeaseEntry, now: number): boolean {\n return now < entry.until + LEASE_SKEW_MS && entry.until <= now + MAX_LEASE_MS + LEASE_SKEW_MS;\n}\n\n/** The generations a collector reading `now` must spare, from the row it holds. */\nexport function heldGenerations(record: RegistryRecord | null, now: number): ReadonlySet<number> {\n const out = new Set<number>();\n for (const e of record?.leases ?? []) if (isLive(e, now)) out.add(e.generation);\n return out;\n}\n\n/** The entries of a row that are live at `now`, in the row's order. */\nexport function liveLeases(record: RegistryRecord | null, now: number): readonly LeaseEntry[] {\n return (record?.leases ?? []).filter((e) => isLive(e, now));\n}\n\n/**\n * What a writer that fences on the row's token needs to wait out lease churn: a sleep, and the rng that spreads it.\n * Both are optional; without a sleep a retry follows at once.\n */\nexport interface ChurnDeps {\n readonly clock?: { readonly sleep?: (ms: number) => Promise<void> } | undefined;\n readonly rng?: Rng | undefined;\n}\n\n/**\n * How many times one writer retries after meeting a row that differs from the one it read only in its leases. Takers of\n * one row serialise: each round exactly one write lands, so a writer racing `k` holders needs up to `k + 1` rounds, and a\n * holder can take and release inside one job, so the bound covers a take and a release by every holder the row can\n * hold, with a few to spare: 2 * {@link MAX_LEASES_PER_SEGMENT} + 8. At waits of up to 25 ms growing to up to 400 ms it is a\n * minute at the very most before the writer reports the conflict it had, and a lease writer that goes on beyond\n * that has stopped being a lease writer and become a flood.\n */\nexport const LEASE_ONLY_RETRIES = 2 * MAX_LEASES_PER_SEGMENT + 8;\n\n/** The fields of a row that a lease write moves without changing what the row says, and the ones that name it. */\nconst BOOKKEEPING: ReadonlySet<string> = new Set(['token', 'updatedAt', 'leases']);\n\n/** A stable text of a value: object keys in order, `undefined` as absent, so two equal rows compare equal. */\nfunction stable(value: unknown): string {\n if (value === undefined) return 'u';\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;\n const o = value as Record<string, unknown>;\n const keys = Object.keys(o)\n .filter((k) => o[k] !== undefined)\n .sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${stable(o[k])}`).join(',')}}`;\n}\n\n/**\n * Whether `now` is `held` with nothing changed but its leases: the same incarnation, and every other field equal,\n * `updatedAt` and the token (which every write moves) aside. `alsoIgnore` names fields the caller's own earlier write\n * changed, so a writer comparing against a row it has itself written does not take its own change for another's.\n *\n * This is the one test that lets a writer fenced on the row's token go on after a lease write: a lease is written by\n * readers, in numbers no operator controls, and it says nothing about the content the writer derived, the pointer it\n * judged or the key it holds. Any other difference is another writer's, and the fence refuses as it always has.\n */\nexport function onlyLeasesDiffer(\n held: RegistryRecord,\n now: RegistryRecord,\n alsoIgnore: readonly (keyof RegistryRecord)[] = [],\n): boolean {\n if (!sameIncarnation(held, now)) return false;\n const skip = new Set<string>([...BOOKKEEPING, ...alsoIgnore]);\n const keys = new Set([...Object.keys(held), ...Object.keys(now)]);\n for (const k of keys) {\n if (skip.has(k)) continue;\n if (\n stable((held as unknown as Record<string, unknown>)[k]) !==\n stable((now as unknown as Record<string, unknown>)[k])\n ) {\n return false;\n }\n }\n return true;\n}\n\n/** A writer's count of the lease-only changes it has waited out, and the wait. One per call of the writer. */\nexport interface LeaseChurn {\n /**\n * When `now` is `held` changed only in its leases and the bound is not spent: wait, then read the row again with\n * `reread`, and return what it found. The wait comes before the read, so the writer's next write is made against a row\n * as fresh as one round trip, not one as stale as the wait. The caller checks that row against `held` once more (a\n * write may have landed during the wait) and goes on against it, without redoing its work. `undefined` otherwise, and\n * the caller does what it always did.\n *\n * The wait is uniform in `[0, bound)`, the bound starting at 25 ms and doubling to 400 ms, taken on the injected\n * clock's `sleep` and spread by its `rng`. With no `sleep` there is no wait, and the retries follow one another at\n * once; with no `rng` the wait is exactly the bound, so contenders stay in step. The store always supplies both.\n */\n settle(\n held: RegistryRecord | null | undefined,\n now: RegistryRecord | null,\n reread: () => Promise<RegistryRecord | null>,\n alsoIgnore?: readonly (keyof RegistryRecord)[],\n ): Promise<{ readonly row: RegistryRecord | null } | undefined>;\n}\n\nexport function leaseChurn(deps: ChurnDeps): LeaseChurn {\n let used = 0;\n return {\n async settle(held, now, reread, alsoIgnore) {\n if (held === null || held === undefined || now === null) return undefined;\n if (used >= LEASE_ONLY_RETRIES || !onlyLeasesDiffer(held, now, alsoIgnore)) return undefined;\n const bound = Math.min(CONFLICT_BASE_MS * 2 ** Math.min(used, 4), CONFLICT_CAP_MS);\n used += 1;\n const sleep = deps.clock?.sleep;\n if (sleep !== undefined) {\n await sleep.call(deps.clock, Math.floor((deps.rng?.next() ?? 1) * bound));\n }\n return { row: await reread() };\n },\n };\n}\n\n/** A row's leases for a patch: the given entries, sorted by generation then holder, or `undefined` when none. */\nfunction listOf(entries: readonly LeaseEntry[]): readonly LeaseEntry[] | undefined {\n if (entries.length === 0) return undefined;\n return [...entries].sort((a, b) =>\n a.generation !== b.generation\n ? a.generation - b.generation\n : a.holder < b.holder\n ? -1\n : a.holder > b.holder\n ? 1\n : 0,\n );\n}\n\n/** What the lease writers need: the registry, the clock that judges liveness and waits, and the rng that spreads waits. */\nexport interface LeaseDeps {\n readonly registry: IRegistryDriver;\n readonly clock: Clock;\n readonly rng?: Rng;\n}\n\n/** What a take asks for. */\nexport interface LeaseTake {\n /** Drawn once per pin call, outside any retry, so a write that landed unseen is found again and never duplicated. */\n readonly holder: string;\n /** The generation to hold. */\n readonly generation: number;\n /** Epoch-ms, already checked against the caller's clock. */\n readonly until: number;\n /** The row the caller read; the first write is made against it, with no row read of its own. */\n readonly row: RegistryRecord;\n /** The generation must still be the row's pointer on every attempt: a pin of the current generation. */\n readonly current: boolean;\n}\n\n/** A lease that landed: the token its write returned, and the row that write was made against. */\nexport interface TakenLease {\n readonly token: Token;\n readonly row: RegistryRecord;\n}\n\nconst wait = (deps: LeaseDeps, bound: number): Promise<void> =>\n deps.clock.sleep(Math.floor((deps.rng?.next() ?? 1) * bound));\n\nconst heldBy = (row: RegistryRecord | null, take: LeaseTake): boolean =>\n (row?.leases ?? []).some(\n (e) => e.holder === take.holder && e.generation === take.generation && e.until === take.until,\n );\n\n/**\n * Write a lease entry for `take.holder`, fenced on the row it was made against, so a lease that lands proves the row\n * was unchanged since the caller read it. Returns `'moved'` when `take.current` and the pointer is no longer at the\n * generation (the caller starts over from a fresh read). Throws {@link NotFoundError} for a row that is gone,\n * destroyed or has no such published generation, {@link LeaseLimitError} when the segment already has\n * {@link MAX_LEASES_PER_SEGMENT} live leases (nothing is written), `WriteConflictError` after\n * {@link LEASE_CAS_ATTEMPTS} lost races, and the registry's own `TransientError` for a write that stayed unanswered.\n *\n * Idempotent by holder: an entry for the holder is replaced, so a retry of a whole pin re-takes without duplicating,\n * and a write that got no answer is settled by reading the row for the holder's entry.\n */\nexport async function takeLease(\n ref: SegmentRef,\n deps: LeaseDeps,\n take: LeaseTake,\n): Promise<TakenLease | 'moved'> {\n let row: RegistryRecord | null = take.row;\n let held = true; // whether `row` is the row the caller read: only then is it passed as the write's hint\n let resends = 0;\n let unanswered: unknown;\n for (let attempt = 0; attempt < LEASE_CAS_ATTEMPTS; attempt++) {\n if (row === null) row = await deps.registry.get(ref);\n if (row === null || row.status === 'destroyed' || row.currentGen === null) {\n throw new NotFoundError(`segment \"${ref.segment}\" has no generation to lease`);\n }\n if (take.generation > row.currentGen) {\n throw new NotFoundError(\n `segment \"${ref.segment}\" generation ${take.generation} cannot be leased: it is not a published generation`,\n );\n }\n if (take.current && row.currentGen !== take.generation) return 'moved';\n if (heldBy(row, take)) return { token: row.token, row };\n const live = liveLeases(row, deps.clock.now()).filter((e) => e.holder !== take.holder);\n if (live.length >= MAX_LEASES_PER_SEGMENT) {\n throw new LeaseLimitError(\n `segment \"${ref.segment}\" already has ${live.length} live leases, the most one segment records`,\n );\n }\n const leases = listOf([\n ...live,\n { holder: take.holder, generation: take.generation, until: take.until },\n ]);\n const against: RegistryRecord = row;\n try {\n const { token } = await deps.registry.compareAndSwap(\n ref,\n against.token,\n { leases },\n held ? { held: against } : undefined,\n );\n return { token, row: against };\n } catch (err) {\n if (isWriteConflictError(err)) {\n row = null;\n held = false;\n await wait(deps, Math.min(CONFLICT_BASE_MS * 2 ** attempt, CONFLICT_CAP_MS));\n continue;\n }\n if (!isTransientError(err)) throw err;\n // No answer: the write may have landed, or may still land. The row says which.\n const now = await deps.registry.get(ref);\n if (heldBy(now, take)) return { token: (now as RegistryRecord).token, row: against };\n if (now !== null && now.token === against.token) {\n if (resends >= UNANSWERED_RESENDS) throw err;\n await wait(deps, UNANSWERED_BASE_MS * 2 ** resends);\n resends += 1;\n unanswered = err;\n }\n row = now;\n held = false;\n if (row === null)\n throw new NotFoundError(`segment \"${ref.segment}\" has no generation to lease`);\n }\n }\n if (unanswered !== undefined) throw unanswered;\n throw new WriteConflictError(`lease: contention taking a lease on segment \"${ref.segment}\"`);\n}\n\n/**\n * Remove `holder`'s entry, and every entry that has ended, in one write. Idempotent: a row that is gone, destroyed or\n * has no entry for the holder is already released. Throws `WriteConflictError` after {@link LEASE_CAS_ATTEMPTS} lost\n * races and the registry's `TransientError` for a write that stayed unanswered over an unchanged row.\n */\nexport async function releaseLease(\n ref: SegmentRef,\n deps: LeaseDeps,\n holder: string,\n): Promise<void> {\n let resends = 0;\n let unanswered: unknown;\n let row: RegistryRecord | null | undefined;\n for (let attempt = 0; attempt < LEASE_CAS_ATTEMPTS; attempt++) {\n if (row === undefined) row = await deps.registry.get(ref);\n if (row === null || row.status === 'destroyed') return;\n if (!(row.leases ?? []).some((e) => e.holder === holder)) return;\n const against: RegistryRecord = row;\n const keep = liveLeases(against, deps.clock.now()).filter((e) => e.holder !== holder);\n try {\n await deps.registry.compareAndSwap(ref, against.token, { leases: listOf(keep) });\n return;\n } catch (err) {\n if (isWriteConflictError(err)) {\n row = undefined;\n await wait(deps, Math.min(CONFLICT_BASE_MS * 2 ** attempt, CONFLICT_CAP_MS));\n continue;\n }\n if (!isTransientError(err)) throw err;\n const now = await deps.registry.get(ref);\n if (now === null || !(now.leases ?? []).some((e) => e.holder === holder)) return;\n if (now.token === against.token) {\n if (resends >= UNANSWERED_RESENDS) throw err;\n await wait(deps, UNANSWERED_BASE_MS * 2 ** resends);\n resends += 1;\n unanswered = err;\n }\n row = now;\n }\n }\n if (unanswered !== undefined) throw unanswered;\n throw new WriteConflictError(`lease: contention releasing a lease on segment \"${ref.segment}\"`);\n}\n", "/**\n * Boundary validation for segment / namespace names.\n *\n * **A name is any non-empty string.** There is no character allowlist, because an allowlist rejects names for\n * the storage layer's convenience \u2014 and the storage layer's convenience is this library's problem, not the\n * caller's. Every physical boundary escapes what *it* cannot take literally (`core/name-codec.ts`),\n * so `dedup:2026-08-01`, `user@example.com`, `orders/2026`, `\u65E5\u672C\u8A9E` and `100%` are all ordinary names.\n *\n * A grammar would fail in both directions. It would reject names that are merely unfamiliar, and it would pass\n * names that are genuinely broken \u2014 `con`, `nul` and `com1` are Windows device names made only of letters and\n * digits, so `store.segment('con')` would validate cleanly and fail only on a user's machine. Encoding handles\n * both: it accepts what is merely unfamiliar, and defuses what is actually dangerous.\n *\n * What remains is **size** and **representability**, both real constraints rather than tastes.\n *\n * Size: S3 caps an object key at 1024 bytes and a name is only one part of it. The cap is applied to the\n * **encoded** length \u2014 and to the longer of the two encodings, since a path escapes `:` three-for-one where a\n * key leaves it literal \u2014 because a limit measured on the input would let a key exceed the backend's.\n *\n * Representability: a name must be well-formed UTF-16, because an unpaired surrogate has no UTF-8 encoding at\n * all. Letting one through would not merely store oddly; every lone surrogate encodes to the same replacement\n * bytes, so four distinct names would claim one key.\n */\nimport { ValidationError } from './errors';\nimport { encodeNameForKey, encodeNameForPath } from './name-codec';\nimport type { ChunkRef, SegmentRef } from './ports';\n\nconst CHUNK_KEY_MAX = 0xffff;\n\n/**\n * The most an encoded name may occupy in a physical key.\n *\n * S3's limit is 1024 bytes for the WHOLE key, which also carries the caller's prefix, the namespace, a fixed\n * infix (`/segments/`) and the `.<generation>.crbm` suffix. 256 leaves generous room for all of that with both\n * a namespace and a segment at the ceiling.\n */\nexport const MAX_NAME_LENGTH = 256;\n\n/**\n * A high surrogate not followed by a low one, or a low surrogate not preceded by a high one.\n *\n * Deliberately NOT `/u` and not `String.prototype.isWellFormed()`: the flag would make the engine read\n * code points, which is the very distinction being tested, and the method needs an ES2024 lib target\n * this package does not set. Matching on code units is what sees a half of a pair.\n */\nconst LONE_SURROGATE = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/** Whether `value` is well-formed UTF-16: no unpaired surrogate, so it survives a round trip through UTF-8. */\nexport function isWellFormedString(value: string): boolean {\n return !LONE_SURROGATE.test(value);\n}\n\n/**\n * How long a name is once storage has it \u2014 the longer of the two encodings.\n *\n * Exported because anything that composes a name out of other names (the due index does) has to measure it the\n * same way, and a second copy of that rule is how the two drifted apart before.\n */\nexport function encodedNameLength(value: string): number {\n return Math.max(encodeNameForKey(value).length, encodeNameForPath(value).length);\n}\n\nfunction validatePart(value: string, field: string): void {\n if (typeof value !== 'string') {\n throw new ValidationError(`${field} must be a string; got ${typeof value}`);\n }\n if (value.length === 0) {\n throw new ValidationError(`${field} must not be empty`);\n }\n // Cheap bound BEFORE encoding. Encoding never shrinks a string, so a name already over the cap in raw units\n // is over it encoded \u2014 and rejecting first means an attacker-supplied name cannot make us build a 60 MB\n // string to find out. (Measured: a 10-million-unit name cost 4.2 s of blocking CPU without this.)\n if (value.length > MAX_NAME_LENGTH) {\n throw new ValidationError(\n `${field} is too long: ${value.length} characters (limit ${MAX_NAME_LENGTH} once encoded for a storage key)`,\n );\n }\n // A name has to survive the round trip to UTF-8 and back. An unpaired surrogate does not: `TextEncoder`\n // replaces it with U+FFFD, so every lone surrogate AND U+FFFD itself would encode to the same bytes \u2014 four\n // distinct names collapsing onto one key, which is the one property everything else here rests on. There is\n // no UTF-8 for a lone surrogate, so this is a limit of the medium rather than a rule we chose.\n if (LONE_SURROGATE.test(value)) {\n throw new ValidationError(\n `${field} contains an unpaired surrogate, so it has no UTF-8 encoding and cannot be stored. This is ` +\n `usually a string sliced through an astral character (an emoji, say) \u2014 slice by code point instead.`,\n );\n }\n // Measured on the ENCODED form, because that is what a bucket has to hold \u2014 and on the LONGER of the two\n // encodings. A path escapes `:` three-for-one where a key leaves it literal, so measuring the key form alone\n // let `'a' + ':'.repeat(255)` pass the boundary and then fail inside the driver with a raw ENAMETOOLONG\n // rather than a typed error at the edge.\n const encoded = encodedNameLength(value);\n if (encoded > MAX_NAME_LENGTH) {\n throw new ValidationError(\n `${field} is too long: ${encoded} characters once encoded for storage (limit ${MAX_NAME_LENGTH}). The name ` +\n `itself is ${value.length} characters \u2014 encoding expands anything outside [A-Za-z0-9._-], so a name of ` +\n `mostly non-ASCII text, or one full of colons, reaches the limit sooner than its length suggests.`,\n );\n }\n}\n\nexport function validateSegmentRef(ref: SegmentRef): void {\n validatePart(ref.segment, 'segment');\n if (ref.namespace !== undefined) validatePart(ref.namespace, 'namespace');\n}\n\n/**\n * The namespace prefix the library keeps for its own bookkeeping: the due index stores one pointer row per\n * expiring segment in `cbm.due.<bucket>` (see `due-index.ts`). **One constant, read by both sides** \u2014 the\n * application-facing checks below refuse it in a name an application passes in, and the due index writes and\n * recognises its rows by it \u2014 so the two cannot drift.\n *\n * Only this exact prefix is reserved, not `cbm.` as a whole: `cbm.dueX`, `cbm.due` and `cbmdue.eu` are ordinary\n * namespaces. Every fleet-wide enumeration skips the rows of a reserved namespace as bookkeeping, so a segment\n * there would be invisible to an erasure, a consistency check, an export and a retention sweep.\n *\n * Internal: not exported from any entry. The flavor keeps a copy for its own facade checks, and a test pins the\n * two together.\n */\nexport const RESERVED_NAMESPACE_PREFIX = 'cbm.due.';\n\n/** Does this namespace start with {@link RESERVED_NAMESPACE_PREFIX}? `undefined` (no namespace) never does. */\nexport function isReservedNamespace(namespace: string | undefined): boolean {\n return namespace !== undefined && namespace.startsWith(RESERVED_NAMESPACE_PREFIX);\n}\n\n/**\n * Validate a namespace an application names, as a segment ref's namespace or as a `namespace` option that scopes\n * a scan: the name rules, and **not** in the reserved namespace. Internal; the public `validateSegmentRef` of\n * `@cloudbitmaps/core/driver-kit` is the name rules only, which is what a driver needs, since the due index's own\n * rows live in the reserved namespace and go through the drivers.\n */\nexport function validateUserNamespace(namespace: string): void {\n validatePart(namespace, 'namespace');\n if (isReservedNamespace(namespace)) {\n throw new ValidationError(\n `namespace \"${namespace}\" is reserved: names starting with \"${RESERVED_NAMESPACE_PREFIX}\" hold the ` +\n `library's own bookkeeping rows, which every fleet-wide scan skips, so a segment there would be ` +\n `invisible to an erasure, a consistency check, an export and a retention sweep. Choose another namespace.`,\n );\n }\n}\n\n/** Validate a segment ref an application hands in: the name rules, and a namespace outside the reserved prefix. */\nexport function validateUserRef(ref: SegmentRef): void {\n validatePart(ref.segment, 'segment');\n if (ref.namespace !== undefined) validateUserNamespace(ref.namespace);\n}\n\n/**\n * Validate the keys of a `getChunks` stream: in ascending order, a key may repeat. Checked before anything is\n * resolved or read, so a caller's mistake costs no request.\n */\nexport function validateChunkKeyOrder(keys: readonly number[]): void {\n for (let i = 1; i < keys.length; i++) {\n if (!(keys[i]! >= keys[i - 1]!))\n throw new ValidationError('chunk keys must be in ascending order');\n }\n}\n\n/** Validate a chunk ref: the segment/namespace rules plus `chunkKey` \u2208 `[0, 65535]` (a u16). A driver-boundary check. */\nexport function validateChunkRef(ref: ChunkRef): void {\n validateSegmentRef(ref);\n if (!Number.isInteger(ref.chunkKey) || ref.chunkKey < 0 || ref.chunkKey > CHUNK_KEY_MAX) {\n throw new ValidationError(`chunkKey must be an integer in [0, ${CHUNK_KEY_MAX}]`);\n }\n}\n", "/**\n * Bounded-concurrency fan-out \u2014 the missing primitive for running async work over many items without either\n * a thundering herd (unbounded `Promise.all` \u2192 N simultaneous object-store 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 \u2014 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 * Storage-driver contracts the engine depends on.\n *\n * Two tiers and one pointer. **Storage** is immutable object storage holding `.crbm` generations (`IStorageDriver`,\n * read by the engine through the per-chunk `StorageChunkSource` view the `.crbm` reader implements); the\n * **registry** is the authoritative per-segment record \u2014 which generation is current, the wrapped DEKs, the\n * governance metadata \u2014 under optimistic concurrency (`IRegistryDriver`). Drivers move opaque bytes and OCC\n * tokens; they never understand roaring or the `.crbm` layout.\n */\n\nimport { UnsupportedError, ValidationError } from './errors';\nimport type { BlobSink } from './blob';\nimport type { WrappedDek } from './crypto';\nimport type { IMetricsSink } from './metrics';\n\n/**\n * Opaque optimistic-concurrency token \u2014 unique per write with overwhelming probability, since it carries random parts\n * (see {@link RegistryRecord.token}), and compared by equality only.\n */\nexport type Token = string;\n\n/**\n * The address of one segment: a `namespace` and a `segment` name, both any non-empty string of at most 256\n * characters once encoded for storage. Omitting the namespace addresses a different segment from one that names it.\n *\n * **A namespace starting with `cbm.due.` is reserved**, and every call of the store, and of the free functions\n * behind it, that takes a ref or a `namespace` option throws `ValidationError` for one. The library keeps the due\n * index there (one pointer row per expiring segment), and every fleet-wide scan skips those rows as bookkeeping, so a\n * segment in such a namespace would be invisible to an erasure, a consistency check, an export and a retention sweep.\n * A driver takes the prefix, since the due index's own rows go through it. Only that exact prefix is reserved:\n * `cbm.dueX` and `cbmdue.eu` are ordinary namespaces, and a segment name is never restricted.\n */\nexport interface SegmentRef {\n readonly namespace?: string;\n readonly segment: string;\n}\n\nexport interface ChunkRef extends SegmentRef {\n readonly chunkKey: number;\n}\n\n/** Identifies one immutable `.crbm` object \u2014 a single generation of a segment. */\nexport interface GenKey extends SegmentRef {\n readonly generation: number;\n}\n\n/**\n * A segment's grounded on-disk footprint \u2014 the current generation's Storage object bytes, read cheaply from the\n * `.crbm` footer/index (no payload reads). Powers the grounded `costReport()`.\n */\nexport interface SegmentSize {\n readonly sizeBytes: number;\n}\n\n/**\n * One chunk of a {@link StorageChunkSource.getChunks} stream: the key asked for, its bytes (`null` where the generation\n * holds none), and the version of the generation the bytes were read from, or `null` when the segment has no\n * generation. The version is what {@link StorageChunkSource.currentVersion} reports for that generation, so a caller\n * can key what it keeps by the generation the bytes came from rather than the one it resolved earlier.\n */\nexport interface ChunkRead {\n readonly key: number;\n readonly bytes: Uint8Array | null;\n readonly version: string | null;\n}\n\n/** Options of {@link StorageChunkSource.getChunks}. */\nexport interface ReadChunksOptions {\n /**\n * Runs one storage request, and may run it again if it fails. A source passes each request it makes through\n * this, so a caller that retries transient faults repeats the one request that failed, not the ones that landed.\n * Absent, each request runs once.\n */\n readonly retry?: <T>(request: () => Promise<T>) => Promise<T>;\n /**\n * How many range requests the stream holds ahead of its consumer, in flight or landed and not yet taken: a positive\n * integer, 32 by default. It bounds the requests in flight, and the memory the stream holds, at this many times the\n * largest range (1 MiB, 1 MiB + 28 B for one encrypted chunk).\n */\n readonly concurrency?: number;\n /**\n * Open the window 1, 2, 4 \u2026 ranges wide up to `concurrency` instead of at full width, so a reader that stops early\n * has asked for little; a number starts it that wide instead of at 1 (a positive integer), and it doubles from there.\n */\n readonly ramp?: boolean | number;\n /**\n * Called once for every range request the stream sends, when it settles: a request the consumer took, one that was\n * still in flight when the consumer stopped, and one that failed. `bytes` is what the request moved, the gaps between\n * the chunks it carried included (0 when it failed), and `ms` how long it took, retries included (0 when the source\n * has no clock). It is how a caller counts what it is billed for, since several chunks can share a request and\n * a stopped stream leaves some in flight. A throw from it is ignored.\n */\n readonly onRequest?: (request: { readonly bytes: number; readonly ms: number }) => void;\n}\n\n/** Per-chunk read view of the immutable Storage tier (implemented by the `.crbm` reader). */\nexport interface StorageChunkSource {\n /** Read-only bytes for the chunk, or `null` if absent. Callers must not mutate the buffer. */\n getChunk(ref: ChunkRef): Promise<Uint8Array | null>;\n listChunkKeys(ref: SegmentRef): Promise<number[]>;\n /**\n * Optional: several chunks of one segment as a stream, read **from one generation** with fewer storage requests than\n * one per chunk where the chunks sit near each other in the object. `keys` are chunk keys in ascending order (a key\n * may repeat; any other order is a `ValidationError`). The stream yields one {@link ChunkRead} per position of\n * `keys`, in that order, as the requests that carry them land; a key the generation does not hold yields `null`\n * bytes, as {@link StorageChunkSource.getChunk} answers. Each chunk is checked as a read of it alone is.\n *\n * **Nothing is resolved or read until the first chunk is asked for**, and the source holds at most\n * {@link ReadChunksOptions.concurrency} ranges at a time (in flight, or landed and not yet taken), however many keys\n * there are: a consumer that is slow holds the stream back, and one that stops early (`break`, or `return()`) stops\n * the reads, so the requests it had already started (at most that many) finish and are dropped, and are not retried.\n * A stream that fails raises at once and sends nothing further, and the requests it left in flight finish in the\n * background and never raise. A plain chunk may be a view into a buffer of up to 1 MiB that it shares with its\n * neighbours (and the same view at two positions for a key asked twice), so do not write to it, and copy a chunk to\n * keep it.\n *\n * One stream reads one generation. If that generation is swept, or its object replaced, while the stream runs, a\n * source may re-resolve the segment and continue with the keys not yet yielded from the generation that is current\n * then; each chunk says which version it came from, and each is whole and verified either way. Before it does, it\n * waits for the requests the failed stream left in flight, so a heal never opens a second window beside them: a\n * request that never answers delays a heal, as it would hang a read of one chunk, until the driver's read timeout (if\n * it has one) ends it, and never delays an error. A source that reads a pinned generation never heals.\n *\n * A source that cannot read a range of an object omits this, and a caller reads chunk by chunk; the `.crbm`\n * source, which is what the stores the library ships read through, implements it.\n */\n getChunks?(\n ref: SegmentRef,\n keys: readonly number[],\n options?: ReadChunksOptions,\n ): AsyncIterable<ChunkRead>;\n /**\n * Optional: the current generation's grounded size, cheaply (from the already-parsed `.crbm` index \u2014 no\n * payload reads), or `null` if the segment has no Storage generation. Powers the grounded `costReport()`.\n */\n sizeOf?(ref: SegmentRef): Promise<SegmentSize | null>;\n /**\n * Optional: how often this source re-reads a segment's pointer while the segment is being read, in ms, or 0 if\n * it never does. The grounded `costReport()` prices the pointer refresh at this interval; a source that omits it\n * is priced at the store's default.\n */\n readonly pointerRefreshMs?: number;\n /**\n * Optional: the current generation's **per-chunk cardinality** (`chunkKey \u2192 count`), read from the\n * already-parsed `.crbm` index with **no payload reads**, or `null` if the segment has no Storage generation.\n * Powers the free `count()` of a source with no {@link StorageChunkSource.summary} \u2014 the engine sums the index\n * instead of fetching a single chunk. A source with no\n * index (e.g. the in-memory source) omits this, and `count()` falls back to fetching every chunk.\n */\n cardinalities?(ref: SegmentRef): Promise<ReadonlyMap<number, number> | null>;\n /**\n * Optional: the current generation's number, id count and metadata, or `null` if the segment has no Storage\n * generation. The `.crbm` source answers from the registry row's summary when it can use it, which is one\n * registry read and no read of the object, and from the opened generation when it cannot. A source with no\n * summary omits this, and `count()` keeps its other paths.\n */\n summary?(ref: SegmentRef): Promise<GenerationSummary | null>;\n /**\n * Optional: the segment's **current generation number** as this source resolves it right now (registry\n * `currentGen`, or the highest storage generation), or `null` if the segment has no Storage generation. The engine\n * keys its chunk cache by this so a generation bump (a load's publish) is observed \u2014 a new generation\n * misses the cache instead of serving a stale decoded chunk, and an erased id can't resurrect from a cached\n * superseded chunk. Cheap: served from the source's own (short-TTL-refreshed) snapshot, **not** a fresh\n * backend read per call. A source that only ever serves one immutable generation may omit this \u2014 the engine\n * then keys the cache without a generation.\n */\n currentGeneration?(ref: SegmentRef): Promise<number | null>;\n /**\n * Optional: forget everything this source has derived from `ref` \u2014 its resolved snapshot, its open reader,\n * and any key material that reader captured \u2014 so the next read resolves from the registry again.\n *\n * The TTL refresh and the generation-keyed chunk cache are both built for **a publish that advances\n * `currentGen`**. Neither covers an event that *destroys* what the cache was derived from: an erasure that\n * deletes the generation holding the bit, a `dropSegment`, a crypto-shred, a retirement. After one of those\n * a source that had already resolved the segment keeps answering from memory \u2014 with no backend read at all,\n * so no storage-side control can close the window \u2014 until its TTL lapses, and with no bound at all if it has\n * no registry, no clock or `cache.genTtlMs: 0`.\n *\n * Callers that destroy or retire a segment must call this. It is synchronous and best-effort: dropping\n * memoized state cannot fail, and a source that memoizes nothing may omit the method entirely.\n */\n invalidate?(ref: SegmentRef): void;\n /**\n * Optional: does this segment **exist as a registered name**, as distinct from resolving to no generation?\n *\n * `currentGeneration` collapses two very different states into `null`: a name nobody ever created, and a\n * segment that exists and is legitimately empty. For a *read* that distinction does not matter \u2014 both answer\n * empty. For an **operand of a combine** it is the difference between a suppression list with nobody on it\n * yet and a suppression list you misspelled, and those must not look alike: the first correctly suppresses\n * nothing, the second silently suppresses nothing while you believe it is working.\n *\n * Consulted **only** when an operand resolved to no chunks at all, so a normal combine never calls it.\n */\n exists?(ref: SegmentRef): Promise<boolean>;\n /**\n * Optional: an opaque token identifying **which bytes** a read of this segment will see right now \u2014\n * the generation *and* the incarnation of the name it belongs to.\n *\n * {@link StorageChunkSource.currentGeneration} is not enough to key a decoded-chunk cache, and the gap is not\n * theoretical: a load numbers its generation from the row's pointer and what is in the bucket, so the number\n * **restarts at 0** once a registry row is purged and the bucket emptied. A retired, re-created name therefore\n * serves different data at the same `currentGen`, and a cache keyed on `(segment, chunk, generation)` hands back\n * the previous incarnation's ids \u2014 an erased id reappearing, with no read to intercept.\n *\n * Note that putting the incarnation in the *object key* would not fix this: the new incarnation still starts\n * at generation 0, so the cache key collides either way. The identity has to reach the cache.\n *\n * Returns `null` when the segment resolves to no generation. A source that only ever serves one immutable\n * generation may omit this, and the engine falls back to the generation alone.\n */\n currentVersion?(ref: SegmentRef): Promise<string | null>;\n}\n\n/** Capabilities a Storage driver advertises; validated at wiring time, fail-fast. */\nexport interface StorageCaps {\n /** REQUIRED \u2014 the format relies on byte-range reads. */\n readonly rangeRead: true;\n /** Largest single object the backend accepts (informs single-object-vs-shard \u2014 future). */\n readonly maxObjectBytes: number;\n /** Optional: enables the pure-object `LATEST`-pointer registry variant (S3 conditional put). */\n readonly conditionalPut?: boolean;\n}\n\n/**\n * Immutable object storage for `.crbm` generations. A \"dumb byte mover\": it\n * understands neither roaring nor the `.crbm` layout, only opaque bytes addressed by a {@link GenKey}.\n * The core never reuses a key, so puts are write-once.\n *\n * **What a driver must do** \u2014 callers rely on each of these, and the storage conformance suite holds every\n * shipped driver to them:\n *\n * - **`putImmutable` is write-once and reports a collision as {@link WriteConflictError}.** It never overwrites a\n * stored object, two concurrent writes of one key included: exactly one lands. `load` reads that error as a lost\n * race for the generation number (`superseded`), so a driver that threw anything else for an existing key would\n * surface as a failed load. A write whose writer fails stores nothing, and the key can be written after.\n * - **Keys keep every name apart.** One segment in two namespaces, two names an encoding could fold into one (`a/b`\n * and `a_b`), and a name that extends another (`s` and `s.1`) are separate objects, each listed and deleted alone;\n * generations are listed and deleted by number, never by a prefix of one.\n * - **A bucket or container that does not exist is not a missing object**: it fails with an error that is neither\n * {@link NotFoundError}, which would read as an empty segment, nor a {@link TransientError}, which a retry cannot fix.\n * - **A missing object makes `getRange` and `getTail` throw {@link NotFoundError}** \u2014 never an empty or short\n * result. Heal-forward (a read whose generation a sweep collected re-resolves), the erasure's holder probe and\n * its verify of the rewrite, and a pin's replaced-object check all branch on that one error. (A zero-length\n * `getRange` may answer empty without reaching the backend, so it proves neither that the object exists nor\n * that the offset lies inside it: the cloud drivers answer it empty, the memory and local-filesystem drivers\n * throw for a missing object or an offset past the end.)\n * - **An out-of-range read throws {@link ValidationError}**: a range that runs past the end of the object, or a\n * negative or non-integer offset or length. Never a clamped, short or adjacent read. A pin whose object\n * was purged and loaded again as a smaller one asks for a range past its end, and this error is what sends it\n * to check that the object is still the one it pinned.\n * - **`getTail` reports the object's true total size**, not the number of bytes it returned.\n * - **`delete` is idempotent.** Deleting an absent key is a no-op, not an error: collection passes race each\n * other and retry.\n * - **`list` is strongly consistent, read-after-delete.** Once `delete` has resolved, `list` no longer yields\n * that generation, and once `putImmutable` has resolved it does. The erasure's re-check for a generation still\n * holding the id, `dropSegment`'s `generationsRemaining`, the retention sweep's check that a tombstone's storage\n * is gone, and rollback's post-move check prove a deletion or a presence by listing, so a listing that lags\n * reports an erasure as incomplete or a stale object as gone.\n * - **`list` yields every generation, however many pages the service splits it into.** One that stops after its\n * first page drops generations from every collection and every check above.\n * - **Never replay a conditional write without telling the replay apart.** A `putImmutable` that lands and then\n * loses its response, sent again, finds its own object and would report a collision. Either send each write\n * once, with the backend client's retry off for that request, or recognise your own write when the\n * precondition fails by reading an id you stored with it back, and treat a match as success. The first is\n * what the registry writes of every shipped driver do; the second is what the Azure Blob driver and the\n * resumable GCS upload do, and what the S3 driver and the single-request GCS upload do when they send an object\n * again after a throttle, which is the one replay a driver may make on purpose.\n * - **Raise a transient fault as {@link TransientError}** (throttling, a 5xx, a dropped connection), so the read\n * retry can ride it out and a write's caller can tell it from a deterministic failure.\n */\nexport interface IStorageDriver {\n capabilities(): StorageCaps;\n /**\n * Stream a new immutable generation. The driver opens a destination, hands `write` a {@link BlobSink},\n * then atomically commits (and computes the content hash). Throws {@link WriteConflictError} if the key\n * already exists (write-once).\n */\n putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }>;\n /**\n * Range read; the caller bounds-checks. Out-of-range throws {@link ValidationError}, never a short/adjacent\n * read, and a missing object throws {@link NotFoundError}.\n */\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;\n /**\n * Speculative tail read: the last `min(maxBytes, size)` bytes + the object's **true total size**. A missing\n * object throws {@link NotFoundError}.\n */\n getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }>;\n /** Idempotent: deleting an absent key is a no-op, not an error. */\n delete(key: GenKey): Promise<void>;\n /**\n * Enumerate the generations present for a segment (orphan sweep / latest-gen resolution). Strongly\n * consistent, read-after-delete and read-after-put.\n */\n list(ref: SegmentRef): AsyncIterable<GenKey>;\n}\n\n/**\n * Lifecycle status of a segment. `active` is the steady state; `destroyed` is the post-crypto-shred tombstone\n * (the row is kept for audit but the segment is logically gone).\n */\nexport type RegistryStatus = 'active' | 'destroyed';\n\n/**\n * Free-form, JSON-serializable governance metadata \u2014 a **plain object** (both registry boundaries reject `null`,\n * an array or a primitive, because a reader that tests `'key' in meta` would throw an untyped `TypeError`).\n *\n * `retention` has one **reserved key with defined semantics**: `expiresAt`, an absolute epoch-ms after which a\n * retention sweep may retire the segment \u2014 written by `setSegmentRetention`, parsed by `readRetentionPolicy`. Any\n * other key is yours (a legal hold, a note, an owner) and is preserved across policy writes. `residency` is still\n * shape-later: stored and round-tripped, no semantics attached.\n */\nexport type GovernanceMeta = Record<string, unknown>;\n\n/**\n * A cached description of one generation, carried on the registry row: how many ids it holds, and the metadata it\n * was loaded with. The generation's `.crbm` object stays the truth; this is a copy, written by the same write that\n * moves the pointer, and it names the generation it describes so a copy left behind by a writer that did not\n * carry it can never be taken for another generation's.\n *\n * Two shapes. On a cleartext segment the values are in the clear. On an encrypted segment (a row with\n * `wrappedDeks`) they are sealed under the segment's data key, as the generation's index is, so the row reveals\n * neither the count nor the metadata. A shipped registry refuses a write whose summary disagrees with the row's\n * keys. It still reads a stored row that disagrees, so that one such row cannot stop every listing: a reader must not\n * use that row's summary.\n */\nexport type RegistrySummary = ClearRegistrySummary | SealedRegistrySummary;\n\n/**\n * A generation's metadata: string keys, string or finite-number values, no nesting, at most 1 KiB as canonical JSON.\n * The rules are in `core/metadata.ts`.\n */\nexport type GenerationMetadata = Readonly<Record<string, string | number>>;\n\n/** What a generation is, as one read answers it: its number, its id count and the metadata it was written with. */\nexport interface GenerationSummary {\n readonly generation: number;\n readonly cardinality: number;\n /** Absent when the generation has none. */\n readonly metadata?: GenerationMetadata;\n}\n\n/** {@link RegistrySummary} on a cleartext segment. */\nexport interface ClearRegistrySummary {\n /** The generation this describes. A non-negative safe integer. */\n readonly generation: number;\n /** How many ids the generation holds: an integer from 0 to 2^32. */\n readonly cardinality: number;\n /** The generation's metadata, when it has any. Never the empty object. */\n readonly metadata?: GenerationMetadata;\n}\n\n/** {@link RegistrySummary} on an encrypted segment. */\nexport interface SealedRegistrySummary {\n /** The generation this describes. A non-negative safe integer. */\n readonly generation: number;\n /**\n * Base64 of `nonce(12) \u2016 ciphertext \u2016 tag(16)`, sealing the cardinality as a little-endian u64 followed by the\n * metadata's canonical JSON, if any. The count is fixed-width, so the length reveals only the metadata's size.\n */\n readonly sealed: string;\n}\n\n/**\n * One lease on a generation. It names no fingerprint: a collector spares a generation by number and cannot compare an\n * object without reading it, and a purge and re-create drops the whole list with the row. A pin's own fingerprint,\n * which its reads check, stops a number retaken after a rollback being read as the leased object; the entry then spares a\n * different object from collection until it ends, at most the longest lease.\n */\nexport interface LeaseEntry {\n /** 16 lowercase hex digits drawn once per pin call; names the holder, so a retried write is idempotent. */\n readonly holder: string;\n /** The generation held. */\n readonly generation: number;\n /** Epoch-ms the lease runs to on the holder's clock; a collector holds it for the skew margin longer. */\n readonly until: number;\n}\n\n/**\n * One registry row \u2014 the authoritative per-segment record. Exactly one per segment.\n */\nexport interface RegistryRecord extends SegmentRef {\n /**\n * **The** authoritative LATEST pointer: which immutable Storage generation is current \u2014 or **`null` for a segment\n * that has no Storage generation yet.**\n *\n * `null` is not \"unknown\", it is a positive statement: *this segment exists and has no Storage data.* It is what\n * lets a segment have a registry row **before its first load** \u2014 `setSegmentRetention` mints one so a policy\n * can be recorded ahead of the data, and so the segment is reachable by `registry.list()` and therefore by\n * retention sweeps, `checkConsistency` and every other fleet-wide operation. The alternative \u2014 a row with\n * `currentGen: 0` and no object behind it \u2014 is the forbidden `missing-storage-generation` state, which fails per\n * read with `NotFoundError`. Generation resolution maps `null` onto the same path a segment with **no row**\n * takes: every read answers empty, and the first publish advances the pointer.\n */\n readonly currentGen: number | null;\n /**\n * Per-segment data-key (DEK) wrappings for encryption-at-rest: the DEK envelope-wrapped under one or more KEKs\n * (active + optional recovery). Reading unwraps with any held KEK; **crypto-shred deletes this whole list**,\n * making the segment's at-rest bytes permanently unrecoverable. Absent \u21D2 the segment is cleartext.\n */\n readonly wrappedDeks?: readonly WrappedDek[];\n /**\n * Optional **external** key reference (reserved) \u2014 e.g. a KMS key ARN for a future KMS keystore adapter that\n * keeps wrapped material in the KMS rather than in-band {@link wrappedDeks}. Unused by the in-process BYOK\n * keystore. Clearable on crypto-shred.\n */\n readonly keyId?: string;\n readonly status: RegistryStatus;\n /**\n * Governance policy. `retention.expiresAt` drives the retention sweep (see {@link GovernanceMeta}); `residency`\n * is stored and round-tripped with no semantics yet. Both must be plain objects, and both must survive a\n * `list()` projection \u2014 a fleet sweep reads the policy from the enumeration rather than per-segment.\n */\n readonly retention?: GovernanceMeta;\n readonly residency?: GovernanceMeta;\n /**\n * A cached description of the current generation (see {@link RegistrySummary}). Optional: a row without one is\n * correct, and a reader then opens the generation instead. Trusted only for the generation it names.\n */\n readonly summary?: RegistrySummary;\n /**\n * The generations below `currentGen` that the last publish kept as its grace window, ascending. Optional: absent\n * means the row does not know which generations are kept, and a load then lists the bucket to collect and records\n * them; an empty list means none are. Trusted only while every entry is below `currentGen`. A patch that moves\n * `currentGen` without naming it drops it.\n */\n readonly keptGens?: readonly number[];\n /**\n * The leases on this segment's generations: each keeps one generation out of a load's collection until it ends.\n * Optional; absent means none. Unlike {@link keptGens} it does not follow the pointer: a patch that moves\n * `currentGen` leaves it as it was, and only a patch that names it, or the row going away, changes it. Entries\n * past their end are ignored by every collector and pruned by the next write that names the list. A row's identity\n * is its token, so a purged and re-created segment starts with none.\n */\n readonly leases?: readonly LeaseEntry[];\n /** Epoch-ms of creation / last mutation (from the driver's injected clock). */\n readonly createdAt: number;\n readonly updatedAt: number;\n /**\n * Opaque OCC token \u2014 compare-by-equality, ABA-safe. A shipped registry gives no two writes under one name the same\n * token: not two writes of this row, not a write of an earlier row under the name, and not a write after this row is\n * restored from a backup. It holds with overwhelming probability rather than by construction, since the token carries random parts: a\n * 128-bit incarnation id drawn when the row is created, and a 64-bit part drawn for each write. Two incarnations of one\n * name meet with probability 2^-128 for any pair (about n^2 / 2^129 among n of them), and two writes at one counter,\n * after a restore, with probability 2^-64. A bare decimal token, on a row no 0.12 or later registry has written,\n * carries neither part.\n */\n readonly token: Token;\n}\n\n/** The caller-settable fields at {@link IRegistryDriver.create} (audit + token are driver-managed). */\nexport interface NewRegistryRecord {\n /** `null` \u21D2 the segment has no Storage generation yet \u2014 see {@link RegistryRecord.currentGen}. */\n readonly currentGen: number | null;\n readonly wrappedDeks?: readonly WrappedDek[];\n readonly keyId?: string;\n /** Defaults to `'active'`. */\n readonly status?: RegistryStatus;\n readonly retention?: GovernanceMeta;\n readonly residency?: GovernanceMeta;\n /** Must name `currentGen` when given. */\n readonly summary?: RegistrySummary;\n /** Every entry below `currentGen`, ascending; see {@link RegistryRecord.keptGens}. */\n readonly keptGens?: readonly number[];\n}\n\n/**\n * Fields a {@link IRegistryDriver.compareAndSwap} may mutate (identity + audit + token are off-limits).\n *\n * Presence-based: a field the patch does not mention is left as it was. `summary` is the one exception, because it\n * describes the current generation: a patch that moves `currentGen` and does not mention `summary` drops the old\n * one rather than keep a description of another generation. A `summary` the patch gives must name the\n * `currentGen` the row will have. `keptGens` follows the pointer the same way: a patch that moves `currentGen` and does\n * not mention it drops it, and one that gives it must name only generations below the `currentGen` the row will have.\n */\nexport type RegistryPatch = Partial<\n Pick<\n RegistryRecord,\n | 'currentGen'\n | 'wrappedDeks'\n | 'keyId'\n | 'status'\n | 'retention'\n | 'residency'\n | 'summary'\n | 'keptGens'\n | 'leases'\n >\n>;\n\n/**\n * What a caller passes {@link IRegistryDriver.create} or {@link IRegistryDriver.compareAndSwap} besides the write itself.\n */\nexport interface RegistryWriteOptions {\n /**\n * The row the caller read, and is writing against: the record a {@link IRegistryDriver.get} of this registry returned\n * to it, or `null` when that read found no row. A driver that would read the row to learn the version its conditional\n * write is fenced on can use the one it observed then, and send the write at once.\n *\n * It is a hint, and never the fence: the write is still conditioned on the store's own version of the row, so a row\n * that has changed since makes it fail as a lost race does, with {@link WriteConflictError}. A driver reads the row\n * as it does without a hint when it does not recognise the record (one it did not return, or one that is not of\n * this row), or when `held` and the `expected` token of a `compareAndSwap` disagree. A write that gets no answer is\n * settled by reading the row, never by this record. A driver that ignores the option reads the row.\n */\n readonly held?: RegistryRecord | null;\n}\n\n/** Capabilities a registry driver advertises; validated fail-fast at wiring time. */\nexport interface RegCaps {\n /** REQUIRED \u2014 `currentGen` feeds read correctness + the publish CAS, so reads must be strongly consistent. */\n readonly strongRead: true;\n /**\n * `false` when this registry cannot write a row in this runtime, though it reads: a shipped registry draws random\n * bytes for every token it issues, and on a runtime with no Web Crypto it has none to draw. A write path that\n * writes an object before its row (a load, an erasure rewrite) checks it first and refuses with `UnsupportedError`\n * before it writes anything, rather than leave an object no row names. Absent means the registry can write.\n */\n readonly canWrite?: false;\n /**\n * `true` when this registry's `delete` removes a row from its backend for good, so that no later `list` reads it, and\n * removes it only while it is still the exact version the delete read: by a delete the backend applies under a\n * precondition (an S3 or Azure Blob ETag, a GCS object generation), or under a lock no other writer of the backend\n * can take. Only a row whose token carries an incarnation id is removed so. A row first written by a release before\n * 0.12 has a bare decimal token, and a delete still tombstones it: a process on that release, re-creating the name\n * over nothing, would issue those counters again from 0, so its row could not be told apart from the deleted one.\n *\n * `false` or absent: every `delete` leaves a tombstone, which every later full `list` still reads. A shipped registry\n * says which it is.\n */\n readonly conditionalDelete?: boolean;\n}\n\n/**\n * Refuse, with `UnsupportedError`, a write that would write an object before its row when the registry reports it\n * cannot write a row (see {@link RegCaps.canWrite}). Called before the write's first request.\n */\nexport function assertRegistryCanWrite(registry: IRegistryDriver, what: string): void {\n if (registry.capabilities().canWrite === false) {\n throw new UnsupportedError(\n `${what}: the registry reports it cannot write a row in this runtime (capabilities().canWrite is false), ` +\n 'so nothing is written',\n );\n }\n}\n\n/**\n * Brand for {@link StorageBackend}.\n *\n * `Symbol.for` rather than a class check, for the same reason the error brands are: a class object is only\n * shared while one copy of core is loaded, so a backend built from one copy and checked by another \u2014 after a\n * version skew, or behind a duplicating bundler \u2014 would fail an `instanceof`. A registered symbol is\n * identity-stable across all of them, and across realms.\n *\n * A brand string is part of that identity contract, so once a release carries one it never changes: a changed\n * string would stop matching the copies already installed.\n */\nconst STORAGE_BACKEND_BRAND: unique symbol = Symbol.for('cloudbitmaps.storage-backend');\n\n/**\n * Where a store keeps everything: the generations, and the pointer saying which one is current.\n *\n * **Branded on purpose.** The two fields alone are not enough to qualify, and that is the whole point. This\n * shape is also {@link LoadDeps}, so before the brand any `{ storage, registry }`\n * object literal satisfied it \u2014 including one assembling halves from two *unrelated* stores, which the store\n * accepted and then answered **empty** for a segment that holds data, because it read a pointer from a place\n * nothing had ever been written. That is the exact silent-empty failure one-class-per-backend exists to\n * remove, and it was reachable in five lines.\n *\n * So a backend comes from `MemoryStorage`, `LocalFsStorage`, `S3Storage`, `GcsStorage` or\n * `AzureBlobStorage` \u2014 each deriving both halves from one bucket and one prefix. A driver author composing halves\n * of their own says so on purpose, with {@link brandAsBackend}. The halves stay readable as `.storage` /\n * `.registry`, because the free functions genuinely need them.\n *\n * **What this stops is the accident, not a determined caller.** The brand is a registered symbol, so it can\n * be written by hand; nothing here is a security boundary. It stops the two spellings people reach for\n * without deciding to \u2014 an object literal, and a spread of a real backend.\n */\nexport interface StorageBackend {\n /** Cross-bundle brand. Set by the backend classes; not part of the public surface. */\n readonly [STORAGE_BACKEND_BRAND]: true;\n /** Where the immutable `.crbm` generations live. */\n readonly storage: IStorageDriver;\n /** Where the `currentGen` pointer, the discovery index and the wrapped DEKs live. */\n readonly registry: IRegistryDriver;\n /**\n * Optional. A store with a metrics sink calls this once, as it is built, with that sink (already safe to call: it\n * never throws back). A backend that has something to say about its own setup, such as a pool it can read and finds\n * small, keeps the sink and emits an `advisory` event to it later. A backend without it is simply never told. One backend\n * may be handed to several stores, and is called once by each, with each store's own sink. It must not throw: an\n * exception propagates from the store's constructor, so a backend's bug fails fast rather than going unseen.\n */\n attachMetrics?(sink: IMetricsSink): void;\n}\n\n/**\n * The brand key, for the type-only `declare` field a backend class carries.\n *\n * Exported from `@cloudbitmaps/core/driver-kit` and part of the driver contract: a third-party storage\n * package needs it to declare the field that {@link brandAsBackend} then stamps at runtime.\n */\nexport const STORAGE_BACKEND: typeof STORAGE_BACKEND_BRAND = STORAGE_BACKEND_BRAND;\n\n/**\n * Stamp the brand on a backend, **non-enumerably**, after checking both halves are drivers. Returns `target`.\n *\n * This is the driver author's door, and it works on a backend class (`brandAsBackend(this)` as the last line of\n * its constructor) and on a plain `{ storage, registry }` object alike \u2014 the latter is how a backend of your\n * own halves is built: a driver wrapped for auditing, metrics, tenant scoping or client-side encryption, or\n * paired with a registry in a database you already run. An application does not need it: it gets both halves\n * from one backend class, which derives them from one bucket and one prefix so they cannot disagree.\n *\n * It throws {@link ValidationError} when `storage` has no `putImmutable` or `registry` has no `compareAndSwap`,\n * so a half that is not a driver is refused here rather than at its first write, and when `target` is frozen or\n * non-extensible, since the brand is stamped on it in place.\n *\n * It cannot check that the halves agree: `IStorageDriver` and `IRegistryDriver` do not expose a location, so\n * nothing here can compare one. Branding two unrelated halves is you taking that on \u2014 the plain\n * `{ storage, registry }` literal is refused by the store precisely because it let the two halves come from\n * unrelated places by accident, and answer **empty** rather than fail.\n *\n * Non-enumerable is load-bearing, not tidiness. A class field (`readonly [BRAND] = true`) emits an\n * *enumerable* own property, and spread and `Object.assign` copy exactly those \u2014 so\n * `{ ...backend, registry: other.registry }` carried the brand and was accepted, reproducing the silent-empty\n * bug the brand exists to close. This does not make the brand unforgeable \u2014 the symbol is registered, so anyone\n * who wants it can write `Symbol.for('cloudbitmaps.storage-backend')`. That is deliberate effort equivalent to\n * calling this function, and it is not what the check is for. The check is for the accident.\n */\nexport function brandAsBackend<T extends { storage: IStorageDriver; registry: IRegistryDriver }>(\n target: T,\n): T & StorageBackend {\n if (target === null || typeof target !== 'object') {\n throw new ValidationError('brandAsBackend needs `{ storage, registry }`');\n }\n const { storage, registry } = target;\n if (\n storage === null ||\n typeof storage !== 'object' ||\n typeof storage.putImmutable !== 'function'\n ) {\n throw new ValidationError(\n 'brandAsBackend: `storage` must be an IStorageDriver (it has no `putImmutable`)',\n );\n }\n if (\n registry === null ||\n typeof registry !== 'object' ||\n typeof registry.compareAndSwap !== 'function'\n ) {\n throw new ValidationError(\n 'brandAsBackend: `registry` must be an IRegistryDriver (it has no `compareAndSwap`)',\n );\n }\n try {\n Object.defineProperty(target, STORAGE_BACKEND_BRAND, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n } catch {\n // A frozen, sealed or non-extensible object cannot take the brand, and the brand is stamped in place.\n throw new ValidationError(\n 'brandAsBackend: cannot brand a frozen or non-extensible object \u2014 pass a plain object or a class instance',\n );\n }\n return target as T & StorageBackend;\n}\n\n/**\n * Is this a branded backend \u2014 from a backend class or from {@link brandAsBackend}?\n *\n * Checks the brand, not the shape \u2014 see {@link StorageBackend} for why the shape alone is not enough.\n */\nexport function isStorageBackend(value: unknown): value is StorageBackend {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[STORAGE_BACKEND_BRAND] === true\n );\n}\n\n/**\n * Per-segment registry \u2014 the authoritative source of `currentGen`, the discovery index, and the wrapped-DEK\n * holder. One row per segment under OCC: an equality-compared {@link Token} that is never reused, with overwhelming\n * probability (ABA-safe across delete\u2192recreate).\n *\n * **What a driver must do** \u2014 callers rely on each of these, and the registry conformance suite holds every\n * shipped driver to them:\n *\n * - **`create` and `compareAndSwap` are atomic conditional writes.** A `create` over a live row, and a\n * `compareAndSwap` whose token is not the stored one, throw {@link WriteConflictError} and change nothing.\n * Two racing writers have exactly one winner.\n * - **A token is not reused, not even across `delete` then `create`**, short of a collision of probability 2^-128 for\n * any two incarnations of one name: a recreated row carries a token no earlier incarnation held, so a stale holder\n * cannot swap into it. The shipped drivers draw a random 128-bit incarnation id into the token of every row they\n * create and a random 64-bit part into the token of every write, beside a counter a tombstone (or a global counter)\n * keeps going; where nothing of the earlier row is left, or the row is restored from a backup to an older counter, the\n * random parts alone keep the tokens apart: with probability 1 - 2^-128 per pair of incarnations, and 1 - 2^-64 per\n * pair of writes at one counter.\n * - **`delete` is idempotent** without an `expected` token: deleting an absent row is a no-op, not an error.\n * **With `expected` it is fenced**: it lands only while the row still carries that token, and otherwise throws\n * {@link WriteConflictError} and leaves the row.\n * - **Reads are strongly consistent** (`RegCaps.strongRead`), and `list` yields every existing row,\n * `destroyed` tombstones included, with every field (see {@link IRegistryDriver.list}), however many pages the\n * service splits the listing into.\n * - **A bucket or container that does not exist is not an absent row**: a read, a listing and a write fail with an\n * error that is neither {@link NotFoundError} nor a {@link TransientError}, and a read never answers `null`, which would\n * read as a segment with no generation.\n * - **Never replay a conditional write without telling the replay apart.** A `create` or `compareAndSwap`\n * that lands and then loses its response, sent again, finds its own write and would report a conflict.\n * Either send each write once, with the backend client's retry off for that request, or recognise your own\n * write when the precondition fails by reading an id you stored with it back. The shipped registries do\n * one or the other.\n * - **Raise a transient fault as {@link TransientError}.**\n */\nexport interface IRegistryDriver {\n capabilities(): RegCaps;\n /**\n * The segment's record, or `null` if it doesn't exist (or was deleted). Throw {@link TransientError} for a fault\n * worth riding out (throttling, a 5xx, a dropped connection): a reader whose pointer refresh meets one keeps\n * serving what it holds and asks again shortly, while any other error reaches the read that met it.\n */\n get(ref: SegmentRef): Promise<RegistryRecord | null>;\n /**\n * Create the row; throws {@link WriteConflictError} if it already exists (use CAS to mutate). With\n * `options.held` of `null`, the caller found no row: a driver may send the create-only write without reading first,\n * and one that then loses it reads the row, as it does without the hint.\n */\n create(\n ref: SegmentRef,\n record: NewRegistryRecord,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }>;\n /**\n * Server-side compare-and-set: apply `patch` iff the stored token equals `expected`, else `WriteConflictError`.\n * `options.held` is the row the caller read, which a driver may use to skip its own read; see\n * {@link RegistryWriteOptions}.\n */\n compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n options?: RegistryWriteOptions,\n ): Promise<{ token: Token }>;\n /**\n * Discovery: every **existing** record, optionally scoped to one namespace. Order is unspecified.\n *\n * \"Existing\" means not `delete`d. A **`destroyed` tombstone is still a record and must be yielded** \u2014 a driver\n * that filters by `status` breaks callers silently, and two already depend on seeing them: `runConsistencyCheck`\n * skips them itself, and the retention sweep can only clean up a tombstone row it can see (filtering it makes\n * the cleanup a permanent no-op, indistinguishable from having nothing to do, while dead rows accumulate). Same\n * rule for every other field: a row with **`currentGen: null`** must be yielded like any other, and `retention`\n * must survive the projection \u2014 a fleet sweep reads the policy straight out of this enumeration rather than\n * paying a `get()` per segment, so a `list()` that drops the field means nothing ever expires, silently.\n */\n list(namespace?: string): AsyncIterable<RegistryRecord>;\n /**\n * Remove the row. A registry whose {@link RegCaps.conditionalDelete} is `true` removes a row whose token carries an\n * incarnation id from its backend; every other row is tombstoned. Either way a later `create` gets a token no\n * earlier incarnation of the name held, but for a collision of probability 2^-128 per pair of incarnations.\n *\n * Without `expected`, idempotent: deleting an absent row is a no-op.\n *\n * With `expected`, the delete is **fenced like a {@link IRegistryDriver.compareAndSwap}**: it lands only while\n * the row still carries exactly that token, and otherwise \u2014 the token differs, or the row is absent or already\n * deleted \u2014 throws {@link WriteConflictError} and leaves the row. Pass the token of the row you read when you\n * decided to delete it, so a delete that is delayed, replayed, or racing a re-create cannot tombstone a row\n * created after the decision. A third-party driver that ignores `expected` keeps the unfenced behaviour.\n */\n delete(ref: SegmentRef, expected?: Token): Promise<void>;\n}\n", "/**\n * Shared key-grammar fragments used by every driver's logical-ref \u2192 physical-key mapping.\n *\n * One copy of the `_default` namespace sentinel for every driver that maps a namespace to a key or a path. Pure\n * string logic, no SDK, no I/O \u2014 it 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. A caller MAY name a namespace `_default`; it simply does not collide, because\n * `namespaceKeyPart`/`namespacePathPart` encode the caller's namespace (to `%5Fdefault`) and emit this\n * sentinel literally. The separation is a property of the encoding, not of a grammar; reading it as a grammar is\n * exactly what would make the collision easy to reintroduce.\n */\nexport const DEFAULT_NAMESPACE = '_default';\n\n/**\n * The physical namespace component of an **object key**: the caller's namespace encoded, or the sentinel.\n *\n * The sentinel is emitted **literally, never encoded**, and that asymmetry is the whole point. Encoding it too\n * would send an absent namespace to `%5Fdefault` \u2014 exactly where a caller who names their namespace `_default`\n * already goes, since the encoder escapes their leading underscore. Both would land in one place and read each\n * other's data. Encoding only the caller's side means `_default` (ours) and `%5Fdefault` (theirs) are two\n * different strings, and no caller can produce the first.\n */\nexport function namespaceKeyPart(namespace: string | undefined): string {\n return namespace === undefined ? DEFAULT_NAMESPACE : encodeNameForKey(namespace);\n}\n\n/** As {@link namespaceKeyPart}, for a filesystem path component. */\nexport function namespacePathPart(namespace: string | undefined): string {\n return namespace === undefined ? DEFAULT_NAMESPACE : encodeNameForPath(namespace);\n}\n\n// The name codec lives in `core/` (pure string logic, and `validate.ts` needs it); imported here so the\n// drivers keep one import for key shaping, and re-exported for the same reason.\nimport { encodeNameForKey, encodeNameForPath } from '@/core/name-codec';\n\nexport {\n encodeNameForKey,\n decodeNameFromKey,\n encodeNameForPath,\n decodeNameFromPath,\n} from '@/core/name-codec';\n", "/**\n * The generations a segment's row records as kept: the grace window below its pointer, so a load collects what its\n * publish pushed out of the window by name instead of listing the bucket.\n *\n * The record is a cache of what a listing would keep, never an inventory of the bucket. Absent means the row does not\n * know, and the load lists; an empty list means nothing below the pointer is kept. A patch that moves the pointer\n * without naming the list drops it (see `applyRegistryPatch`), so a writer that forgets the list leaves a row that\n * lists, never one that deletes a generation it should keep. Pure: no I/O, time or randomness.\n */\nimport type { RegistryRecord } from './ports';\n\n/**\n * The most generations a writer records. A `keep` above it records none, and the load lists on every publish. A\n * reader accepts up to {@link MAX_STORED_KEPT_GENERATIONS}, so a release can write more than this without a new row\n * schema.\n */\nexport const MAX_KEPT_GENERATIONS = 64;\n\n/** The most entries a stored row may hold: four times what a writer writes. */\nexport const MAX_STORED_KEPT_GENERATIONS = 256;\n\n/**\n * The row's list when a collection may rely on it: present, on a row with a pointer, and every entry below that\n * pointer. A well-formed list that disagrees with the pointer is read but not used (the load lists instead), as a\n * summary that names another generation is.\n */\nexport function usableKeptGens(record: RegistryRecord | null): readonly number[] | undefined {\n const list = record?.keptGens;\n if (record === null || list === undefined || record.currentGen === null) return undefined;\n for (const g of list) if (g >= record.currentGen) return undefined;\n return list;\n}\n\n/** What a publish of a generation writes into the row, and which names it pushes out of the window. */\nexport interface KeptAfter {\n /** The list to write, or `undefined` to write none (the row then does not know, and the next load lists). */\n readonly list: readonly number[] | undefined;\n /** The generations the window no longer keeps, ascending: the names to delete. */\n readonly evict: readonly number[];\n}\n\n/**\n * The list a publish of `generation` over `prev` writes: the newest `keep` of the row's list and the generation that\n * was current, and the names that fell out of it. Only generations that were current are named, so a number a refused\n * or crashed load took is never in it.\n *\n * No list is written when the row has no usable list to extend (except for generation 0, which has nothing below it),\n * when `keep` is above {@link MAX_KEPT_GENERATIONS}, or when no `keep` is given.\n */\nexport function nextKept(\n prev: RegistryRecord | null,\n generation: number,\n keep: number | undefined,\n): KeptAfter {\n const none: KeptAfter = { list: undefined, evict: [] };\n if (keep === undefined || keep > MAX_KEPT_GENERATIONS) return none;\n if (generation === 0) return { list: [], evict: [] };\n const previous = prev?.currentGen ?? null;\n const known = usableKeptGens(prev);\n if (previous === null || known === undefined) return none;\n const all = [...known, previous];\n const cut = Math.max(0, all.length - keep);\n return { list: all.slice(cut), evict: all.slice(0, cut) };\n}\n", "/**\n * Generation metadata: a small, flat record of strings and finite numbers attached to one generation.\n *\n * The rules live here once, for every boundary that meets a value: a caller's input, refused with\n * `ValidationError`, and bytes read back from a tier, refused with `IntegrityError`. The caller passes the error\n * to raise. Pure: no I/O.\n */\nimport type { GenerationMetadata } from './ports';\nimport { isWellFormedString } from './validate';\n\n/** Cap on the canonical JSON of one generation's metadata, in UTF-8 bytes (braces and quotes included). */\nexport const MAX_METADATA_BYTES = 1024;\n/** Cap on one metadata key, in UTF-8 bytes. */\nexport const MAX_METADATA_KEY_BYTES = 128;\n\nconst utf8Length = (s: string): number => new TextEncoder().encode(s).length;\n\n/**\n * Validate `value` as generation metadata (`GenerationMetadata` in the ports) and return its canonical JSON: RFC 8785\n * (the JSON Canonicalization Scheme) for a flat object of strings and finite numbers. Keys are sorted by UTF-16 code\n * unit, strings are escaped as `JSON.stringify` escapes them, numbers are written as ECMAScript's\n * `Number.prototype.toString` writes them (so `-0` is `0`, and `1e21` is `1e+21`), and there is no whitespace. Key\n * order therefore never changes the bytes, and `tests/golden/metadata-canonical.json` holds vectors a port can check\n * itself against. Both caps are in UTF-8 bytes. The container is an object whose prototype is\n * `Object.prototype` or `null`, holding only enumerable data properties with string keys. `fail` raises the error the\n * boundary calls for. The empty object passes and returns `{}`: whether it may be stored is the caller's rule.\n */\nexport function canonicalMetadataJson(value: unknown, fail: (message: string) => never): string {\n if (value === null || typeof value !== 'object') {\n fail(`metadata must be a plain object (got ${value === null ? 'null' : typeof value})`);\n }\n const proto: unknown = Object.getPrototypeOf(value);\n if (\n Object.prototype.toString.call(value) !== '[object Object]' ||\n (proto !== Object.prototype && proto !== null)\n ) {\n fail('metadata must be a plain object, not an array, a Map, a boxed value or a class instance');\n }\n // Each key with the value the rules checked, so the bytes are serialised from that value and never from a second\n // read, which a proxy could answer differently.\n const entries: Array<[string, string | number]> = [];\n const keys = Reflect.ownKeys(value as object);\n for (const key of keys) {\n if (typeof key !== 'string') fail('metadata keys must be strings, not symbols');\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor === undefined || !('value' in descriptor) || descriptor.enumerable !== true) {\n fail(`metadata key ${JSON.stringify(key)} must be an enumerable data property`);\n }\n if (key.length === 0) fail('metadata keys must be non-empty');\n if (key === '__proto__') fail('metadata may not use the key \"__proto__\"');\n if (!isWellFormedString(key)) fail('metadata keys must be well-formed UTF-16');\n // A UTF-16 unit is at most 3 UTF-8 bytes, so a key that short is under the cap without encoding it.\n if (key.length * 3 > MAX_METADATA_KEY_BYTES) {\n const keyBytes = utf8Length(key);\n if (keyBytes > MAX_METADATA_KEY_BYTES) {\n fail(`metadata key is ${keyBytes}B, over the ${MAX_METADATA_KEY_BYTES}B cap`);\n }\n }\n const v: unknown = descriptor.value;\n if (typeof v === 'string') {\n if (!isWellFormedString(v)) {\n fail(`metadata value of ${JSON.stringify(key)} must be well-formed UTF-16`);\n }\n } else if (typeof v !== 'number' || !Number.isFinite(v)) {\n fail(`metadata value of ${JSON.stringify(key)} must be a string or a finite number`);\n }\n entries.push([key, v]);\n }\n // Keys are unique, so comparing them alone orders the entries by UTF-16 code unit.\n entries.sort(([a], [b]) => (a < b ? -1 : 1));\n const json = `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${JSON.stringify(v)}`).join(',')}}`;\n const bytes = utf8Length(json);\n if (bytes > MAX_METADATA_BYTES) {\n fail(`metadata is ${bytes}B as canonical JSON, over the ${MAX_METADATA_BYTES}B cap`);\n }\n return json;\n}\n\n/**\n * The bytes a generation stores for `value`: its canonical JSON in UTF-8, or `undefined` when it has none (`undefined`\n * or the empty object, which store nothing). Synchronous, so what is stored is what the caller passed at the call,\n * whatever it does with its object afterwards. `fail` raises the boundary's error.\n */\nexport function metadataBytes(\n value: unknown,\n fail: (message: string) => never,\n): Uint8Array | undefined {\n if (value === undefined) return undefined;\n const json = canonicalMetadataJson(value, fail);\n return json === '{}' ? undefined : new TextEncoder().encode(json);\n}\n\n/**\n * A caller's metadata, checked against the rules and copied, so what is stored is what the caller passed at the call,\n * whatever it does with its object afterwards: the frozen record in canonical key order, or `undefined` when there is\n * none (`undefined`, or the empty object, which store nothing). Synchronous. `fail` raises the boundary's error.\n */\nexport function copiedMetadata(\n value: unknown,\n fail: (message: string) => never,\n): GenerationMetadata | undefined {\n const bytes = metadataBytes(value, fail);\n return bytes === undefined ? undefined : metadataFromBytes(bytes, fail);\n}\n\n/**\n * Read metadata back from bytes a tier holds, which are untrusted. They must be at most {@link MAX_METADATA_BYTES},\n * valid UTF-8, and exactly the canonical JSON of a non-empty record, so a stored copy has one spelling: whitespace, a\n * key out of order or listed twice, and a number or an escape `JSON.stringify` would write another way are all\n * refused. Returns a frozen record of its own. `fail` raises the boundary's error.\n */\nexport function metadataFromBytes(\n bytes: Uint8Array,\n fail: (message: string) => never,\n): GenerationMetadata {\n if (bytes.length > MAX_METADATA_BYTES) {\n fail(`metadata is ${bytes.length}B, over the ${MAX_METADATA_BYTES}B cap`);\n }\n let text: string;\n try {\n text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);\n } catch {\n fail('metadata is not valid UTF-8');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n fail('metadata is not JSON');\n }\n const json = canonicalMetadataJson(parsed, fail);\n if (json === '{}') fail('metadata is empty; a generation without metadata carries none');\n if (json !== text) fail('metadata is not in canonical form');\n return Object.freeze(parsed as GenerationMetadata);\n}\n", "/**\n * Shared, SDK-free helpers for assembling + validating {@link RegistryRecord}s.\n *\n * The registry's record-construction, patch-application, and field-validation are identical across every\n * backend (memory / LocalFs / object store) \u2014 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`), and no\n * ambient randomness (the caller passes its `Entropy`; the Web Crypto default is in `entropy.ts`).\n */\nimport { IntegrityError, UnsupportedError, ValidationError } from '@/core/errors';\nimport type { Entropy } from '@/core/determinism';\nimport { canonicalMetadataJson, MAX_METADATA_BYTES } from '@/core/metadata';\nimport { INCARNATION_TOKEN, incarnationOf } from '@/core/token';\nimport { MAX_LEASES_PER_SEGMENT, MAX_STORED_LEASES } from '@/core/leases';\nimport {\n MAX_KEPT_GENERATIONS,\n MAX_STORED_KEPT_GENERATIONS,\n usableKeptGens,\n} from '@/core/kept-generations';\nimport type {\n LeaseEntry,\n NewRegistryRecord,\n RegistryPatch,\n RegistryRecord,\n RegistrySummary,\n SegmentRef,\n Token,\n} from '@/core/ports';\n\n/** The valid {@link RegistryStatus} values \u2014 used to validate both caller input and stored bytes. */\nconst STATUSES: readonly string[] = ['active', 'destroyed'];\n/**\n * The fields a stored record may carry: {@link RegistryRecord}'s, and nothing else. A field no reader resolves\n * through is refused on read-back like any other corruption (invariant 5), rather than ignored.\n */\nconst BASE_FIELDS = [\n 'namespace',\n 'segment',\n 'currentGen',\n 'wrappedDeks',\n 'keyId',\n 'status',\n 'retention',\n 'residency',\n 'summary',\n 'createdAt',\n 'updatedAt',\n 'token',\n] as const;\n/**\n * The fields schema 3 added. A schema-2 row carrying one is refused as undeclared. A field that joins schema 3 before\n * it is released is appended here, with its validator, and needs no new schema version.\n */\nconst SCHEMA_3_FIELDS = ['keptGens', 'leases'] as const;\nexport const RECORD_FIELDS = [...BASE_FIELDS, ...SCHEMA_3_FIELDS] as const;\n/** The record fields a row of `schemaVersion` may carry: each schema adds to the one before. */\nfunction fieldsOf(schemaVersion: number): readonly string[] {\n if (schemaVersion >= 3) return RECORD_FIELDS;\n const base: readonly string[] = BASE_FIELDS;\n return schemaVersion === 2 ? base : base.filter((f) => f !== 'summary');\n}\n/** The fields of the persisted envelope around a record. */\nconst ENVELOPE_FIELDS: readonly string[] = ['schemaVersion', 'deleted', 'record'];\n/** Cap on a serialized governance blob (retention/residency) \u2014 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) \u2014 keeps the row small + rejects abuse. */\nconst MAX_WRAPPED_DEKS = 8;\nconst MAX_WRAPPED_DEK_BYTES = 4 * 1024;\n/** Ids a generation can hold: every 32-bit id. */\nconst MAX_SUMMARY_CARDINALITY = 2 ** 32;\n/** A sealed summary's fixed part: a 12-byte nonce, the u64 count, and a 16-byte tag. */\nconst SEALED_SUMMARY_MIN_BYTES = 12 + 8 + 16;\n/** The fixed part plus metadata at its cap. */\nconst SEALED_SUMMARY_MAX_BYTES = SEALED_SUMMARY_MIN_BYTES + MAX_METADATA_BYTES;\n/** Padded standard base64; canonical once its pad bits are checked too (see {@link base64PadBitsAreZero}). */\nconst BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\n\n/** `null` is legal and meaningful: the segment has no Storage generation yet (see `RegistryRecord.currentGen`). */\nfunction validateGeneration(gen: number | null): void {\n if (gen === null) return;\n if (!Number.isSafeInteger(gen) || gen < 0) {\n throw new ValidationError(\n `currentGen must be a non-negative safe integer or null (no Storage generation yet); got ${gen}`,\n );\n }\n}\n\n/**\n * A patch that *mentions* `currentGen` must give it a real value \u2014 `null` to clear the pointer, or a generation.\n * `{ currentGen: undefined }` is refused rather than coerced. `{ currentGen: maybeUndefined }` is what `strict`\n * alone permits, since `exactOptionalPropertyTypes` is off, and a caller writing it means to leave the pointer\n * alone. Under presence-based merging the same call would silently *un-publish* a live segment: every Storage\n * generation goes invisible, and the collection then refuses to collect the objects (no pointer \u21D2 nothing\n * to compare against), so they are stranded and billed forever. Fail fast at the boundary instead.\n */\nfunction validatePatchGeneration(patch: RegistryPatch): void {\n if (!('currentGen' in patch)) return;\n // `validateGeneration(undefined)` fails the integer test on its own, because this check reads the raw patch\n // before `applyRegistryPatch` turns an undefined `currentGen` into `null`; this branch exists to make the\n // *message* say which value to pass instead, because the generic \"must be a non-negative integer or null\"\n // reads like a type error rather than the trap it is.\n if (patch.currentGen === undefined) {\n throw new ValidationError(\n `currentGen was present in the patch but undefined. Pass \\`null\\` to clear the pointer (the segment has no ` +\n `Storage generation), or omit the key to leave it unchanged \u2014 an undefined value is refused because it ` +\n `would un-publish the segment's Storage data.`,\n );\n }\n validateGeneration(patch.currentGen);\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 \u2014 a brick).\n */\nfunction validateGovernance(meta: unknown, field: string): void {\n if (meta === undefined) return;\n // A plain object, not `null`/an array/a primitive. `JSON.stringify(null)` is 4 valid bytes, so without this the\n // size + serializability checks below happily store `\"retention\": null` \u2014 and `retention.expiresAt` is read with\n // an `in` test, which throws an untyped `TypeError` on a non-object and would abort a whole fleet retention\n // sweep rather than becoming one ledger entry. Reject at the write boundary; the read boundary\n // ({@link assertStoredRecordShape}) rejects it too, for a row edited by hand or written by another writer.\n if (meta === null || typeof meta !== 'object' || Array.isArray(meta)) {\n throw new ValidationError(\n `${field} must be a plain object (got ${meta === null ? 'null' : typeof meta})`,\n );\n }\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/** The standard base64 alphabet, whose index of a character is the six bits it carries. */\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Whether a padded standard base64 string is canonical: the bits of its last character past the data are zero.\n * Without this two strings would decode to the same bytes.\n */\nfunction base64PadBitsAreZero(text: string): boolean {\n const pad = text.endsWith('==') ? 2 : text.endsWith('=') ? 1 : 0;\n if (pad === 0) return true;\n const last = BASE64_ALPHABET.indexOf(text[text.length - pad - 1]!);\n return pad === 2 ? (last & 0b1111) === 0 : (last & 0b11) === 0;\n}\n\n/**\n * Validate a {@link RegistrySummary}'s shape at the write or read boundary, and return a frozen copy built from the\n * checked fields only: exactly one of the two shapes, a non-negative safe-integer generation, a cardinality from 0 to\n * 2^32, metadata by the metadata rules (never the empty object, which is never stored) with its keys in canonical\n * order, or a sealed blob in canonical base64 whose length fits a sealed count plus metadata at its cap. A writer\n * stores the copy, so a caller that changes its object after the call, while the driver awaits the row, changes\n * nothing that is written. Whether a summary may be *used* is the reader's rule, not this one: this only bounds what a\n * row can hold. `isStored` picks the error class (write = ValidationError; read = IntegrityError, invariant 5), and a\n * read names the row by `ctx`.\n */\nfunction validateSummary(\n value: unknown,\n isStored: boolean,\n ctx?: string,\n): RegistrySummary | undefined {\n if (value === undefined) return undefined;\n const fail = (msg: string): never => {\n const where = ctx === undefined ? '' : `: ${ctx}`;\n throw isStored\n ? new IntegrityError(`registry record summary: ${msg}${where}`)\n : new ValidationError(`summary: ${msg}${where}`);\n };\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n fail(\n `must be an object (got ${value === null ? 'null' : Array.isArray(value) ? 'an array' : typeof value})`,\n );\n }\n const s = value as Record<string, unknown>;\n const keys = Object.keys(s);\n const isSealed = keys.includes('sealed');\n const allowed = isSealed ? ['generation', 'sealed'] : ['generation', 'cardinality', 'metadata'];\n const extra = keys.filter((k) => !allowed.includes(k));\n if (extra.length > 0) {\n fail(\n `has fields its ${isSealed ? 'sealed' : 'clear'} shape does not declare (${extra.join(', ')})`,\n );\n }\n const generation = s.generation;\n if (!Number.isSafeInteger(generation) || (generation as number) < 0) {\n fail(`generation must be a non-negative safe integer (got ${String(generation)})`);\n }\n if (isSealed) {\n const sealed = s.sealed;\n if (typeof sealed !== 'string' || !BASE64.test(sealed) || !base64PadBitsAreZero(sealed)) {\n fail('sealed must be canonical, padded standard base64');\n }\n const text = sealed as string;\n const bytes = (text.length / 4) * 3 - (text.endsWith('==') ? 2 : text.endsWith('=') ? 1 : 0);\n if (bytes < SEALED_SUMMARY_MIN_BYTES || bytes > SEALED_SUMMARY_MAX_BYTES) {\n fail(\n `sealed is ${bytes}B, outside ${SEALED_SUMMARY_MIN_BYTES}..${SEALED_SUMMARY_MAX_BYTES}B ` +\n '(a nonce, a fixed-width count, a tag, and metadata up to its cap)',\n );\n }\n return Object.freeze({ generation: generation as number, sealed: text });\n }\n const n = s.cardinality;\n if (!Number.isInteger(n) || (n as number) < 0 || (n as number) > MAX_SUMMARY_CARDINALITY) {\n fail(`cardinality must be an integer from 0 to 2^32 (got ${String(n)})`);\n }\n if (s.metadata === undefined) {\n return Object.freeze({ generation: generation as number, cardinality: n as number });\n }\n const canonical = canonicalMetadataJson(s.metadata, fail);\n if (canonical === '{}') fail('metadata is empty; a generation without metadata carries none');\n // A read only checks the stored shape and keeps the object it parsed, so it builds no copy.\n if (isStored) return s as unknown as RegistrySummary;\n // Rebuilt from the canonical JSON, so its keys are in canonical order (JavaScript still lists integer-like keys\n // first, in numeric order, as it does in every object) and nothing of the caller's object is kept.\n const metadata = Object.freeze(JSON.parse(canonical) as Record<string, string | number>);\n return Object.freeze({ generation: generation as number, cardinality: n as number, metadata });\n}\n\n/** A summary given at a write must describe the generation the row will point at. */\nfunction validateSummaryNames(\n summary: RegistrySummary | undefined,\n currentGen: number | null,\n): void {\n if (summary !== undefined && summary.generation !== currentGen) {\n throw new ValidationError(\n `summary describes generation ${summary.generation}, but the row points at ${String(currentGen)}`,\n );\n }\n}\n\n/**\n * Whether a summary's shape agrees with the row's encryption: sealed on a row with wrapped keys, clear on one without.\n * A clear count or metadata beside a key would leak what the segment's objects hide; a sealed one on a cleartext row\n * could never be opened.\n */\nfunction summaryAgreesWithKeys(\n summary: RegistrySummary,\n wrappedDeks: RegistryRecord['wrappedDeks'],\n): boolean {\n return 'sealed' in summary === (wrappedDeks !== undefined);\n}\n\n/** A summary given at a write must agree with the row's encryption (see {@link summaryAgreesWithKeys}). */\nfunction validateSummaryKeys(\n summary: RegistrySummary | undefined,\n wrappedDeks: RegistryRecord['wrappedDeks'],\n): void {\n if (summary !== undefined && !summaryAgreesWithKeys(summary, wrappedDeks)) {\n throw new ValidationError(\n wrappedDeks === undefined\n ? 'summary is sealed, but the row has no wrapped keys to open it with'\n : \"summary is in the clear, but the row is encrypted: an encrypted segment's summary must be sealed\",\n );\n }\n}\n\n/**\n * Validate a {@link RegistryRecord.keptGens} list's shape at the write or read boundary: an array of at most `max`\n * entries, each a non-negative safe integer, strictly ascending (which refuses a duplicate). A write returns a frozen\n * copy, so a caller that changes its array afterwards changes nothing that is written. `isStored` picks the error class\n * (write = ValidationError; read = IntegrityError, invariant 5). Whether the entries are below the pointer is not\n * checked here on a read: a list that disagrees with the pointer is one its reader does not use, not a row to refuse.\n */\nfunction validateKeptGens(\n value: unknown,\n isStored: boolean,\n ctx?: string,\n): readonly number[] | undefined {\n if (value === undefined) return undefined;\n const fail = (msg: string): never => {\n const where = ctx === undefined ? '' : `: ${ctx}`;\n throw isStored\n ? new IntegrityError(`registry record keptGens: ${msg}${where}`)\n : new ValidationError(`keptGens: ${msg}`);\n };\n if (!Array.isArray(value)) fail('must be an array');\n const list = value as unknown[];\n const max = isStored ? MAX_STORED_KEPT_GENERATIONS : MAX_KEPT_GENERATIONS;\n if (list.length > max) fail(`has ${list.length} entries, cap ${max}`);\n let last = -1;\n for (const g of list) {\n if (!Number.isSafeInteger(g) || (g as number) < 0) {\n fail(`entries must be non-negative safe integers (got ${String(g)})`);\n }\n if ((g as number) <= last) fail('entries must be strictly ascending');\n last = g as number;\n }\n return isStored ? (list as number[]) : Object.freeze([...(list as number[])]);\n}\n\nconst HOLDER = /^[0-9a-f]{16}$/;\nconst LEASE_ENTRY_KEYS: readonly string[] = ['holder', 'generation', 'until'];\n\n/**\n * Validate a {@link RegistryRecord.leases} list at the write or read boundary: an array of at most the writer's cap\n * (write) or the reader's (read), each entry exactly `{ holder, generation, until }`, the holder 16 lowercase hex digits\n * and unique, the two numbers non-negative safe integers. A write returns a frozen copy, and an empty list as\n * `undefined`, so a row that never held a lease is the row it was before leases. `isStored` picks the error class\n * (write = ValidationError; read = IntegrityError, invariant 5). Whether an entry is still live, or its generation\n * exists, is not checked here: a collector reads that, and a row is not refused for it.\n */\nfunction validateLeases(\n value: unknown,\n isStored: boolean,\n ctx?: string,\n): readonly LeaseEntry[] | undefined {\n if (value === undefined) return undefined;\n const fail = (msg: string): never => {\n const where = ctx === undefined ? '' : `: ${ctx}`;\n throw isStored\n ? new IntegrityError(`registry record leases: ${msg}${where}`)\n : new ValidationError(`leases: ${msg}`);\n };\n if (!Array.isArray(value)) fail('must be an array');\n const list = value as unknown[];\n const max = MAX_STORED_LEASES; // a write's own cap is applied against the row it patches\n if (list.length > max) fail(`has ${list.length} entries, cap ${max}`);\n const seen = new Set<string>();\n const out: LeaseEntry[] = [];\n for (const e of list) {\n if (typeof e !== 'object' || e === null || Array.isArray(e)) fail('an entry must be an object');\n const entry = e as Record<string, unknown>;\n const extra = Object.keys(entry).filter((k) => !LEASE_ENTRY_KEYS.includes(k));\n if (extra.length > 0) fail(`an entry carries an undeclared field (${extra.join(', ')})`);\n const { holder, generation, until } = entry;\n if (typeof holder !== 'string' || !HOLDER.test(holder)) {\n fail('a holder must be 16 lowercase hex digits');\n }\n if (seen.has(holder as string)) fail('holders must be unique');\n seen.add(holder as string);\n for (const [name, n] of [\n ['generation', generation],\n ['until', until],\n ] as const) {\n if (!Number.isSafeInteger(n) || (n as number) < 0) {\n fail(`${name} must be a non-negative safe integer (got ${String(n)})`);\n }\n }\n out.push(\n isStored\n ? (entry as unknown as LeaseEntry)\n : Object.freeze({\n holder: holder as string,\n generation: generation as number,\n until: until as number,\n }),\n );\n }\n if (isStored) return out;\n return out.length === 0 ? undefined : Object.freeze(out);\n}\n\n/** A non-empty list given at a write needs a pointer to hold generations of. */\nfunction validateLeasesPointer(\n leases: readonly LeaseEntry[] | undefined,\n currentGen: number | null,\n): void {\n if (leases !== undefined && leases.length > 0 && currentGen === null) {\n throw new ValidationError('leases: a row with no pointer has no generation to lease');\n }\n}\n\n/** A list given at a write must name only generations below the pointer the row will have, and none on no pointer. */\nfunction validateKeptGensBelow(\n keptGens: readonly number[] | undefined,\n currentGen: number | null,\n): void {\n if (keptGens === undefined) return;\n if (currentGen === null) {\n throw new ValidationError(\n 'keptGens: a row with no pointer has no generations below it to keep',\n );\n }\n const top = keptGens[keptGens.length - 1];\n if (top !== undefined && top >= currentGen) {\n throw new ValidationError(\n `keptGens names generation ${top}, which is not below the row's pointer ${currentGen}`,\n );\n }\n}\n\n/**\n * Validate the caller-settable fields at `create`, and return the record to store: the caller's, with its summary\n * replaced by the checked, frozen copy {@link validateSummary} builds.\n */\nexport function validateNewRegistryRecord(rec: NewRegistryRecord): NewRegistryRecord {\n validateGeneration(rec.currentGen);\n if (rec.status !== undefined) validateStatus(rec.status);\n validateWrappedDeks(rec.wrappedDeks, false);\n validateGovernance(rec.retention, 'retention');\n validateGovernance(rec.residency, 'residency');\n const keptGens = validateKeptGens(rec.keptGens, false);\n validateKeptGensBelow(keptGens, rec.currentGen);\n const withKept = keptGens === undefined ? rec : { ...rec, keptGens };\n if (!('summary' in rec)) return withKept;\n const summary = validateSummary(rec.summary, false);\n validateSummaryNames(summary, rec.currentGen);\n validateSummaryKeys(summary, rec.wrappedDeks);\n return { ...withKept, summary };\n}\n\n/**\n * Validate the caller-settable fields in a `compareAndSwap` patch, and return the patch to apply: the caller's, with\n * its summary replaced by the checked, frozen copy. That a given `summary` names the row's resulting `currentGen`,\n * and agrees with its resulting keys, needs the stored row, so {@link applyRegistryPatch} checks both.\n */\nexport function validateRegistryPatch(patch: RegistryPatch): RegistryPatch {\n validatePatchGeneration(patch);\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 const withKept =\n patch.keptGens === undefined\n ? patch\n : { ...patch, keptGens: validateKeptGens(patch.keptGens, false) };\n const withLeases =\n 'leases' in withKept\n ? { ...withKept, leases: validateLeases(withKept.leases, false) }\n : withKept;\n if (!('summary' in patch)) return withLeases;\n return { ...withLeases, summary: validateSummary(patch.summary, false) };\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 a re-create carries the counter on and the two\n * incarnations' tokens are apart by construction, as well as by their random parts \u2014 ABA-safety. A row removed by a\n * conditional delete leaves no counter to carry on, so a re-create starts at 0 and only the random parts keep its\n * tokens apart from the old ones. Shared by the\n * persistent drivers (LocalFs file, S3 object).\n *\n * `schemaVersion` is a wire-only concern \u2014 it stamps the persisted bytes, not the in-memory domain object \u2014\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 \u2014 a pre-1.0 format-freeze prerequisite. Every persistent\n * registry driver \u2014 every one of which persists the `{ deleted, record }` envelope \u2014 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 \u2192 `UnsupportedError`\n * (fail-closed); an **absent** or malformed stamp \u2192 `IntegrityError`, since every row this build writes has one.\n *\n * Schema 2 added the record's `summary` and the incarnation-form token; schema 3 adds `keptGens`. Every row this\n * build writes is stamped 3, whatever it holds, and a build that reads only schema 2 refuses it, so a fleet cannot go\n * back once one has been written.\n */\nexport const REGISTRY_SCHEMA_VERSION = 3;\n\n/**\n * The oldest schema this build reads. A schema-1 or schema-2 row is read as it was written; the first write to it\n * stamps it 3.\n */\nconst OLDEST_REGISTRY_SCHEMA_VERSION = 1;\n\n/**\n * Validate a persisted registry row's `schemaVersion` (untrusted bytes, invariant 5) and return it: an absent or\n * malformed value \u2192 `IntegrityError`; a version newer than this build \u2192 `UnsupportedError` (fail-closed rather than\n * misread a format we don't understand).\n */\nexport function assertRegistrySchemaVersion(raw: unknown, ctx: string): number {\n if (raw === undefined) {\n throw new IntegrityError(`registry row has no schemaVersion: ${ctx}`);\n }\n if (typeof raw !== 'number' || !Number.isInteger(raw) || raw < OLDEST_REGISTRY_SCHEMA_VERSION) {\n throw new IntegrityError(`registry row has a malformed schemaVersion (${shown(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 return raw;\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// \u2500\u2500 The OCC token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// A token is `<incarnation>.<counter>.<write>`. The incarnation is 32 lowercase hex digits drawn from injected\n// entropy when the row is created; it keeps a re-created name from ever being taken for an earlier incarnation of\n// it, even once the earlier row's record is gone and nothing is left to continue a counter from. The counter is a\n// canonical decimal that every write of the row advances by one, and carries on across a tombstone, so while a row's\n// history is intact its tokens are apart by construction. The write part is 16 lowercase hex digits drawn afresh for\n// every write: a row restored from a backup is back at an older counter, and without it the writes after the restore\n// would be given the tokens the writes after the backup already had.\n//\n// A row first written by a schema-1 build has a bare decimal counter (`\"7\"`), and gains no incarnation for as long as\n// it lives: a write to it advances the counter and adds a write part (`\"8.<write>\"`). Only a create starts a new\n// incarnation. So a token's form says which kind of row issued it, and no two forms ever compare equal: they differ\n// in how many `.` they hold. Tokens are compared only by equality; nothing orders them.\n\n/** A schema-1 row's token: a canonical decimal counter. */\nconst COUNTER_TOKEN = /^(0|[1-9]\\d*)$/;\n/** A schema-1-born row's token once this build has written it: the counter, a `.`, and a write part. */\nconst WRITTEN_COUNTER_TOKEN = /^(0|[1-9]\\d*)\\.([0-9a-f]{16})$/;\n/** The incarnation id's width, in bytes. */\nconst INCARNATION_BYTES = 16;\n/** The write part's width, in bytes. */\nconst WRITE_BYTES = 8;\n\n/** A token taken apart: its incarnation (absent on a schema-1-born row) and its counter. */\ninterface TokenParts {\n readonly incarnation: string | undefined;\n readonly counter: number;\n}\n\n/**\n * Take a token apart, refusing anything that is not a form a shipped driver writes (invariant 5): `\"1e3\"`, `\"0x10\"`,\n * `\" 5 \"`, `\"\"`, a counter past 2^53, upper-case hex. A stored row of `schemaVersion` 1 holds only a bare counter, and\n * one of 2 only a form with a write part; a record already read (`schemaVersion` undefined) may hold any of them.\n */\nfunction tokenParts(token: string, schemaVersion: number | undefined, ctx: string): TokenParts {\n const bare =\n schemaVersion === undefined || schemaVersion === 1 ? COUNTER_TOKEN.exec(token) : null;\n const written =\n schemaVersion === undefined || schemaVersion >= 2\n ? (WRITTEN_COUNTER_TOKEN.exec(token) ?? INCARNATION_TOKEN.exec(token))\n : null;\n const match = bare ?? written;\n if (match === null) {\n throw new IntegrityError(\n `registry row token is not one a schema-${schemaVersion ?? REGISTRY_SCHEMA_VERSION} row holds ` +\n `(${shown(JSON.stringify(token))}): ${ctx}`,\n );\n }\n const born = match.length === 4; // the incarnation form has three groups\n const counter = Number(born ? match[2] : match[1]);\n if (!Number.isSafeInteger(counter)) {\n throw new IntegrityError(`registry row token's counter is out of safe-integer range: ${ctx}`);\n }\n return { incarnation: born ? match[1] : undefined, counter };\n}\n\nexport { usableKeptGens };\n\n// `incarnationOf` is defined in `core/token`, where the publish reads it too, and is the same function here.\nexport { incarnationOf };\n\n/** `bytes` fresh bytes from `entropy`, as lowercase hex, refusing a source that does not give them. */\nfunction drawHex(entropy: Entropy, bytes: number): string {\n const drawn = entropy(bytes);\n if (!(drawn instanceof Uint8Array) || drawn.length !== bytes) {\n throw new ValidationError(\n `the registry's entropy source must return ${bytes} bytes as a Uint8Array`,\n );\n }\n let hex = '';\n for (const b of drawn) hex += b.toString(16).padStart(2, '0');\n return hex;\n}\n\n/** A fresh incarnation id from `entropy`: 128 bits as 32 lowercase hex digits. */\nexport function drawIncarnation(entropy: Entropy): string {\n return drawHex(entropy, INCARNATION_BYTES);\n}\n\n/** A fresh write part from `entropy`: 64 bits as 16 lowercase hex digits. */\nexport function drawWrite(entropy: Entropy): string {\n return drawHex(entropy, WRITE_BYTES);\n}\n\n/**\n * The token for the write after `record`'s: the same incarnation, if it has one, the counter one on, and a fresh write\n * part. For a compare-and-swap or a tombstone.\n */\nexport function nextRegistryToken(record: RegistryRecord, entropy: Entropy): Token {\n const { incarnation, counter } = tokenParts(record.token, undefined, record.segment);\n const tail = `${counter + 1}.${drawWrite(entropy)}`;\n return incarnation === undefined ? tail : `${incarnation}.${tail}`;\n}\n\n/**\n * The token of a new row: a fresh incarnation and write part from `entropy`, and a counter that continues\n * `tombstone`'s when the row is created over one, else starts at 0.\n */\nexport function newIncarnationToken(\n entropy: Entropy,\n tombstone: RegistryRecord | undefined,\n): Token {\n const counter =\n tombstone === undefined\n ? 0\n : tokenParts(tombstone.token, undefined, tombstone.segment).counter + 1;\n return `${drawIncarnation(entropy)}.${counter}.${drawWrite(entropy)}`;\n}\n\n/** A stored value as a message shows it: at most 64 characters, so a hostile row cannot fill every log line it reaches. */\nfunction shown(v: unknown): string {\n const text = String(v);\n return text.length > 64 ? `${text.slice(0, 64)}\u2026` : text;\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 \u2014\n * fail fast (invariant 5), never silently report \"absent\". `ctx` names the source (path/key) for the message.\n * `expected` is the segment the row was read under; a row that names another is refused.\n */\nexport function parseRegistryEnvelope(\n text: string,\n ctx: string,\n expected?: SegmentRef,\n): 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 const schemaVersion = assertRegistrySchemaVersion(env.schemaVersion, ctx);\n const extra = Object.keys(env).filter((k) => !ENVELOPE_FIELDS.includes(k));\n if (extra.length > 0) {\n throw new IntegrityError(\n `registry row has fields its envelope does not declare (${shown(extra.join(', '))}): ${ctx}`,\n );\n }\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, schemaVersion);\n if (typeof r.token !== 'string') {\n throw new IntegrityError(`registry row is missing its token: ${ctx}`);\n }\n tokenParts(r.token, schemaVersion, ctx);\n // A row is the row of the name it is stored under. One copied or restored under another name would read as that\n // segment while naming this one, and every sweep that acts on the name it carries (an erasure, a report, a retention\n // pass) would act on the wrong segment, or on this one twice.\n if (\n expected !== undefined &&\n (r.segment !== expected.segment ||\n (r.namespace ?? undefined) !== (expected.namespace ?? undefined))\n ) {\n throw new IntegrityError(\n `registry row names another segment than the one it is stored for: ${ctx}`,\n );\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 status: rec.status ?? 'active',\n retention: rec.retention,\n residency: rec.residency,\n summary: rec.summary,\n keptGens: rec.keptGens,\n // A new row has no holder: a lease is written only against a row that already exists.\n leases: undefined,\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 \u2014 reject\n * it rather than silently report \"absent\". A row of an older `schemaVersion` may carry only that schema's\n * fields. `token` is checked by the caller.\n */\nexport function assertStoredRecordShape(\n r: Record<string, unknown>,\n ctx: string,\n schemaVersion: number = REGISTRY_SCHEMA_VERSION,\n): void {\n if (\n typeof r.segment !== 'string' ||\n (r.namespace !== undefined && typeof r.namespace !== 'string') ||\n (r.currentGen !== null && typeof r.currentGen !== '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 (r.currentGen !== null && (!Number.isSafeInteger(r.currentGen) || r.currentGen < 0)) {\n throw new IntegrityError(\n `registry record has an invalid currentGen (${shown(r.currentGen)}): ${ctx}`,\n );\n }\n if (!STATUSES.includes(r.status)) {\n throw new IntegrityError(`registry record has an unknown status (${shown(r.status)}): ${ctx}`);\n }\n const declared = fieldsOf(schemaVersion);\n const extra = Object.keys(r).filter((k) => !declared.includes(k));\n if (extra.length > 0) {\n throw new IntegrityError(\n `registry record has fields a schema-${schemaVersion} row does not declare (${shown(extra.join(', '))}): ${ctx}`,\n );\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 // The governance blobs' SHAPE is checked on read-back too, because one of them carries semantics:\n // `retention.expiresAt` is read with an `in` test, which throws an untyped `TypeError` on a stored\n // `null`/string/number. That is reachable \u2014 the write boundary only checks\n // JSON-serializability and size, so `\"retention\": null` round-trips through every driver from a hand-edit,\n // another writer, or a restore \u2014 and it would abort a whole fleet retention sweep rather than becoming one\n // ledger entry. Reject it here, typed, at the trust boundary (invariant 5).\n for (const field of ['retention', 'residency'] as const) {\n const meta = r[field];\n if (meta !== undefined && (meta === null || typeof meta !== 'object' || Array.isArray(meta))) {\n throw new IntegrityError(`registry record has a non-object ${field}: ${ctx}`);\n }\n }\n // Shape only. Whether the summary agrees with the row's keys and names its `currentGen` is not checked here: a\n // stored row that disagrees is a summary its reader must not use, not a row to refuse, and refusing it would let\n // one row stop every listing that reaches it.\n validateSummary(r.summary, true, ctx);\n validateKeptGens(r.keptGens, true, ctx);\n validateLeases(r.leases, true, ctx);\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 *\n * `summary` describes the current generation, so it follows the pointer and the keys: a patch that moves\n * `currentGen`, or changes `wrappedDeks` so the summary's shape no longer agrees, without mentioning `summary` drops\n * the old one; and a summary the patch gives must name the resulting `currentGen` and agree with the resulting keys\n * (`ValidationError`, before anything is written).\n */\nexport function applyRegistryPatch(\n prev: RegistryRecord,\n patch: RegistryPatch,\n now: number,\n token: Token,\n): RegistryRecord {\n // `'currentGen' in patch`, NOT `patch.currentGen ?? prev.currentGen`. `null` is a legal, meaningful value\n // here (no Storage generation yet), and `??` treats it as absent \u2014 so the nullish form would silently ignore a\n // patch that clears the pointer and leave the old generation in place. The same reason `wrappedDeks` and\n // `keyId` below use presence: any field whose null is a *value* cannot be merged with `??`.\n const currentGen = 'currentGen' in patch ? (patch.currentGen ?? null) : prev.currentGen;\n const wrappedDeks = 'wrappedDeks' in patch ? patch.wrappedDeks : prev.wrappedDeks;\n let summary: RegistrySummary | undefined;\n if ('summary' in patch) {\n validateSummaryNames(patch.summary, currentGen);\n validateSummaryKeys(patch.summary, wrappedDeks);\n summary = patch.summary;\n } else {\n // Kept only while it still describes the row: the same generation, and the same encryption.\n const kept = currentGen === prev.currentGen ? prev.summary : undefined;\n summary = kept !== undefined && summaryAgreesWithKeys(kept, wrappedDeks) ? kept : undefined;\n }\n // The list names generations below the pointer, so it follows the pointer as the summary does: kept while the\n // pointer stays, dropped when it moves without the patch naming the list, and checked against the pointer it gets.\n let keptGens: readonly number[] | undefined;\n if ('keptGens' in patch) {\n validateKeptGensBelow(patch.keptGens, currentGen);\n keptGens = patch.keptGens;\n } else {\n keptGens = currentGen === prev.currentGen ? prev.keptGens : undefined;\n }\n // Leases name generations a holder pinned, and the pointer moving does not end them: kept unless the patch names the list.\n let leases: readonly LeaseEntry[] | undefined;\n if ('leases' in patch) {\n leases = patch.leases;\n validateLeasesPointer(leases, currentGen);\n // A writer writes at most the cap, except that a list may always shrink: a release over a row that holds more\n // (written by another build) writes that list less one, and so can never be stuck behind the cap.\n const most = Math.max(MAX_LEASES_PER_SEGMENT, prev.leases?.length ?? 0);\n if (leases !== undefined && leases.length > most) {\n throw new ValidationError(`leases: has ${leases.length} entries, cap ${most}`);\n }\n } else {\n leases = prev.leases;\n }\n return {\n namespace: prev.namespace,\n segment: prev.segment,\n currentGen,\n wrappedDeks,\n keyId: 'keyId' in patch ? patch.keyId : prev.keyId,\n status: patch.status ?? prev.status,\n retention: 'retention' in patch ? patch.retention : prev.retention,\n residency: 'residency' in patch ? patch.residency : prev.residency,\n summary,\n keptGens,\n leases,\n createdAt: prev.createdAt,\n updatedAt: now,\n token,\n };\n}\n", "/**\n * The default entropy a shipped registry draws its tokens' random parts from: the platform's Web Crypto.\n *\n * Kept apart from the record helpers, which are pure, because this reads an ambient global. It is checked when a\n * row is written, not when a registry is built, so a process that only reads runs on a runtime without it.\n */\nimport { UnsupportedError } from '@/core/errors';\nimport type { Entropy } from '@/core/determinism';\n\ninterface WebCrypto {\n getRandomValues(array: Uint8Array): Uint8Array;\n}\n\n/** The platform's Web Crypto, or `undefined` when this runtime has none. */\nfunction webCrypto(): WebCrypto | undefined {\n const c = (globalThis as { crypto?: { getRandomValues?: unknown } }).crypto;\n return c !== undefined && typeof c.getRandomValues === 'function' ? (c as WebCrypto) : undefined;\n}\n\n/** Draws from the platform's Web Crypto; `UnsupportedError` on a runtime without it. */\nexport const webCryptoEntropy: Entropy = (length) => {\n const c = webCrypto();\n if (c === undefined) {\n throw new UnsupportedError(\n 'this runtime has no Web Crypto (crypto.getRandomValues), which a registry needs for the token of every ' +\n 'row it writes: run on a runtime that has it',\n );\n }\n return c.getRandomValues(new Uint8Array(length));\n};\n\n/** Whether `entropy` can draw here: an injected source always, the default only where Web Crypto exists. */\nexport function entropyIsAvailable(entropy: Entropy): boolean {\n return entropy !== webCryptoEntropy || webCrypto() !== undefined;\n}\n"],
5
+ "mappings": ";AAqBA,IAAM,cAA6B,uBAAO,IAAI,oBAAoB;AAClE,IAAM,kBAAiC,uBAAO,IAAI,8BAA8B;AAOhF,IAAM,QAAQ,oBAAI,QAA4D;AAGvE,IAAM,oBAAN,cAAgC,MAAM;AAAA;AAAA,EAE3C,CAAU,WAAW,IAAI;AAAA,EACzB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AAGb,SAAK,OAAO,MAAM,IAAI,UAAU,KAAK,WAAW;AAAA,EAClD;AACF;AAGO,IAAM,kBAAN,cAA8B,kBAAkB;AAAC;AAGjD,IAAM,qBAAN,cAAiC,kBAAkB;AAAC;AAGpD,IAAM,iBAAN,cAA6B,kBAAkB;AAAC;AAOhD,IAAM,gBAAN,cAA4B,kBAAkB;AAAC;AAQ/C,IAAM,oBAAN,cAAgC,kBAAkB;AAAA;AAAA,EAE9C;AAAA;AAAA,EAEA;AAAA,EACT,YAAY,SAAiB,OAAe,QAAgC;AAC1E,UAAM,OAAO;AACb,SAAK,QAAQ;AACb,SAAK,SAAS;AAAA,EAChB;AACF;AAMO,IAAM,kBAAN,cAA8B,kBAAkB;AAAC;AASjD,IAAM,oBAAN,cAAgC,kBAAkB;AAAA,EAC9C,OAAO;AAAA;AAAA,EAEP;AAAA;AAAA,EAEA;AAAA,EACT,YAAY,SAAiB,SAAiB,QAA4B;AACxE,UAAM,OAAO;AACb,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AACF;AAUO,IAAM,mBAAN,cAA+B,kBAAkB;AAAC;AAMlD,IAAM,kBAAN,cAA8B,kBAAkB;AAAC;AAUjD,IAAM,sBAAN,cAAkC,kBAAkB;AAAC;AAUrD,IAAM,sBAAN,cAAkC,kBAAkB;AAAC;AAerD,IAAM,iBAAN,cAA6B,kBAAkB;AAAA;AAAA,EAEpD,CAAU,eAAe,IAAI;AAAA,EAC7B,YAAY,SAAiB,SAA+B;AAC1D,UAAM,OAAO;AACb,QAAI,WAAW,WAAW,QAAS,MAAK,QAAQ,QAAQ;AAAA,EAC1D;AACF;AAGA,MAAM,IAAI,mBAAmB,mBAAmB;AAChD,MAAM,IAAI,iBAAiB,iBAAiB;AAC5C,MAAM,IAAI,oBAAoB,oBAAoB;AAClD,MAAM,IAAI,gBAAgB,gBAAgB;AAC1C,MAAM,IAAI,eAAe,eAAe;AACxC,MAAM,IAAI,mBAAmB,mBAAmB;AAChD,MAAM,IAAI,iBAAiB,iBAAiB;AAC5C,MAAM,IAAI,mBAAmB,mBAAmB;AAChD,MAAM,IAAI,kBAAkB,kBAAkB;AAC9C,MAAM,IAAI,iBAAiB,iBAAiB;AAC5C,MAAM,IAAI,qBAAqB,qBAAqB;AACpD,MAAM,IAAI,qBAAqB,qBAAqB;AACpD,MAAM,IAAI,gBAAgB,gBAAgB;AAO1C,SAAS,SAAS,KAAc,OAAwB;AACtD,SACE,OAAO,QAAQ,YAAY,QAAQ,QAAS,IAAgC,KAAK,MAAM;AAE3F;AAGO,SAAS,oBAAoB,KAAwC;AAC1E,SAAO,SAAS,KAAK,WAAW;AAClC;AAGO,SAAS,qBAAqB,KAAyC;AAC5E,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,iBAAiB,KAAqC;AACpE,SAAO,SAAS,KAAK,eAAe;AACtC;AAGO,SAAS,oBAAoB,KAAwC;AAC1E,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,oBAAoB,KAAwC;AAC1E,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,kBAAkB,KAAsC;AACtE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,gBAAgB,KAAoC;AAClE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,iBAAiB,KAAqC;AACpE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,kBAAkB,KAAsC;AACtE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,mBAAmB,KAAuC;AACxE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,kBAAkB,KAAsC;AACtE,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,sBAAsB,KAA0C;AAC9E,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;AAGO,SAAS,sBAAsB,KAA0C;AAC9E,SAAO,oBAAoB,GAAG,KAAK,IAAI,SAAS;AAClD;;;ACjNA,IAAM,WAAW;AAEjB,IAAM,YAAY;AAElB,IAAM,OAAO,IAAI,YAAY;AAS7B,SAAS,WAAW,IAAoB;AACtC,MAAI,MAAM;AACV,aAAW,QAAQ,KAAK,OAAO,EAAE,GAAG;AAClC,WAAO,IAAI,KAAK,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EAC7D;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAc,MAAsB;AACtD,MAAI,MAAM;AAGV,aAAW,MAAM,MAAM;AACrB,WAAO,OAAO,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,WAAW,EAAE;AAAA,EACzD;AAMA,SAAO,IAAI,WAAW,GAAG,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK;AACtD;AAEA,SAAS,cAAc,SAAyB;AAC9C,QAAM,QAAkB,CAAC;AACzB,WAAS,IAAI,GAAG,IAAI,QAAQ,UAAS;AACnC,QAAI,QAAQ,CAAC,MAAM,OAAO,IAAI,IAAI,QAAQ,SAAS,GAAG;AACpD,YAAM,MAAM,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC;AACtC,UAAI,CAAC,mBAAmB,KAAK,GAAG,EAAG,QAAO;AAC1C,YAAM,KAAK,SAAS,KAAK,EAAE,CAAC;AAC5B,WAAK;AAAA,IACP,OAAO;AACL,iBAAW,KAAK,IAAI,YAAY,EAAE,OAAO,QAAQ,CAAC,CAAC,EAAG,OAAM,KAAK,CAAC;AAClE,WAAK;AAAA,IACP;AAAA,EACF;AAcA,SAAO,IAAI,YAAY,SAAS,EAAE,OAAO,OAAO,WAAW,KAAK,CAAC,EAAE,OAAO,IAAI,WAAW,KAAK,CAAC;AACjG;AASO,SAAS,iBAAiB,MAAsB;AACrD,SAAO,mBAAmB,WAAW,MAAM,QAAQ,CAAC;AACtD;AAiBA,SAAS,mBAAmB,SAAyB;AACnD,SAAO,YAAY,OAAO,YAAY,OAAO,QAAQ,WAAW,KAAK,KAAK,IAAI;AAChF;AAGO,SAAS,kBAAkB,SAAyB;AACzD,SAAO,cAAc,OAAO;AAC9B;AAmBO,SAAS,kBAAkB,MAAsB;AACtD,MAAI,UAAU,WAAW,MAAM,SAAS;AAIxC,QAAM,SAAS,mBAAmB,OAAO;AACzC,MAAI,WAAW,QAAS,QAAO;AAG/B,QAAM,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK;AACtC,MAAI,2CAA2C,KAAK,IAAI,GAAG;AACzD,cAAU,WAAW,QAAQ,CAAC,CAAW,IAAI,QAAQ,MAAM,CAAC;AAAA,EAC9D;AAIA,MAAI,QAAQ,SAAS,GAAG,EAAG,WAAU,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC;AAE5D,SAAO;AACT;AAGO,SAAS,mBAAmB,SAAyB;AAC1D,SAAO,cAAc,OAAO;AAC9B;;;ACvKO,IAAM,oBAAoB;AAM1B,SAAS,cAAc,OAAkC;AAC9D,SAAO,kBAAkB,KAAK,KAAK,IAAI,CAAC;AAC1C;AAWO,SAAS,gBACd,GACA,GACS;AACT,QAAM,KAAK,cAAc,EAAE,KAAK;AAChC,QAAM,KAAK,cAAc,EAAE,KAAK;AAChC,MAAI,OAAO,UAAa,OAAO,OAAW,QAAO,OAAO;AACxD,SAAO,EAAE,cAAc,EAAE;AAC3B;;;ACbO,IAAM,eAAe,KAAK;AAM1B,IAAM,gBAAgB;AAGtB,IAAM,yBAAyB;AAG/B,IAAM,oBAAoB;AAO1B,IAAM,qBAAqB,yBAAyB;AAG3D,IAAM,qBAAqB;AAE3B,IAAM,qBAAqB;AAE3B,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAQjB,SAAS,OAAO,OAAmB,KAAsB;AAC9D,SAAO,MAAM,MAAM,QAAQ,iBAAiB,MAAM,SAAS,MAAM,eAAe;AAClF;AAGO,SAAS,gBAAgB,QAA+B,KAAkC;AAC/F,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,KAAK,QAAQ,UAAU,CAAC,EAAG,KAAI,OAAO,GAAG,GAAG,EAAG,KAAI,IAAI,EAAE,UAAU;AAC9E,SAAO;AACT;AAGO,SAAS,WAAW,QAA+B,KAAoC;AAC5F,UAAQ,QAAQ,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC;AAC5D;AAmBO,IAAM,qBAAqB,IAAI,yBAAyB;AAG/D,IAAM,cAAmC,oBAAI,IAAI,CAAC,SAAS,aAAa,QAAQ,CAAC;AAGjF,SAAS,OAAO,OAAwB;AACtC,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK;AAC5E,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,MAAM,EAAE,KAAK,GAAG,CAAC;AAChE,QAAM,IAAI;AACV,QAAM,OAAO,OAAO,KAAK,CAAC,EACvB,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,MAAS,EAChC,KAAK;AACR,SAAO,IAAI,KAAK,IAAI,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC9E;AAWO,SAAS,iBACd,MACA,KACA,aAAgD,CAAC,GACxC;AACT,MAAI,CAAC,gBAAgB,MAAM,GAAG,EAAG,QAAO;AACxC,QAAM,OAAO,oBAAI,IAAY,CAAC,GAAG,aAAa,GAAG,UAAU,CAAC;AAC5D,QAAM,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,GAAG,CAAC,CAAC;AAChE,aAAW,KAAK,MAAM;AACpB,QAAI,KAAK,IAAI,CAAC,EAAG;AACjB,QACE,OAAQ,KAA4C,CAAC,CAAC,MACtD,OAAQ,IAA2C,CAAC,CAAC,GACrD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAuBO,SAAS,WAAW,MAA6B;AACtD,MAAI,OAAO;AACX,SAAO;AAAA,IACL,MAAM,OAAO,MAAM,KAAK,QAAQ,YAAY;AAC1C,UAAI,SAAS,QAAQ,SAAS,UAAa,QAAQ,KAAM,QAAO;AAChE,UAAI,QAAQ,sBAAsB,CAAC,iBAAiB,MAAM,KAAK,UAAU,EAAG,QAAO;AACnF,YAAM,QAAQ,KAAK,IAAI,mBAAmB,KAAK,KAAK,IAAI,MAAM,CAAC,GAAG,eAAe;AACjF,cAAQ;AACR,YAAM,QAAQ,KAAK,OAAO;AAC1B,UAAI,UAAU,QAAW;AACvB,cAAM,MAAM,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,CAAC;AAAA,MAC1E;AACA,aAAO,EAAE,KAAK,MAAM,OAAO,EAAE;AAAA,IAC/B;AAAA,EACF;AACF;AAGA,SAAS,OAAO,SAAmE;AACjF,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,CAAC,GAAG,OAAO,EAAE;AAAA,IAAK,CAAC,GAAG,MAC3B,EAAE,eAAe,EAAE,aACf,EAAE,aAAa,EAAE,aACjB,EAAE,SAAS,EAAE,SACX,KACA,EAAE,SAAS,EAAE,SACX,IACA;AAAA,EACV;AACF;AA6BA,IAAM,OAAO,CAAC,MAAiB,UAC7B,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,CAAC;AAE9D,IAAM,SAAS,CAAC,KAA4B,UACzC,KAAK,UAAU,CAAC,GAAG;AAAA,EAClB,CAAC,MAAM,EAAE,WAAW,KAAK,UAAU,EAAE,eAAe,KAAK,cAAc,EAAE,UAAU,KAAK;AAC1F;AAaF,eAAsB,UACpB,KACA,MACA,MAC+B;AAC/B,MAAI,MAA6B,KAAK;AACtC,MAAI,OAAO;AACX,MAAI,UAAU;AACd,MAAI;AACJ,WAAS,UAAU,GAAG,UAAU,oBAAoB,WAAW;AAC7D,QAAI,QAAQ,KAAM,OAAM,MAAM,KAAK,SAAS,IAAI,GAAG;AACnD,QAAI,QAAQ,QAAQ,IAAI,WAAW,eAAe,IAAI,eAAe,MAAM;AACzE,YAAM,IAAI,cAAc,YAAY,IAAI,OAAO,8BAA8B;AAAA,IAC/E;AACA,QAAI,KAAK,aAAa,IAAI,YAAY;AACpC,YAAM,IAAI;AAAA,QACR,YAAY,IAAI,OAAO,gBAAgB,KAAK,UAAU;AAAA,MACxD;AAAA,IACF;AACA,QAAI,KAAK,WAAW,IAAI,eAAe,KAAK,WAAY,QAAO;AAC/D,QAAI,OAAO,KAAK,IAAI,EAAG,QAAO,EAAE,OAAO,IAAI,OAAO,IAAI;AACtD,UAAM,OAAO,WAAW,KAAK,KAAK,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,MAAM;AACrF,QAAI,KAAK,UAAU,wBAAwB;AACzC,YAAM,IAAI;AAAA,QACR,YAAY,IAAI,OAAO,iBAAiB,KAAK,MAAM;AAAA,MACrD;AAAA,IACF;AACA,UAAM,SAAS,OAAO;AAAA,MACpB,GAAG;AAAA,MACH,EAAE,QAAQ,KAAK,QAAQ,YAAY,KAAK,YAAY,OAAO,KAAK,MAAM;AAAA,IACxE,CAAC;AACD,UAAM,UAA0B;AAChC,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAAS;AAAA,QACpC;AAAA,QACA,QAAQ;AAAA,QACR,EAAE,OAAO;AAAA,QACT,OAAO,EAAE,MAAM,QAAQ,IAAI;AAAA,MAC7B;AACA,aAAO,EAAE,OAAO,KAAK,QAAQ;AAAA,IAC/B,SAAS,KAAK;AACZ,UAAI,qBAAqB,GAAG,GAAG;AAC7B,cAAM;AACN,eAAO;AACP,cAAM,KAAK,MAAM,KAAK,IAAI,mBAAmB,KAAK,SAAS,eAAe,CAAC;AAC3E;AAAA,MACF;AACA,UAAI,CAAC,iBAAiB,GAAG,EAAG,OAAM;AAElC,YAAM,MAAM,MAAM,KAAK,SAAS,IAAI,GAAG;AACvC,UAAI,OAAO,KAAK,IAAI,EAAG,QAAO,EAAE,OAAQ,IAAuB,OAAO,KAAK,QAAQ;AACnF,UAAI,QAAQ,QAAQ,IAAI,UAAU,QAAQ,OAAO;AAC/C,YAAI,WAAW,mBAAoB,OAAM;AACzC,cAAM,KAAK,MAAM,qBAAqB,KAAK,OAAO;AAClD,mBAAW;AACX,qBAAa;AAAA,MACf;AACA,YAAM;AACN,aAAO;AACP,UAAI,QAAQ;AACV,cAAM,IAAI,cAAc,YAAY,IAAI,OAAO,8BAA8B;AAAA,IACjF;AAAA,EACF;AACA,MAAI,eAAe,OAAW,OAAM;AACpC,QAAM,IAAI,mBAAmB,gDAAgD,IAAI,OAAO,GAAG;AAC7F;AAOA,eAAsB,aACpB,KACA,MACA,QACe;AACf,MAAI,UAAU;AACd,MAAI;AACJ,MAAI;AACJ,WAAS,UAAU,GAAG,UAAU,oBAAoB,WAAW;AAC7D,QAAI,QAAQ,OAAW,OAAM,MAAM,KAAK,SAAS,IAAI,GAAG;AACxD,QAAI,QAAQ,QAAQ,IAAI,WAAW,YAAa;AAChD,QAAI,EAAE,IAAI,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,EAAG;AAC1D,UAAM,UAA0B;AAChC,UAAM,OAAO,WAAW,SAAS,KAAK,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACpF,QAAI;AACF,YAAM,KAAK,SAAS,eAAe,KAAK,QAAQ,OAAO,EAAE,QAAQ,OAAO,IAAI,EAAE,CAAC;AAC/E;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,qBAAqB,GAAG,GAAG;AAC7B,cAAM;AACN,cAAM,KAAK,MAAM,KAAK,IAAI,mBAAmB,KAAK,SAAS,eAAe,CAAC;AAC3E;AAAA,MACF;AACA,UAAI,CAAC,iBAAiB,GAAG,EAAG,OAAM;AAClC,YAAM,MAAM,MAAM,KAAK,SAAS,IAAI,GAAG;AACvC,UAAI,QAAQ,QAAQ,EAAE,IAAI,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,EAAG;AAC1E,UAAI,IAAI,UAAU,QAAQ,OAAO;AAC/B,YAAI,WAAW,mBAAoB,OAAM;AACzC,cAAM,KAAK,MAAM,qBAAqB,KAAK,OAAO;AAClD,mBAAW;AACX,qBAAa;AAAA,MACf;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,eAAe,OAAW,OAAM;AACpC,QAAM,IAAI,mBAAmB,mDAAmD,IAAI,OAAO,GAAG;AAChG;;;ACnUA,IAAM,gBAAgB;AASf,IAAM,kBAAkB;AAS/B,IAAM,iBAAiB;AAGhB,SAAS,mBAAmB,OAAwB;AACzD,SAAO,CAAC,eAAe,KAAK,KAAK;AACnC;AAQO,SAAS,kBAAkB,OAAuB;AACvD,SAAO,KAAK,IAAI,iBAAiB,KAAK,EAAE,QAAQ,kBAAkB,KAAK,EAAE,MAAM;AACjF;AAEA,SAAS,aAAa,OAAe,OAAqB;AACxD,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,IAAI,gBAAgB,GAAG,KAAK,0BAA0B,OAAO,KAAK,EAAE;AAAA,EAC5E;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,gBAAgB,GAAG,KAAK,oBAAoB;AAAA,EACxD;AAIA,MAAI,MAAM,SAAS,iBAAiB;AAClC,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,iBAAiB,MAAM,MAAM,sBAAsB,eAAe;AAAA,IAC5E;AAAA,EACF;AAKA,MAAI,eAAe,KAAK,KAAK,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR,GAAG,KAAK;AAAA,IAEV;AAAA,EACF;AAKA,QAAM,UAAU,kBAAkB,KAAK;AACvC,MAAI,UAAU,iBAAiB;AAC7B,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,iBAAiB,OAAO,+CAA+C,eAAe,yBAC/E,MAAM,MAAM;AAAA,IAE7B;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,KAAuB;AACxD,eAAa,IAAI,SAAS,SAAS;AACnC,MAAI,IAAI,cAAc,OAAW,cAAa,IAAI,WAAW,WAAW;AAC1E;AAeO,IAAM,4BAA4B;AAGlC,SAAS,oBAAoB,WAAwC;AAC1E,SAAO,cAAc,UAAa,UAAU,WAAW,yBAAyB;AAClF;AAQO,SAAS,sBAAsB,WAAyB;AAC7D,eAAa,WAAW,WAAW;AACnC,MAAI,oBAAoB,SAAS,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,cAAc,SAAS,uCAAuC,yBAAyB;AAAA,IAGzF;AAAA,EACF;AACF;AAGO,SAAS,gBAAgB,KAAuB;AACrD,eAAa,IAAI,SAAS,SAAS;AACnC,MAAI,IAAI,cAAc,OAAW,uBAAsB,IAAI,SAAS;AACtE;AAMO,SAAS,sBAAsB,MAA+B;AACnE,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,EAAE,KAAK,CAAC,KAAM,KAAK,IAAI,CAAC;AAC1B,YAAM,IAAI,gBAAgB,uCAAuC;AAAA,EACrE;AACF;AAGO,SAAS,iBAAiB,KAAqB;AACpD,qBAAmB,GAAG;AACtB,MAAI,CAAC,OAAO,UAAU,IAAI,QAAQ,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,eAAe;AACvF,UAAM,IAAI,gBAAgB,sCAAsC,aAAa,GAAG;AAAA,EAClF;AACF;;;ACrJA,eAAsB,mBACpB,OACA,OACA,IACc;AACd,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,IAAI,gBAAgB,qDAAqD,KAAK,EAAE;AAAA,EACxF;AACA,QAAM,UAAU,IAAI,MAAS,MAAM,MAAM;AACzC,MAAI,OAAO;AACX,MAAI,SAAS;AACb,MAAI;AACJ,QAAM,SAAS,YAA2B;AACxC,WAAO,CAAC,QAAQ;AACd,YAAM,IAAI;AACV,UAAI,KAAK,MAAM,OAAQ;AACvB,UAAI;AACF,gBAAQ,CAAC,IAAI,MAAM,GAAG,MAAM,CAAC,GAAI,CAAC;AAAA,MACpC,SAAS,KAAK;AACZ,YAAI,CAAC,QAAQ;AACX,mBAAS;AACT,uBAAa;AAAA,QACf;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,MAAM,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC;AACpF,QAAM,QAAQ,IAAI,OAAO;AACzB,MAAI,OAAQ,OAAM;AAClB,SAAO;AACT;;;AC4eO,SAAS,uBAAuB,UAA2B,MAAoB;AACpF,MAAI,SAAS,aAAa,EAAE,aAAa,OAAO;AAC9C,UAAM,IAAI;AAAA,MACR,GAAG,IAAI;AAAA,IAET;AAAA,EACF;AACF;AAaA,IAAM,wBAAuC,uBAAO,IAAI,8BAA8B;AA4C/E,IAAM,kBAAgD;AA2BtD,SAAS,eACd,QACoB;AACpB,MAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,UAAM,IAAI,gBAAgB,8CAA8C;AAAA,EAC1E;AACA,QAAM,EAAE,SAAS,SAAS,IAAI;AAC9B,MACE,YAAY,QACZ,OAAO,YAAY,YACnB,OAAO,QAAQ,iBAAiB,YAChC;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MACE,aAAa,QACb,OAAO,aAAa,YACpB,OAAO,SAAS,mBAAmB,YACnC;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,WAAO,eAAe,QAAQ,uBAAuB;AAAA,MACnD,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,QAAQ;AAEN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,iBAAiB,OAAyC;AACxE,SACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,qBAAqB,MAAM;AAElE;;;AC9pBO,IAAM,oBAAoB;AAW1B,SAAS,iBAAiB,WAAuC;AACtE,SAAO,cAAc,SAAY,oBAAoB,iBAAiB,SAAS;AACjF;AAGO,SAAS,kBAAkB,WAAuC;AACvE,SAAO,cAAc,SAAY,oBAAoB,kBAAkB,SAAS;AAClF;;;ACfO,IAAM,uBAAuB;AAG7B,IAAM,8BAA8B;AAOpC,SAAS,eAAe,QAA8D;AAC3F,QAAM,OAAO,QAAQ;AACrB,MAAI,WAAW,QAAQ,SAAS,UAAa,OAAO,eAAe,KAAM,QAAO;AAChF,aAAW,KAAK,KAAM,KAAI,KAAK,OAAO,WAAY,QAAO;AACzD,SAAO;AACT;AAkBO,SAAS,SACd,MACA,YACA,MACW;AACX,QAAM,OAAkB,EAAE,MAAM,QAAW,OAAO,CAAC,EAAE;AACrD,MAAI,SAAS,UAAa,OAAO,qBAAsB,QAAO;AAC9D,MAAI,eAAe,EAAG,QAAO,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE;AACnD,QAAM,WAAW,MAAM,cAAc;AACrC,QAAM,QAAQ,eAAe,IAAI;AACjC,MAAI,aAAa,QAAQ,UAAU,OAAW,QAAO;AACrD,QAAM,MAAM,CAAC,GAAG,OAAO,QAAQ;AAC/B,QAAM,MAAM,KAAK,IAAI,GAAG,IAAI,SAAS,IAAI;AACzC,SAAO,EAAE,MAAM,IAAI,MAAM,GAAG,GAAG,OAAO,IAAI,MAAM,GAAG,GAAG,EAAE;AAC1D;;;ACpDO,IAAM,qBAAqB;AAE3B,IAAM,yBAAyB;AAEtC,IAAM,aAAa,CAAC,MAAsB,IAAI,YAAY,EAAE,OAAO,CAAC,EAAE;AAY/D,SAAS,sBAAsB,OAAgB,MAA0C;AAC9F,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,SAAK,wCAAwC,UAAU,OAAO,SAAS,OAAO,KAAK,GAAG;AAAA,EACxF;AACA,QAAM,QAAiB,OAAO,eAAe,KAAK;AAClD,MACE,OAAO,UAAU,SAAS,KAAK,KAAK,MAAM,qBACzC,UAAU,OAAO,aAAa,UAAU,MACzC;AACA,SAAK,yFAAyF;AAAA,EAChG;AAGA,QAAM,UAA4C,CAAC;AACnD,QAAM,OAAO,QAAQ,QAAQ,KAAe;AAC5C,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,SAAU,MAAK,4CAA4C;AAC9E,UAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;AAC7D,QAAI,eAAe,UAAa,EAAE,WAAW,eAAe,WAAW,eAAe,MAAM;AAC1F,WAAK,gBAAgB,KAAK,UAAU,GAAG,CAAC,sCAAsC;AAAA,IAChF;AACA,QAAI,IAAI,WAAW,EAAG,MAAK,iCAAiC;AAC5D,QAAI,QAAQ,YAAa,MAAK,0CAA0C;AACxE,QAAI,CAAC,mBAAmB,GAAG,EAAG,MAAK,0CAA0C;AAE7E,QAAI,IAAI,SAAS,IAAI,wBAAwB;AAC3C,YAAM,WAAW,WAAW,GAAG;AAC/B,UAAI,WAAW,wBAAwB;AACrC,aAAK,mBAAmB,QAAQ,eAAe,sBAAsB,OAAO;AAAA,MAC9E;AAAA,IACF;AACA,UAAM,IAAa,WAAW;AAC9B,QAAI,OAAO,MAAM,UAAU;AACzB,UAAI,CAAC,mBAAmB,CAAC,GAAG;AAC1B,aAAK,qBAAqB,KAAK,UAAU,GAAG,CAAC,6BAA6B;AAAA,MAC5E;AAAA,IACF,WAAW,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;AACvD,WAAK,qBAAqB,KAAK,UAAU,GAAG,CAAC,sCAAsC;AAAA,IACrF;AACA,YAAQ,KAAK,CAAC,KAAK,CAAC,CAAC;AAAA,EACvB;AAEA,UAAQ,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,CAAE;AAC3C,QAAM,OAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC/F,QAAM,QAAQ,WAAW,IAAI;AAC7B,MAAI,QAAQ,oBAAoB;AAC9B,SAAK,eAAe,KAAK,iCAAiC,kBAAkB,OAAO;AAAA,EACrF;AACA,SAAO;AACT;AAOO,SAAS,cACd,OACA,MACwB;AACxB,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,sBAAsB,OAAO,IAAI;AAC9C,SAAO,SAAS,OAAO,SAAY,IAAI,YAAY,EAAE,OAAO,IAAI;AAClE;AAOO,SAAS,eACd,OACA,MACgC;AAChC,QAAM,QAAQ,cAAc,OAAO,IAAI;AACvC,SAAO,UAAU,SAAY,SAAY,kBAAkB,OAAO,IAAI;AACxE;AAQO,SAAS,kBACd,OACA,MACoB;AACpB,MAAI,MAAM,SAAS,oBAAoB;AACrC,SAAK,eAAe,MAAM,MAAM,eAAe,kBAAkB,OAAO;AAAA,EAC1E;AACA,MAAI;AACJ,MAAI;AACF,WAAO,IAAI,YAAY,SAAS,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC,EAAE,OAAO,KAAK;AAAA,EAChF,QAAQ;AACN,SAAK,6BAA6B;AAAA,EACpC;AACA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,SAAK,sBAAsB;AAAA,EAC7B;AACA,QAAM,OAAO,sBAAsB,QAAQ,IAAI;AAC/C,MAAI,SAAS,KAAM,MAAK,+DAA+D;AACvF,MAAI,SAAS,KAAM,MAAK,mCAAmC;AAC3D,SAAO,OAAO,OAAO,MAA4B;AACnD;;;ACzGA,IAAM,WAA8B,CAAC,UAAU,WAAW;AAK1D,IAAM,cAAc;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,IAAM,kBAAkB,CAAC,YAAY,QAAQ;AACtC,IAAM,gBAAgB,CAAC,GAAG,aAAa,GAAG,eAAe;AAEhE,SAAS,SAAS,eAA0C;AAC1D,MAAI,iBAAiB,EAAG,QAAO;AAC/B,QAAM,OAA0B;AAChC,SAAO,kBAAkB,IAAI,OAAO,KAAK,OAAO,CAAC,MAAM,MAAM,SAAS;AACxE;AAEA,IAAM,kBAAqC,CAAC,iBAAiB,WAAW,QAAQ;AAEhF,IAAM,uBAAuB,KAAK;AAElC,IAAM,mBAAmB;AACzB,IAAM,wBAAwB,IAAI;AAElC,IAAM,0BAA0B,KAAK;AAErC,IAAM,2BAA2B,KAAK,IAAI;AAE1C,IAAM,2BAA2B,2BAA2B;AAE5D,IAAM,SAAS;AAGf,SAAS,mBAAmB,KAA0B;AACpD,MAAI,QAAQ,KAAM;AAClB,MAAI,CAAC,OAAO,cAAc,GAAG,KAAK,MAAM,GAAG;AACzC,UAAM,IAAI;AAAA,MACR,2FAA2F,GAAG;AAAA,IAChG;AAAA,EACF;AACF;AAUA,SAAS,wBAAwB,OAA4B;AAC3D,MAAI,EAAE,gBAAgB,OAAQ;AAK9B,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,qBAAmB,MAAM,UAAU;AACrC;AAEA,SAAS,eAAe,QAAsB;AAC5C,MAAI,CAAC,SAAS,SAAS,MAAM,GAAG;AAC9B,UAAM,IAAI,gBAAgB,yBAAyB,SAAS,KAAK,GAAG,CAAC,SAAS,MAAM,EAAE;AAAA,EACxF;AACF;AAOA,SAAS,mBAAmB,MAAe,OAAqB;AAC9D,MAAI,SAAS,OAAW;AAMxB,MAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AACpE,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,gCAAgC,SAAS,OAAO,SAAS,OAAO,IAAI;AAAA,IAC9E;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,UAAU,IAAI;AAAA,EAC5B,QAAQ;AACN,UAAM,IAAI,gBAAgB,GAAG,KAAK,4BAA4B;AAAA,EAChE;AACA,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,gBAAgB,GAAG,KAAK,OAAO,KAAK,MAAM,kBAAkB,oBAAoB,GAAG;AAAA,EAC/F;AACF;AAQA,SAAS,oBAAoB,OAAgB,UAAyB;AACpE,MAAI,UAAU,OAAW;AACzB,QAAM,OAAO,CAAC,QAAuB;AACnC,UAAM,WAAW,IAAI,eAAe,GAAG,IAAI,IAAI,gBAAgB,GAAG;AAAA,EACpE;AACA,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,MAAK,8BAA8B;AAC9D,QAAM,OAAO;AACb,MAAI,KAAK,WAAW,EAAG,MAAK,4CAA4C;AACxE,MAAI,KAAK,SAAS;AAChB,SAAK,mBAAmB,KAAK,MAAM,iBAAiB,gBAAgB,EAAE;AACxE,aAAW,KAAK,MAAM;AACpB,QAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,MAAK,qCAAqC;AACnF,UAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAI,OAAO,UAAU,YAAY,MAAM,WAAW;AAChD,WAAK,2CAA2C;AAClD,QAAI,OAAO,YAAY,YAAY,QAAQ,WAAW;AACpD,WAAK,kDAAkD;AACzD,QAAK,QAAmB,SAAS;AAC/B,WAAK,wBAAyB,QAAmB,MAAM,UAAU,qBAAqB,GAAG;AAAA,EAC7F;AACF;AAGA,IAAM,kBAAkB;AAMxB,SAAS,qBAAqB,MAAuB;AACnD,QAAM,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI;AAC/D,MAAI,QAAQ,EAAG,QAAO;AACtB,QAAM,OAAO,gBAAgB,QAAQ,KAAK,KAAK,SAAS,MAAM,CAAC,CAAE;AACjE,SAAO,QAAQ,KAAK,OAAO,QAAY,KAAK,OAAO,OAAU;AAC/D;AAYA,SAAS,gBACP,OACA,UACA,KAC6B;AAC7B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,CAAC,QAAuB;AACnC,UAAM,QAAQ,QAAQ,SAAY,KAAK,KAAK,GAAG;AAC/C,UAAM,WACF,IAAI,eAAe,4BAA4B,GAAG,GAAG,KAAK,EAAE,IAC5D,IAAI,gBAAgB,YAAY,GAAG,GAAG,KAAK,EAAE;AAAA,EACnD;AACA,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACvE;AAAA,MACE,0BAA0B,UAAU,OAAO,SAAS,MAAM,QAAQ,KAAK,IAAI,aAAa,OAAO,KAAK;AAAA,IACtG;AAAA,EACF;AACA,QAAM,IAAI;AACV,QAAM,OAAO,OAAO,KAAK,CAAC;AAC1B,QAAM,WAAW,KAAK,SAAS,QAAQ;AACvC,QAAM,UAAU,WAAW,CAAC,cAAc,QAAQ,IAAI,CAAC,cAAc,eAAe,UAAU;AAC9F,QAAM,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,QAAQ,SAAS,CAAC,CAAC;AACrD,MAAI,MAAM,SAAS,GAAG;AACpB;AAAA,MACE,kBAAkB,WAAW,WAAW,OAAO,4BAA4B,MAAM,KAAK,IAAI,CAAC;AAAA,IAC7F;AAAA,EACF;AACA,QAAM,aAAa,EAAE;AACrB,MAAI,CAAC,OAAO,cAAc,UAAU,KAAM,aAAwB,GAAG;AACnE,SAAK,uDAAuD,OAAO,UAAU,CAAC,GAAG;AAAA,EACnF;AACA,MAAI,UAAU;AACZ,UAAM,SAAS,EAAE;AACjB,QAAI,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK,MAAM,KAAK,CAAC,qBAAqB,MAAM,GAAG;AACvF,WAAK,kDAAkD;AAAA,IACzD;AACA,UAAM,OAAO;AACb,UAAM,QAAS,KAAK,SAAS,IAAK,KAAK,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI;AAC1F,QAAI,QAAQ,4BAA4B,QAAQ,0BAA0B;AACxE;AAAA,QACE,aAAa,KAAK,cAAc,wBAAwB,KAAK,wBAAwB;AAAA,MAEvF;AAAA,IACF;AACA,WAAO,OAAO,OAAO,EAAE,YAAkC,QAAQ,KAAK,CAAC;AAAA,EACzE;AACA,QAAM,IAAI,EAAE;AACZ,MAAI,CAAC,OAAO,UAAU,CAAC,KAAM,IAAe,KAAM,IAAe,yBAAyB;AACxF,SAAK,sDAAsD,OAAO,CAAC,CAAC,GAAG;AAAA,EACzE;AACA,MAAI,EAAE,aAAa,QAAW;AAC5B,WAAO,OAAO,OAAO,EAAE,YAAkC,aAAa,EAAY,CAAC;AAAA,EACrF;AACA,QAAM,YAAY,sBAAsB,EAAE,UAAU,IAAI;AACxD,MAAI,cAAc,KAAM,MAAK,+DAA+D;AAE5F,MAAI,SAAU,QAAO;AAGrB,QAAM,WAAW,OAAO,OAAO,KAAK,MAAM,SAAS,CAAoC;AACvF,SAAO,OAAO,OAAO,EAAE,YAAkC,aAAa,GAAa,SAAS,CAAC;AAC/F;AAGA,SAAS,qBACP,SACA,YACM;AACN,MAAI,YAAY,UAAa,QAAQ,eAAe,YAAY;AAC9D,UAAM,IAAI;AAAA,MACR,gCAAgC,QAAQ,UAAU,2BAA2B,OAAO,UAAU,CAAC;AAAA,IACjG;AAAA,EACF;AACF;AAOA,SAAS,sBACP,SACA,aACS;AACT,SAAO,YAAY,aAAa,gBAAgB;AAClD;AAGA,SAAS,oBACP,SACA,aACM;AACN,MAAI,YAAY,UAAa,CAAC,sBAAsB,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI;AAAA,MACR,gBAAgB,SACZ,uEACA;AAAA,IACN;AAAA,EACF;AACF;AASA,SAAS,iBACP,OACA,UACA,KAC+B;AAC/B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,CAAC,QAAuB;AACnC,UAAM,QAAQ,QAAQ,SAAY,KAAK,KAAK,GAAG;AAC/C,UAAM,WACF,IAAI,eAAe,6BAA6B,GAAG,GAAG,KAAK,EAAE,IAC7D,IAAI,gBAAgB,aAAa,GAAG,EAAE;AAAA,EAC5C;AACA,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,MAAK,kBAAkB;AAClD,QAAM,OAAO;AACb,QAAM,MAAM,WAAW,8BAA8B;AACrD,MAAI,KAAK,SAAS,IAAK,MAAK,OAAO,KAAK,MAAM,iBAAiB,GAAG,EAAE;AACpE,MAAI,OAAO;AACX,aAAW,KAAK,MAAM;AACpB,QAAI,CAAC,OAAO,cAAc,CAAC,KAAM,IAAe,GAAG;AACjD,WAAK,mDAAmD,OAAO,CAAC,CAAC,GAAG;AAAA,IACtE;AACA,QAAK,KAAgB,KAAM,MAAK,oCAAoC;AACpE,WAAO;AAAA,EACT;AACA,SAAO,WAAY,OAAoB,OAAO,OAAO,CAAC,GAAI,IAAiB,CAAC;AAC9E;AAEA,IAAM,SAAS;AACf,IAAM,mBAAsC,CAAC,UAAU,cAAc,OAAO;AAU5E,SAAS,eACP,OACA,UACA,KACmC;AACnC,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,CAAC,QAAuB;AACnC,UAAM,QAAQ,QAAQ,SAAY,KAAK,KAAK,GAAG;AAC/C,UAAM,WACF,IAAI,eAAe,2BAA2B,GAAG,GAAG,KAAK,EAAE,IAC3D,IAAI,gBAAgB,WAAW,GAAG,EAAE;AAAA,EAC1C;AACA,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,MAAK,kBAAkB;AAClD,QAAM,OAAO;AACb,QAAM,MAAM;AACZ,MAAI,KAAK,SAAS,IAAK,MAAK,OAAO,KAAK,MAAM,iBAAiB,GAAG,EAAE;AACpE,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAoB,CAAC;AAC3B,aAAW,KAAK,MAAM;AACpB,QAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,MAAM,QAAQ,CAAC,EAAG,MAAK,4BAA4B;AAC9F,UAAM,QAAQ;AACd,UAAM,QAAQ,OAAO,KAAK,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,SAAS,CAAC,CAAC;AAC5E,QAAI,MAAM,SAAS,EAAG,MAAK,yCAAyC,MAAM,KAAK,IAAI,CAAC,GAAG;AACvF,UAAM,EAAE,QAAQ,YAAY,MAAM,IAAI;AACtC,QAAI,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK,MAAM,GAAG;AACtD,WAAK,0CAA0C;AAAA,IACjD;AACA,QAAI,KAAK,IAAI,MAAgB,EAAG,MAAK,wBAAwB;AAC7D,SAAK,IAAI,MAAgB;AACzB,eAAW,CAAC,MAAM,CAAC,KAAK;AAAA,MACtB,CAAC,cAAc,UAAU;AAAA,MACzB,CAAC,SAAS,KAAK;AAAA,IACjB,GAAY;AACV,UAAI,CAAC,OAAO,cAAc,CAAC,KAAM,IAAe,GAAG;AACjD,aAAK,GAAG,IAAI,6CAA6C,OAAO,CAAC,CAAC,GAAG;AAAA,MACvE;AAAA,IACF;AACA,QAAI;AAAA,MACF,WACK,QACD,OAAO,OAAO;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACP;AAAA,EACF;AACA,MAAI,SAAU,QAAO;AACrB,SAAO,IAAI,WAAW,IAAI,SAAY,OAAO,OAAO,GAAG;AACzD;AAGA,SAAS,sBACP,QACA,YACM;AACN,MAAI,WAAW,UAAa,OAAO,SAAS,KAAK,eAAe,MAAM;AACpE,UAAM,IAAI,gBAAgB,0DAA0D;AAAA,EACtF;AACF;AAGA,SAAS,sBACP,UACA,YACM;AACN,MAAI,aAAa,OAAW;AAC5B,MAAI,eAAe,MAAM;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,SAAS,SAAS,SAAS,CAAC;AACxC,MAAI,QAAQ,UAAa,OAAO,YAAY;AAC1C,UAAM,IAAI;AAAA,MACR,6BAA6B,GAAG,0CAA0C,UAAU;AAAA,IACtF;AAAA,EACF;AACF;AAMO,SAAS,0BAA0B,KAA2C;AACnF,qBAAmB,IAAI,UAAU;AACjC,MAAI,IAAI,WAAW,OAAW,gBAAe,IAAI,MAAM;AACvD,sBAAoB,IAAI,aAAa,KAAK;AAC1C,qBAAmB,IAAI,WAAW,WAAW;AAC7C,qBAAmB,IAAI,WAAW,WAAW;AAC7C,QAAM,WAAW,iBAAiB,IAAI,UAAU,KAAK;AACrD,wBAAsB,UAAU,IAAI,UAAU;AAC9C,QAAM,WAAW,aAAa,SAAY,MAAM,EAAE,GAAG,KAAK,SAAS;AACnE,MAAI,EAAE,aAAa,KAAM,QAAO;AAChC,QAAM,UAAU,gBAAgB,IAAI,SAAS,KAAK;AAClD,uBAAqB,SAAS,IAAI,UAAU;AAC5C,sBAAoB,SAAS,IAAI,WAAW;AAC5C,SAAO,EAAE,GAAG,UAAU,QAAQ;AAChC;AAOO,SAAS,sBAAsB,OAAqC;AACzE,0BAAwB,KAAK;AAC7B,MAAI,MAAM,WAAW,OAAW,gBAAe,MAAM,MAAM;AAC3D,MAAI,iBAAiB,MAAO,qBAAoB,MAAM,aAAa,KAAK;AACxE,MAAI,eAAe,MAAO,oBAAmB,MAAM,WAAW,WAAW;AACzE,MAAI,eAAe,MAAO,oBAAmB,MAAM,WAAW,WAAW;AACzE,QAAM,WACJ,MAAM,aAAa,SACf,QACA,EAAE,GAAG,OAAO,UAAU,iBAAiB,MAAM,UAAU,KAAK,EAAE;AACpE,QAAM,aACJ,YAAY,WACR,EAAE,GAAG,UAAU,QAAQ,eAAe,SAAS,QAAQ,KAAK,EAAE,IAC9D;AACN,MAAI,EAAE,aAAa,OAAQ,QAAO;AAClC,SAAO,EAAE,GAAG,YAAY,SAAS,gBAAgB,MAAM,SAAS,KAAK,EAAE;AACzE;AA8BO,IAAM,0BAA0B;AAMvC,IAAM,iCAAiC;AAOhC,SAAS,4BAA4B,KAAc,KAAqB;AAC7E,MAAI,QAAQ,QAAW;AACrB,UAAM,IAAI,eAAe,sCAAsC,GAAG,EAAE;AAAA,EACtE;AACA,MAAI,OAAO,QAAQ,YAAY,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,gCAAgC;AAC7F,UAAM,IAAI,eAAe,+CAA+C,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE;AAAA,EAC/F;AACA,MAAI,MAAM,yBAAyB;AACjC,UAAM,IAAI;AAAA,MACR,8BAA8B,GAAG,qCAAqC,uBAAuB,MAAM,GAAG;AAAA,IACxG;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,0BAA0B,KAA+B;AACvE,SAAO,KAAK,UAAU;AAAA,IACpB,eAAe;AAAA,IACf,SAAS,IAAI;AAAA,IACb,QAAQ,IAAI;AAAA,EACd,CAAC;AACH;AAkBA,IAAM,gBAAgB;AAEtB,IAAM,wBAAwB;AAE9B,IAAM,oBAAoB;AAE1B,IAAM,cAAc;AAapB,SAAS,WAAW,OAAe,eAAmC,KAAyB;AAC7F,QAAM,OACJ,kBAAkB,UAAa,kBAAkB,IAAI,cAAc,KAAK,KAAK,IAAI;AACnF,QAAM,UACJ,kBAAkB,UAAa,iBAAiB,IAC3C,sBAAsB,KAAK,KAAK,KAAK,kBAAkB,KAAK,KAAK,IAClE;AACN,QAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,MAAM;AAClB,UAAM,IAAI;AAAA,MACR,0CAA0C,iBAAiB,uBAAuB,eAC5E,MAAM,KAAK,UAAU,KAAK,CAAC,CAAC,MAAM,GAAG;AAAA,IAC7C;AAAA,EACF;AACA,QAAM,OAAO,MAAM,WAAW;AAC9B,QAAM,UAAU,OAAO,OAAO,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;AACjD,MAAI,CAAC,OAAO,cAAc,OAAO,GAAG;AAClC,UAAM,IAAI,eAAe,8DAA8D,GAAG,EAAE;AAAA,EAC9F;AACA,SAAO,EAAE,aAAa,OAAO,MAAM,CAAC,IAAI,QAAW,QAAQ;AAC7D;AAQA,SAAS,QAAQ,SAAkB,OAAuB;AACxD,QAAM,QAAQ,QAAQ,KAAK;AAC3B,MAAI,EAAE,iBAAiB,eAAe,MAAM,WAAW,OAAO;AAC5D,UAAM,IAAI;AAAA,MACR,6CAA6C,KAAK;AAAA,IACpD;AAAA,EACF;AACA,MAAI,MAAM;AACV,aAAW,KAAK,MAAO,QAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC5D,SAAO;AACT;AAGO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,QAAQ,SAAS,iBAAiB;AAC3C;AAGO,SAAS,UAAU,SAA0B;AAClD,SAAO,QAAQ,SAAS,WAAW;AACrC;AAMO,SAAS,kBAAkB,QAAwB,SAAyB;AACjF,QAAM,EAAE,aAAa,QAAQ,IAAI,WAAW,OAAO,OAAO,QAAW,OAAO,OAAO;AACnF,QAAM,OAAO,GAAG,UAAU,CAAC,IAAI,UAAU,OAAO,CAAC;AACjD,SAAO,gBAAgB,SAAY,OAAO,GAAG,WAAW,IAAI,IAAI;AAClE;AAMO,SAAS,oBACd,SACA,WACO;AACP,QAAM,UACJ,cAAc,SACV,IACA,WAAW,UAAU,OAAO,QAAW,UAAU,OAAO,EAAE,UAAU;AAC1E,SAAO,GAAG,gBAAgB,OAAO,CAAC,IAAI,OAAO,IAAI,UAAU,OAAO,CAAC;AACrE;AAGA,SAAS,MAAM,GAAoB;AACjC,QAAM,OAAO,OAAO,CAAC;AACrB,SAAO,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,WAAM;AACtD;AAQO,SAAS,sBACd,MACA,KACA,UACkB;AAClB,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,UAAM,IAAI,eAAe,mCAAmC,GAAG,EAAE;AAAA,EACnE;AAGA,MAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,UAAM,IAAI,eAAe,0CAA0C,GAAG,EAAE;AAAA,EAC1E;AACA,QAAM,MAAM;AACZ,QAAM,gBAAgB,4BAA4B,IAAI,eAAe,GAAG;AACxE,QAAM,QAAQ,OAAO,KAAK,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,SAAS,CAAC,CAAC;AACzE,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI;AAAA,MACR,0DAA0D,MAAM,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG;AAAA,IAC5F;AAAA,EACF;AACA,MAAI,OAAO,IAAI,YAAY,aAAa,IAAI,WAAW,QAAQ,OAAO,IAAI,WAAW,UAAU;AAC7F,UAAM,IAAI,eAAe,0CAA0C,GAAG,EAAE;AAAA,EAC1E;AACA,QAAM,IAAI,IAAI;AACd,0BAAwB,GAAG,KAAK,aAAa;AAC7C,MAAI,OAAO,EAAE,UAAU,UAAU;AAC/B,UAAM,IAAI,eAAe,sCAAsC,GAAG,EAAE;AAAA,EACtE;AACA,aAAW,EAAE,OAAO,eAAe,GAAG;AAItC,MACE,aAAa,WACZ,EAAE,YAAY,SAAS,YACrB,EAAE,aAAa,aAAgB,SAAS,aAAa,UACxD;AACA,UAAM,IAAI;AAAA,MACR,qEAAqE,GAAG;AAAA,IAC1E;AAAA,EACF;AACA,SAAO,EAAE,SAAS,IAAI,SAAS,QAAQ,IAAI,OAAyB;AACtE;AAGO,SAAS,cACd,KACA,KACA,KACA,OACgB;AAChB,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,SAAS,IAAI;AAAA,IACb,YAAY,IAAI;AAAA,IAChB,aAAa,IAAI;AAAA,IACjB,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI,UAAU;AAAA,IACtB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,SAAS,IAAI;AAAA,IACb,UAAU,IAAI;AAAA;AAAA,IAEd,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,EACF;AACF;AAQO,SAAS,wBACd,GACA,KACA,gBAAwB,yBAClB;AACN,MACE,OAAO,EAAE,YAAY,YACpB,EAAE,cAAc,UAAa,OAAO,EAAE,cAAc,YACpD,EAAE,eAAe,QAAQ,OAAO,EAAE,eAAe,YAClD,OAAO,EAAE,WAAW,YACpB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,cAAc,UACvB;AACA,UAAM,IAAI,eAAe,+CAA+C,GAAG,EAAE;AAAA,EAC/E;AAGA,MAAI,EAAE,eAAe,SAAS,CAAC,OAAO,cAAc,EAAE,UAAU,KAAK,EAAE,aAAa,IAAI;AACtF,UAAM,IAAI;AAAA,MACR,8CAA8C,MAAM,EAAE,UAAU,CAAC,MAAM,GAAG;AAAA,IAC5E;AAAA,EACF;AACA,MAAI,CAAC,SAAS,SAAS,EAAE,MAAM,GAAG;AAChC,UAAM,IAAI,eAAe,0CAA0C,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,EAAE;AAAA,EAC/F;AACA,QAAM,WAAW,SAAS,aAAa;AACvC,QAAM,QAAQ,OAAO,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,SAAS,CAAC,CAAC;AAChE,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI;AAAA,MACR,uCAAuC,aAAa,0BAA0B,MAAM,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG;AAAA,IAChH;AAAA,EACF;AACA,MAAI,EAAE,UAAU,UAAa,OAAO,EAAE,UAAU,UAAU;AACxD,UAAM,IAAI,eAAe,yCAAyC,GAAG,EAAE;AAAA,EACzE;AACA,sBAAoB,EAAE,aAAa,IAAI;AAOvC,aAAW,SAAS,CAAC,aAAa,WAAW,GAAY;AACvD,UAAM,OAAO,EAAE,KAAK;AACpB,QAAI,SAAS,WAAc,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,IAAI;AAC5F,YAAM,IAAI,eAAe,oCAAoC,KAAK,KAAK,GAAG,EAAE;AAAA,IAC9E;AAAA,EACF;AAIA,kBAAgB,EAAE,SAAS,MAAM,GAAG;AACpC,mBAAiB,EAAE,UAAU,MAAM,GAAG;AACtC,iBAAe,EAAE,QAAQ,MAAM,GAAG;AACpC;AAYO,SAAS,mBACd,MACA,OACA,KACA,OACgB;AAKhB,QAAM,aAAa,gBAAgB,QAAS,MAAM,cAAc,OAAQ,KAAK;AAC7E,QAAM,cAAc,iBAAiB,QAAQ,MAAM,cAAc,KAAK;AACtE,MAAI;AACJ,MAAI,aAAa,OAAO;AACtB,yBAAqB,MAAM,SAAS,UAAU;AAC9C,wBAAoB,MAAM,SAAS,WAAW;AAC9C,cAAU,MAAM;AAAA,EAClB,OAAO;AAEL,UAAM,OAAO,eAAe,KAAK,aAAa,KAAK,UAAU;AAC7D,cAAU,SAAS,UAAa,sBAAsB,MAAM,WAAW,IAAI,OAAO;AAAA,EACpF;AAGA,MAAI;AACJ,MAAI,cAAc,OAAO;AACvB,0BAAsB,MAAM,UAAU,UAAU;AAChD,eAAW,MAAM;AAAA,EACnB,OAAO;AACL,eAAW,eAAe,KAAK,aAAa,KAAK,WAAW;AAAA,EAC9D;AAEA,MAAI;AACJ,MAAI,YAAY,OAAO;AACrB,aAAS,MAAM;AACf,0BAAsB,QAAQ,UAAU;AAGxC,UAAM,OAAO,KAAK,IAAI,wBAAwB,KAAK,QAAQ,UAAU,CAAC;AACtE,QAAI,WAAW,UAAa,OAAO,SAAS,MAAM;AAChD,YAAM,IAAI,gBAAgB,eAAe,OAAO,MAAM,iBAAiB,IAAI,EAAE;AAAA,IAC/E;AAAA,EACF,OAAO;AACL,aAAS,KAAK;AAAA,EAChB;AACA,SAAO;AAAA,IACL,WAAW,KAAK;AAAA,IAChB,SAAS,KAAK;AAAA,IACd;AAAA,IACA;AAAA,IACA,OAAO,WAAW,QAAQ,MAAM,QAAQ,KAAK;AAAA,IAC7C,QAAQ,MAAM,UAAU,KAAK;AAAA,IAC7B,WAAW,eAAe,QAAQ,MAAM,YAAY,KAAK;AAAA,IACzD,WAAW,eAAe,QAAQ,MAAM,YAAY,KAAK;AAAA,IACzD;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,WAAW;AAAA,IACX;AAAA,EACF;AACF;;;AC70BA,SAAS,YAAmC;AAC1C,QAAM,IAAK,WAA0D;AACrE,SAAO,MAAM,UAAa,OAAO,EAAE,oBAAoB,aAAc,IAAkB;AACzF;AAGO,IAAM,mBAA4B,CAAC,WAAW;AACnD,QAAM,IAAI,UAAU;AACpB,MAAI,MAAM,QAAW;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,SAAO,EAAE,gBAAgB,IAAI,WAAW,MAAM,CAAC;AACjD;AAGO,SAAS,mBAAmB,SAA2B;AAC5D,SAAO,YAAY,oBAAoB,UAAU,MAAM;AACzD;",
6
+ "names": []
7
+ }