@cloudbitmaps/core 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/azure/index.d.cts +1 -1
- package/dist/azure/index.d.ts +1 -1
- package/dist/cassandra/index.cjs.map +1 -1
- package/dist/cassandra/index.d.cts +1 -1
- package/dist/cassandra/index.d.ts +1 -1
- package/dist/cassandra/index.js +1 -1
- package/dist/{chunk-2YDULGXS.js → chunk-L54FL5DW.js} +2 -2
- package/dist/{chunk-2YDULGXS.js.map → chunk-L54FL5DW.js.map} +1 -1
- package/dist/{chunk-AS6ODRLT.js → chunk-YEHMG6W2.js} +2 -2
- package/dist/{chunk-AS6ODRLT.js.map → chunk-YEHMG6W2.js.map} +1 -1
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +6 -6
- package/dist/dynamodb/index.d.ts +6 -6
- package/dist/dynamodb/index.js +2 -2
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/gcs/index.d.cts +1 -1
- package/dist/gcs/index.d.ts +1 -1
- package/dist/index.cjs +34 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -15
- package/dist/index.d.ts +36 -15
- package/dist/index.js +37 -3
- package/dist/index.js.map +1 -1
- package/dist/mongodb/index.cjs.map +1 -1
- package/dist/mongodb/index.d.cts +1 -1
- package/dist/mongodb/index.d.ts +1 -1
- package/dist/mongodb/index.js +1 -1
- package/dist/mysql/index.cjs.map +1 -1
- package/dist/mysql/index.d.cts +1 -1
- package/dist/mysql/index.d.ts +1 -1
- package/dist/mysql/index.js +1 -1
- package/dist/mysql/index.js.map +1 -1
- package/dist/{ports-D3BrJ6ax.d.cts → ports-5BQTGKze.d.cts} +2 -3
- package/dist/{ports-D3BrJ6ax.d.ts → ports-5BQTGKze.d.ts} +2 -3
- package/dist/postgres/index.cjs.map +1 -1
- package/dist/postgres/index.d.cts +1 -1
- package/dist/postgres/index.d.ts +1 -1
- package/dist/postgres/index.js +1 -1
- package/dist/redis/index.cjs.map +1 -1
- package/dist/redis/index.d.cts +1 -1
- package/dist/redis/index.d.ts +1 -1
- package/dist/redis/index.js +1 -1
- package/dist/s3/index.cjs.map +1 -1
- package/dist/s3/index.d.cts +1 -1
- package/dist/s3/index.d.ts +1 -1
- package/dist/s3/index.js +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as IWarmDriver, h as ColdChunkSource, S as SegmentRef, W as WarmReadOptions, i as SegmentSize, I as IColdDriver, d as IRegistryDriver, j as IKeystore, b as ChunkRef, C as ColdCaps, G as GenKey, B as BlobSink, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch, c as WarmRow, N as NoRow, k as CrbmCrypto, l as BlobReader, m as WrappedDek, A as Aead, n as AeadSealed } from './ports-
|
|
2
|
-
export { o as BufferReader, p as BufferSink, q as GovernanceMeta, r as NO_ROW, s as RegistryStatus, t as aadFor } from './ports-
|
|
1
|
+
import { a as IWarmDriver, h as ColdChunkSource, S as SegmentRef, W as WarmReadOptions, i as SegmentSize, I as IColdDriver, d as IRegistryDriver, j as IKeystore, b as ChunkRef, C as ColdCaps, G as GenKey, B as BlobSink, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch, c as WarmRow, N as NoRow, k as CrbmCrypto, l as BlobReader, m as WrappedDek, A as Aead, n as AeadSealed } from './ports-5BQTGKze.cjs';
|
|
2
|
+
export { o as BufferReader, p as BufferSink, q as GovernanceMeta, r as NO_ROW, s as RegistryStatus, t as aadFor } from './ports-5BQTGKze.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The **bitmap-codec seam**.
|
|
@@ -50,6 +50,17 @@ interface CodecBitmap {
|
|
|
50
50
|
/** Ascending iterator over the set values. */
|
|
51
51
|
[Symbol.iterator](): IterableIterator<number>;
|
|
52
52
|
toArray(): number[];
|
|
53
|
+
/**
|
|
54
|
+
* The largest value in the set, or `undefined` when empty.
|
|
55
|
+
*
|
|
56
|
+
* **Optional, and deliberately so.** The engine uses it for one thing: asserting that a payload it is about
|
|
57
|
+
* to interpret **as a chunk** holds only 16-bit remainders (see {@link assertChunkPayload}). A codec that
|
|
58
|
+
* cannot answer this in better than O(n) should simply omit it — the engine then skips the check rather
|
|
59
|
+
* than walking every value on the read path, which is the one thing this must never cost.
|
|
60
|
+
*
|
|
61
|
+
* Roaring answers it in O(1) from its container index, so the flagship codec implements it.
|
|
62
|
+
*/
|
|
63
|
+
maximum?(): number | undefined;
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
55
66
|
* A pluggable bitmap codec — the factory the codec-agnostic engine constructs {@link CodecBitmap}s through.
|
|
@@ -426,7 +437,7 @@ interface EngineDeps {
|
|
|
426
437
|
readonly cache?: BoundedLru<string, CodecBitmap>;
|
|
427
438
|
readonly maxBitmapBytes?: number;
|
|
428
439
|
/**
|
|
429
|
-
* The bitmap codec
|
|
440
|
+
* The bitmap codec — **required**. `core/` is
|
|
430
441
|
* codec-agnostic: it can have no default, because the concrete codec lives in a *flavor* package that depends
|
|
431
442
|
* on core (a default here would invert that arrow). A flavor's facade injects it — `@cloudbitmaps/roaring`
|
|
432
443
|
* passes `roaringCodec` — so applications never see this.
|
|
@@ -545,6 +556,21 @@ declare class SegmentEngine {
|
|
|
545
556
|
* letting it flow into `joinId` and produce a bogus id.
|
|
546
557
|
*/
|
|
547
558
|
private assertChunkKeyInRange;
|
|
559
|
+
/**
|
|
560
|
+
* The other half of invariant 5, and the one that was missing: a chunk payload holds **remainders** — 16-bit
|
|
561
|
+
* offsets within one chunk — so every value must be `<= 0xffff`.
|
|
562
|
+
*
|
|
563
|
+
* Nothing upstream established that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes
|
|
564
|
+
* that were written — which anyone able to write the tier satisfies trivially. A value `>= 65536` then
|
|
565
|
+
* reaches `joinId`, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a
|
|
566
|
+
* different chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious
|
|
567
|
+
* `intersect` matches. Compaction is the only path that already failed loud (`CrbmWriter` rejects
|
|
568
|
+
* `cardinality > 65536`), which merely turns the same row into a permanently poison segment.
|
|
569
|
+
*
|
|
570
|
+
* Costs one `maximum()` per chunk, not per id — `maximum` is optional on the codec seam precisely so a codec
|
|
571
|
+
* that cannot answer in O(1) opts out instead of making the read path walk every value.
|
|
572
|
+
*/
|
|
573
|
+
private assertChunkPayloadInRange;
|
|
548
574
|
private effectiveChunk;
|
|
549
575
|
/** The segment's current generation, resolved once per op (`undefined` ⇒ source can't report it). */
|
|
550
576
|
private currentGen;
|
|
@@ -824,7 +850,7 @@ declare class RecordingAuditSink implements IAuditSink {
|
|
|
824
850
|
* **Correctness without a lock:** the commit is the conditional `currentGen` swap; write-once generations +
|
|
825
851
|
* version-fenced purge make even two concurrent compactions safe (the loser's staged generation is an orphan
|
|
826
852
|
* GC'd later; no torn read — readers are pinned to a committed generation, **I5**). The lease only avoids that
|
|
827
|
-
* wasted duplicate work
|
|
853
|
+
* wasted duplicate work.
|
|
828
854
|
*
|
|
829
855
|
* Pure orchestration over the injected driver interfaces + an injected {@link Clock} (timer-free; the daemon
|
|
830
856
|
* layer owns scheduling/heartbeat). A crash at *any* step is recoverable: nothing is destructive until after
|
|
@@ -839,7 +865,7 @@ interface CompactionDeps {
|
|
|
839
865
|
readonly clock: Pick<Clock, 'now'>;
|
|
840
866
|
readonly maxBitmapBytes?: number;
|
|
841
867
|
/**
|
|
842
|
-
* Bitmap codec
|
|
868
|
+
* Bitmap codec — compaction only merges bitmaps through it. Optional in the type so this
|
|
843
869
|
* stays call-compatible public API; a **flavor** package binds it (see {@link requireCodec}).
|
|
844
870
|
*/
|
|
845
871
|
readonly codec?: CodecInterface;
|
|
@@ -1040,7 +1066,7 @@ interface ExportOptions {
|
|
|
1040
1066
|
/** Output format; defaults to `'roaring'`. */
|
|
1041
1067
|
readonly format?: ExportFormat;
|
|
1042
1068
|
/**
|
|
1043
|
-
* Bitmap codec used to build the exported bitmap for the `'roaring'` format
|
|
1069
|
+
* Bitmap codec used to build the exported bitmap for the `'roaring'` format. Optional in the
|
|
1044
1070
|
* type so this stays call-compatible public API; a **flavor** package binds it (see `requireCodec`). Not needed
|
|
1045
1071
|
* for `'ndjson'`, which streams plain ids.
|
|
1046
1072
|
*/
|
|
@@ -1123,11 +1149,6 @@ interface BitRoute {
|
|
|
1123
1149
|
}
|
|
1124
1150
|
/** Split a u32 id into `{ chunkKey, remainder }`. Throws `ValidationError` for non-u32 input. */
|
|
1125
1151
|
declare function splitId(id: number): BitRoute;
|
|
1126
|
-
/**
|
|
1127
|
-
* Recombine a chunk key + remainder back into the u32 id. Precondition: `chunkKey` is a validated
|
|
1128
|
-
* 16-bit value (tier-derived keys are validated upstream in the engine before reaching here, per
|
|
1129
|
-
* invariant 5); `remainder` is masked to 16 bits.
|
|
1130
|
-
*/
|
|
1131
1152
|
declare function joinId(chunkKey: number, remainder: number): number;
|
|
1132
1153
|
|
|
1133
1154
|
/**
|
|
@@ -1516,14 +1537,14 @@ interface BulkLoadResult {
|
|
|
1516
1537
|
readonly cardinality: number;
|
|
1517
1538
|
}
|
|
1518
1539
|
/**
|
|
1519
|
-
* **Bulk-load** a whole immutable generation from a flat id source — the batch "seed/
|
|
1540
|
+
* **Bulk-load** a whole immutable generation from a flat id source — the batch "seed/rebuild" entry point.
|
|
1520
1541
|
* Unlike {@link writeCrbmGeneration} (which takes pre-grouped bitmaps), this
|
|
1521
1542
|
* consumes an arbitrary, **unsorted** stream of u32 ids (sync or async) and routes each into its chunk's
|
|
1522
1543
|
* Roaring bitmap as it goes. The input is consumed lazily and ids dedup on insert, so memory is bounded by
|
|
1523
1544
|
* the **built generation** — the in-memory Roaring representation of the *distinct* set (≤ one bitmap per
|
|
1524
1545
|
* non-empty chunk) — not by the input length: you can stream a billion duplicate-heavy ids and hold only the
|
|
1525
1546
|
* distinct result. Note this is `O(distinct set)`, **not** window-bounded like {@link SegmentEngine.intersect}:
|
|
1526
|
-
* bulk-load holds the whole generation in RAM, which suits batch seed/
|
|
1547
|
+
* bulk-load holds the whole generation in RAM, which suits batch seed/rebuild jobs but not an
|
|
1527
1548
|
* unbounded-cardinality stream (a segment larger than RAM needs external-merge / pre-sorted input — later phase).
|
|
1528
1549
|
*
|
|
1529
1550
|
* Each id must be an integer in `[0, 2³²)` ({@link splitId} throws {@link ValidationError} otherwise) — the
|
|
@@ -1541,7 +1562,7 @@ declare function bulkLoadCrbmGeneration(driver: IColdDriver, key: GenKey, ids: I
|
|
|
1541
1562
|
keystore?: IKeystore;
|
|
1542
1563
|
requireEncryption?: boolean;
|
|
1543
1564
|
audit?: IAuditSink;
|
|
1544
|
-
/** Bitmap codec
|
|
1565
|
+
/** Bitmap codec. Optional in the type; a **flavor** package binds it ({@link requireCodec}). */
|
|
1545
1566
|
codec?: CodecInterface;
|
|
1546
1567
|
}): Promise<BulkLoadResult>;
|
|
1547
1568
|
|
|
@@ -1696,7 +1717,7 @@ declare class InProcessKeystore implements IKeystore {
|
|
|
1696
1717
|
}
|
|
1697
1718
|
|
|
1698
1719
|
/**
|
|
1699
|
-
* Crypto-shred erasure (Phase 4e
|
|
1720
|
+
* Crypto-shred erasure (Phase 4e).
|
|
1700
1721
|
*
|
|
1701
1722
|
* GDPR "right to erasure" on immutable/backed-up Cold storage: you can't delete a `.crbm` object from every
|
|
1702
1723
|
* backup, but you can **delete its key**. `destroySegment` drops the segment's wrapped DEK(s) from the registry
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as IWarmDriver, h as ColdChunkSource, S as SegmentRef, W as WarmReadOptions, i as SegmentSize, I as IColdDriver, d as IRegistryDriver, j as IKeystore, b as ChunkRef, C as ColdCaps, G as GenKey, B as BlobSink, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch, c as WarmRow, N as NoRow, k as CrbmCrypto, l as BlobReader, m as WrappedDek, A as Aead, n as AeadSealed } from './ports-
|
|
2
|
-
export { o as BufferReader, p as BufferSink, q as GovernanceMeta, r as NO_ROW, s as RegistryStatus, t as aadFor } from './ports-
|
|
1
|
+
import { a as IWarmDriver, h as ColdChunkSource, S as SegmentRef, W as WarmReadOptions, i as SegmentSize, I as IColdDriver, d as IRegistryDriver, j as IKeystore, b as ChunkRef, C as ColdCaps, G as GenKey, B as BlobSink, R as RegCaps, e as RegistryRecord, f as NewRegistryRecord, T as Token, g as RegistryPatch, c as WarmRow, N as NoRow, k as CrbmCrypto, l as BlobReader, m as WrappedDek, A as Aead, n as AeadSealed } from './ports-5BQTGKze.js';
|
|
2
|
+
export { o as BufferReader, p as BufferSink, q as GovernanceMeta, r as NO_ROW, s as RegistryStatus, t as aadFor } from './ports-5BQTGKze.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The **bitmap-codec seam**.
|
|
@@ -50,6 +50,17 @@ interface CodecBitmap {
|
|
|
50
50
|
/** Ascending iterator over the set values. */
|
|
51
51
|
[Symbol.iterator](): IterableIterator<number>;
|
|
52
52
|
toArray(): number[];
|
|
53
|
+
/**
|
|
54
|
+
* The largest value in the set, or `undefined` when empty.
|
|
55
|
+
*
|
|
56
|
+
* **Optional, and deliberately so.** The engine uses it for one thing: asserting that a payload it is about
|
|
57
|
+
* to interpret **as a chunk** holds only 16-bit remainders (see {@link assertChunkPayload}). A codec that
|
|
58
|
+
* cannot answer this in better than O(n) should simply omit it — the engine then skips the check rather
|
|
59
|
+
* than walking every value on the read path, which is the one thing this must never cost.
|
|
60
|
+
*
|
|
61
|
+
* Roaring answers it in O(1) from its container index, so the flagship codec implements it.
|
|
62
|
+
*/
|
|
63
|
+
maximum?(): number | undefined;
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
55
66
|
* A pluggable bitmap codec — the factory the codec-agnostic engine constructs {@link CodecBitmap}s through.
|
|
@@ -426,7 +437,7 @@ interface EngineDeps {
|
|
|
426
437
|
readonly cache?: BoundedLru<string, CodecBitmap>;
|
|
427
438
|
readonly maxBitmapBytes?: number;
|
|
428
439
|
/**
|
|
429
|
-
* The bitmap codec
|
|
440
|
+
* The bitmap codec — **required**. `core/` is
|
|
430
441
|
* codec-agnostic: it can have no default, because the concrete codec lives in a *flavor* package that depends
|
|
431
442
|
* on core (a default here would invert that arrow). A flavor's facade injects it — `@cloudbitmaps/roaring`
|
|
432
443
|
* passes `roaringCodec` — so applications never see this.
|
|
@@ -545,6 +556,21 @@ declare class SegmentEngine {
|
|
|
545
556
|
* letting it flow into `joinId` and produce a bogus id.
|
|
546
557
|
*/
|
|
547
558
|
private assertChunkKeyInRange;
|
|
559
|
+
/**
|
|
560
|
+
* The other half of invariant 5, and the one that was missing: a chunk payload holds **remainders** — 16-bit
|
|
561
|
+
* offsets within one chunk — so every value must be `<= 0xffff`.
|
|
562
|
+
*
|
|
563
|
+
* Nothing upstream established that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes
|
|
564
|
+
* that were written — which anyone able to write the tier satisfies trivially. A value `>= 65536` then
|
|
565
|
+
* reaches `joinId`, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a
|
|
566
|
+
* different chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious
|
|
567
|
+
* `intersect` matches. Compaction is the only path that already failed loud (`CrbmWriter` rejects
|
|
568
|
+
* `cardinality > 65536`), which merely turns the same row into a permanently poison segment.
|
|
569
|
+
*
|
|
570
|
+
* Costs one `maximum()` per chunk, not per id — `maximum` is optional on the codec seam precisely so a codec
|
|
571
|
+
* that cannot answer in O(1) opts out instead of making the read path walk every value.
|
|
572
|
+
*/
|
|
573
|
+
private assertChunkPayloadInRange;
|
|
548
574
|
private effectiveChunk;
|
|
549
575
|
/** The segment's current generation, resolved once per op (`undefined` ⇒ source can't report it). */
|
|
550
576
|
private currentGen;
|
|
@@ -824,7 +850,7 @@ declare class RecordingAuditSink implements IAuditSink {
|
|
|
824
850
|
* **Correctness without a lock:** the commit is the conditional `currentGen` swap; write-once generations +
|
|
825
851
|
* version-fenced purge make even two concurrent compactions safe (the loser's staged generation is an orphan
|
|
826
852
|
* GC'd later; no torn read — readers are pinned to a committed generation, **I5**). The lease only avoids that
|
|
827
|
-
* wasted duplicate work
|
|
853
|
+
* wasted duplicate work.
|
|
828
854
|
*
|
|
829
855
|
* Pure orchestration over the injected driver interfaces + an injected {@link Clock} (timer-free; the daemon
|
|
830
856
|
* layer owns scheduling/heartbeat). A crash at *any* step is recoverable: nothing is destructive until after
|
|
@@ -839,7 +865,7 @@ interface CompactionDeps {
|
|
|
839
865
|
readonly clock: Pick<Clock, 'now'>;
|
|
840
866
|
readonly maxBitmapBytes?: number;
|
|
841
867
|
/**
|
|
842
|
-
* Bitmap codec
|
|
868
|
+
* Bitmap codec — compaction only merges bitmaps through it. Optional in the type so this
|
|
843
869
|
* stays call-compatible public API; a **flavor** package binds it (see {@link requireCodec}).
|
|
844
870
|
*/
|
|
845
871
|
readonly codec?: CodecInterface;
|
|
@@ -1040,7 +1066,7 @@ interface ExportOptions {
|
|
|
1040
1066
|
/** Output format; defaults to `'roaring'`. */
|
|
1041
1067
|
readonly format?: ExportFormat;
|
|
1042
1068
|
/**
|
|
1043
|
-
* Bitmap codec used to build the exported bitmap for the `'roaring'` format
|
|
1069
|
+
* Bitmap codec used to build the exported bitmap for the `'roaring'` format. Optional in the
|
|
1044
1070
|
* type so this stays call-compatible public API; a **flavor** package binds it (see `requireCodec`). Not needed
|
|
1045
1071
|
* for `'ndjson'`, which streams plain ids.
|
|
1046
1072
|
*/
|
|
@@ -1123,11 +1149,6 @@ interface BitRoute {
|
|
|
1123
1149
|
}
|
|
1124
1150
|
/** Split a u32 id into `{ chunkKey, remainder }`. Throws `ValidationError` for non-u32 input. */
|
|
1125
1151
|
declare function splitId(id: number): BitRoute;
|
|
1126
|
-
/**
|
|
1127
|
-
* Recombine a chunk key + remainder back into the u32 id. Precondition: `chunkKey` is a validated
|
|
1128
|
-
* 16-bit value (tier-derived keys are validated upstream in the engine before reaching here, per
|
|
1129
|
-
* invariant 5); `remainder` is masked to 16 bits.
|
|
1130
|
-
*/
|
|
1131
1152
|
declare function joinId(chunkKey: number, remainder: number): number;
|
|
1132
1153
|
|
|
1133
1154
|
/**
|
|
@@ -1516,14 +1537,14 @@ interface BulkLoadResult {
|
|
|
1516
1537
|
readonly cardinality: number;
|
|
1517
1538
|
}
|
|
1518
1539
|
/**
|
|
1519
|
-
* **Bulk-load** a whole immutable generation from a flat id source — the batch "seed/
|
|
1540
|
+
* **Bulk-load** a whole immutable generation from a flat id source — the batch "seed/rebuild" entry point.
|
|
1520
1541
|
* Unlike {@link writeCrbmGeneration} (which takes pre-grouped bitmaps), this
|
|
1521
1542
|
* consumes an arbitrary, **unsorted** stream of u32 ids (sync or async) and routes each into its chunk's
|
|
1522
1543
|
* Roaring bitmap as it goes. The input is consumed lazily and ids dedup on insert, so memory is bounded by
|
|
1523
1544
|
* the **built generation** — the in-memory Roaring representation of the *distinct* set (≤ one bitmap per
|
|
1524
1545
|
* non-empty chunk) — not by the input length: you can stream a billion duplicate-heavy ids and hold only the
|
|
1525
1546
|
* distinct result. Note this is `O(distinct set)`, **not** window-bounded like {@link SegmentEngine.intersect}:
|
|
1526
|
-
* bulk-load holds the whole generation in RAM, which suits batch seed/
|
|
1547
|
+
* bulk-load holds the whole generation in RAM, which suits batch seed/rebuild jobs but not an
|
|
1527
1548
|
* unbounded-cardinality stream (a segment larger than RAM needs external-merge / pre-sorted input — later phase).
|
|
1528
1549
|
*
|
|
1529
1550
|
* Each id must be an integer in `[0, 2³²)` ({@link splitId} throws {@link ValidationError} otherwise) — the
|
|
@@ -1541,7 +1562,7 @@ declare function bulkLoadCrbmGeneration(driver: IColdDriver, key: GenKey, ids: I
|
|
|
1541
1562
|
keystore?: IKeystore;
|
|
1542
1563
|
requireEncryption?: boolean;
|
|
1543
1564
|
audit?: IAuditSink;
|
|
1544
|
-
/** Bitmap codec
|
|
1565
|
+
/** Bitmap codec. Optional in the type; a **flavor** package binds it ({@link requireCodec}). */
|
|
1545
1566
|
codec?: CodecInterface;
|
|
1546
1567
|
}): Promise<BulkLoadResult>;
|
|
1547
1568
|
|
|
@@ -1696,7 +1717,7 @@ declare class InProcessKeystore implements IKeystore {
|
|
|
1696
1717
|
}
|
|
1697
1718
|
|
|
1698
1719
|
/**
|
|
1699
|
-
* Crypto-shred erasure (Phase 4e
|
|
1720
|
+
* Crypto-shred erasure (Phase 4e).
|
|
1700
1721
|
*
|
|
1701
1722
|
* GDPR "right to erasure" on immutable/backed-up Cold storage: you can't delete a `.crbm` object from every
|
|
1702
1723
|
* backup, but you can **delete its key**. `destroySegment` drops the segment's wrapped DEK(s) from the registry
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mapWithConcurrency } from './chunk-SNJVZ227.js';
|
|
2
2
|
export { mapWithConcurrency } from './chunk-SNJVZ227.js';
|
|
3
|
-
import { validateNewRegistryRecord, recordFromNew, validateRegistryPatch, applyRegistryPatch, registryCounterOf, parseRegistryEnvelope, serializeRegistryEnvelope } from './chunk-
|
|
4
|
-
import { NO_ROW } from './chunk-
|
|
5
|
-
export { NO_ROW } from './chunk-
|
|
3
|
+
import { validateNewRegistryRecord, recordFromNew, validateRegistryPatch, applyRegistryPatch, registryCounterOf, parseRegistryEnvelope, serializeRegistryEnvelope } from './chunk-L54FL5DW.js';
|
|
4
|
+
import { NO_ROW } from './chunk-YEHMG6W2.js';
|
|
5
|
+
export { NO_ROW } from './chunk-YEHMG6W2.js';
|
|
6
6
|
import { ValidationError, BudgetExceededError, isTransientError, isWriteConflictError, WriteConflictError, IntegrityError, UnsupportedError, CapabilityError, KeyUnavailableError, validateChunkRef, validateSegmentRef, isNotFoundError, NotFoundError, TransientError, namespacePart } from './chunk-NUIDEEFZ.js';
|
|
7
7
|
export { BudgetExceededError, CapabilityError, CloudRoaringError, IntegrityError, KeyUnavailableError, NotFoundError, TimeoutError, TransientError, UnsupportedError, ValidationError, WriteConflictError, isCloudRoaringError, isIntegrityError, isNotFoundError, isTransientError, isValidationError, isWriteConflictError, validateSegmentRef } from './chunk-NUIDEEFZ.js';
|
|
8
8
|
import { createHash, randomUUID, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
|
|
@@ -20,6 +20,7 @@ function splitId(id) {
|
|
|
20
20
|
}
|
|
21
21
|
return { chunkKey: id >>> 16, remainder: id & LOW_16 };
|
|
22
22
|
}
|
|
23
|
+
var MAX_REMAINDER = CHUNK_COUNT - 1;
|
|
23
24
|
function joinId(chunkKey, remainder) {
|
|
24
25
|
return ((chunkKey & LOW_16) << 16 >>> 0) + (remainder & LOW_16);
|
|
25
26
|
}
|
|
@@ -82,8 +83,18 @@ function decodeDelta(bytes, maxBitmapBytes, codec) {
|
|
|
82
83
|
}
|
|
83
84
|
const adds = codec.safeDeserialize(bytes.subarray(addsStart, addsEnd), maxBitmapBytes);
|
|
84
85
|
const removes = codec.safeDeserialize(bytes.subarray(addsEnd), maxBitmapBytes);
|
|
86
|
+
assertRemainderRange(adds, "adds");
|
|
87
|
+
assertRemainderRange(removes, "removes");
|
|
85
88
|
return { adds, removes };
|
|
86
89
|
}
|
|
90
|
+
function assertRemainderRange(bitmap, half) {
|
|
91
|
+
const max = bitmap.maximum?.();
|
|
92
|
+
if (max !== void 0 && max > MAX_REMAINDER) {
|
|
93
|
+
throw new IntegrityError(
|
|
94
|
+
`warm delta ${half} holds value ${max}, outside the 16-bit remainder range [0, ${MAX_REMAINDER}] \u2014 the stored row is corrupt or was not written by this codec`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
87
98
|
|
|
88
99
|
// src/core/budget.ts
|
|
89
100
|
var DEFAULT_BUDGET = { maxRequests: 1e6 };
|
|
@@ -611,6 +622,28 @@ var SegmentEngine = class {
|
|
|
611
622
|
throw new IntegrityError(`chunk key from a tier is out of range: ${k}`);
|
|
612
623
|
}
|
|
613
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* The other half of invariant 5, and the one that was missing: a chunk payload holds **remainders** — 16-bit
|
|
627
|
+
* offsets within one chunk — so every value must be `<= 0xffff`.
|
|
628
|
+
*
|
|
629
|
+
* Nothing upstream established that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes
|
|
630
|
+
* that were written — which anyone able to write the tier satisfies trivially. A value `>= 65536` then
|
|
631
|
+
* reaches `joinId`, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a
|
|
632
|
+
* different chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious
|
|
633
|
+
* `intersect` matches. Compaction is the only path that already failed loud (`CrbmWriter` rejects
|
|
634
|
+
* `cardinality > 65536`), which merely turns the same row into a permanently poison segment.
|
|
635
|
+
*
|
|
636
|
+
* Costs one `maximum()` per chunk, not per id — `maximum` is optional on the codec seam precisely so a codec
|
|
637
|
+
* that cannot answer in O(1) opts out instead of making the read path walk every value.
|
|
638
|
+
*/
|
|
639
|
+
assertChunkPayloadInRange(bitmap, chunkKey) {
|
|
640
|
+
const max = bitmap.maximum?.();
|
|
641
|
+
if (max !== void 0 && max > MAX_REMAINDER) {
|
|
642
|
+
throw new IntegrityError(
|
|
643
|
+
`chunk ${chunkKey} payload holds value ${max}, outside the 16-bit remainder range [0, ${MAX_REMAINDER}] \u2014 the stored object is corrupt or was not written by this codec`
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
614
647
|
async effectiveChunk(seg, chunkKey, warmRows, gen) {
|
|
615
648
|
const warmBytes = warmRows.get(chunkKey);
|
|
616
649
|
const delta = warmBytes ? decodeDelta(warmBytes, this.maxBitmapBytes, this.codec) : emptyDelta(this.codec);
|
|
@@ -655,6 +688,7 @@ var SegmentEngine = class {
|
|
|
655
688
|
}
|
|
656
689
|
if (!bytes) return null;
|
|
657
690
|
const bitmap = this.codec.safeDeserialize(bytes, this.maxBitmapBytes);
|
|
691
|
+
this.assertChunkPayloadInRange(bitmap, ref.chunkKey);
|
|
658
692
|
this.cache?.set(cacheKey, bitmap);
|
|
659
693
|
return bitmap;
|
|
660
694
|
}
|