@cloudbitmaps/core 0.17.0 → 0.18.1

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.
@@ -6,7 +6,7 @@ import type { Aead, CrbmCrypto, IKeystore, WrappedDek } from './crypto.js';
6
6
  import type { ChunkRef, ChunkRead, ReadChunksOptions, StorageChunkSource, GenerationMetadata, GenerationSummary, GenKey, IStorageDriver, IRegistryDriver, RegistryRecord, RegistrySummary, SegmentRef, SegmentSize, Token } from './ports.js';
7
7
  import { CrbmReader } from './crbm/reader.js';
8
8
  import type { CrbmReaderOptions } from './crbm/reader.js';
9
- import type { CodecBitmap, CodecInterface } from './codec.js';
9
+ import type { CodecBitmap, CodecInterface, EncodedChunk } from './codec.js';
10
10
  import { ChunkLoadInput, DecodedLoadInput } from './load-input.js';
11
11
  export interface CrbmStorageChunkSourceOptions extends CrbmReaderOptions {
12
12
  /**
@@ -445,6 +445,13 @@ export declare function writeCrbmGeneration(driver: IStorageDriver, key: GenKey,
445
445
  sha256: string;
446
446
  fingerprint: string;
447
447
  }>;
448
+ /**
449
+ * The chunks a load of ids, or of a decoded bitmap, writes: ascending by key, each non-empty and run-optimized. A decoded
450
+ * bitmap writes its own chunks, which never touches an id. Ids, and the bitmap of a codec that cannot encode its own
451
+ * chunks, are bucketed per chunk instead; both give the same bytes. Exported for a caller that holds the chunks itself
452
+ * instead of writing them.
453
+ */
454
+ export declare function encodedChunksOfInput(ids: Iterable<number> | AsyncIterable<number> | DecodedLoadInput, codec: CodecInterface, clock: Clock | undefined): Promise<Iterable<EncodedChunk>>;
448
455
  /**
449
456
  * Whether the object under `key` is provably the one `fingerprint` names ({@link CrbmReader.fingerprint}), from one
450
457
  * read of its footer. False when it is another object, when it is gone, and when the read fails in any way: a caller
@@ -312,32 +312,8 @@ export declare class SegmentEngine {
312
312
  private streamedVersion;
313
313
  /** The cache key of a chunk: by the version it was read under, or by segment and key alone for a source with none. */
314
314
  private chunkCacheKey;
315
- /** The segment's chunk keys, ascending — a shape read off the index, no payload. Keys are untrusted (invariant 5). */
315
+ /** The segment's chunk keys, ascending, checked as untrusted tier data. */
316
316
  private chunkKeys;
317
- /**
318
- * Tier-derived keys are untrusted (invariant 5) — fail fast on a corrupt/out-of-range key rather than
319
- * letting it flow into the id-routing step and produce a bogus id.
320
- */
321
- private assertChunkKeyInRange;
322
- /**
323
- * The other half of invariant 5: a chunk payload holds **remainders** — 16-bit offsets within one chunk — so
324
- * every value must be `<= 0xffff`.
325
- *
326
- * Nothing upstream establishes that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes
327
- * that were written — which anyone able to write the bucket satisfies trivially. A value `>= 65536` would then
328
- * reach the id-routing step, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a different
329
- * chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious `intersect`
330
- * matches.
331
- *
332
- * Costs one `maximum()` per chunk, not per id — `maximum` is optional on the codec seam precisely so a codec
333
- * that cannot answer in O(1) opts out instead of making the read path walk every value.
334
- *
335
- * One value stands for all of them only because the decode is structurally checked. Roaring answers `maximum()`
336
- * from its last container, so a payload listing its containers out of order would report the wrong one's
337
- * largest value and pass here while holding values above 65,535. The codec's `safeDeserialize` refuses that
338
- * payload, and every other shape that would make this answer wrong, before it reaches this check.
339
- */
340
- private assertChunkPayloadInRange;
341
317
  /**
342
318
  * Refuse a combine whose operand names a segment that was never created.
343
319
  *
@@ -402,11 +378,6 @@ export declare class SegmentEngine {
402
378
  * one): callers read it or clone it, never mutate it.
403
379
  */
404
380
  private storageChunk;
405
- /**
406
- * A chunk's stored bytes decoded under the size cap (invariant 5) and range-checked: the one place a chunk becomes a
407
- * bitmap, whether its bytes came from a request of its own or from a stream of coalesced ranges.
408
- */
409
- private decodeChunk;
410
381
  /**
411
382
  * One chunk, decoded, range-checked and cached. A source with `getChunks` is read through it, as a one-key stream, so
412
383
  * a `storage.get` is reported only for a request that was sent (a chunk the source holds in memory sends none);
@@ -61,6 +61,21 @@ export declare class LeaseExpiredError extends CloudRoaringError {
61
61
  */
62
62
  export declare class LeaseLimitError extends CloudRoaringError {
63
63
  }
64
+ /**
65
+ * An operand a call relied on changed while the call ran, so what the call built from it is not published. Carries the
66
+ * operand's name in the call and why it is stale (`'moved'`: it was pinned at a generation and its pointer has since
67
+ * moved; `'erased'`: an erasure ran in the store after a call with a feed began, or after a held operand the call reads
68
+ * was made, so what the feed gave it, or what the operand holds, may hold an erased id), under the stable `code`
69
+ * `'stale-operand'`. Deterministic: run the call again against the current operand.
70
+ */
71
+ export declare class StaleOperandError extends CloudRoaringError {
72
+ readonly code: "stale-operand";
73
+ /** The operand's name in the call that found it stale. */
74
+ readonly operand: string;
75
+ /** Why it is stale. */
76
+ readonly reason: 'moved' | 'erased';
77
+ constructor(message: string, operand: string, reason: 'moved' | 'erased');
78
+ }
64
79
  /**
65
80
  * This build/configuration cannot perform the requested operation, though nothing is malformed. Two uses:
66
81
  * (1) **format** — the bytes are well-formed but unreadable here (an unknown `.crbm` major version) —
@@ -125,6 +140,8 @@ export declare function isWriteConflictError(err: unknown): err is WriteConflict
125
140
  export declare function isTransientError(err: unknown): err is TransientError;
126
141
  /** A read came after its pin's lease ended. */
127
142
  export declare function isLeaseExpiredError(err: unknown): err is LeaseExpiredError;
143
+ /** An operand a call relied on changed while it ran. */
144
+ export declare function isStaleOperandError(err: unknown): err is StaleOperandError;
128
145
  /** A segment has no room for another live lease. */
129
146
  export declare function isLeaseLimitError(err: unknown): err is LeaseLimitError;
130
147
  /** A requested object/row does not exist. */
@@ -57,11 +57,12 @@ export declare class ChunkLoadInput {
57
57
  * Check a load's input and decode a bitmap input, before the load makes any request.
58
58
  *
59
59
  * @returns ids unchanged, to be consumed lazily by the write, or the decoded bitmap.
60
+ * @param subject names what takes the input in a refusal's message.
60
61
  * @throws {ValidationError} for a byte array passed as ids; bytes that are malformed, over the cap, or followed by
61
62
  * more bytes; a `{ bitmap }` with no `serialize` method, or whose `serialize('portable')` returns no `Uint8Array`;
62
63
  * and anything that is none of the three inputs. An error the caller's own `serialize` throws propagates as it is.
63
64
  */
64
- export declare function prepareLoadInput(input: LoadInput, codec: CodecInterface): Iterable<number> | AsyncIterable<number> | DecodedLoadInput;
65
+ export declare function prepareLoadInput(input: LoadInput, codec: CodecInterface, subject?: string): Iterable<number> | AsyncIterable<number> | DecodedLoadInput;
65
66
  /**
66
67
  * Portable bytes a caller holds, checked and decoded by the codec's safe deserializer: the one check every bitmap
67
68
  * input of a load goes through, and what a flavor offers its users to decode bytes they hold themselves.
@@ -29,7 +29,7 @@ import {
29
29
  validateRegistryPatch,
30
30
  validateSegmentRef,
31
31
  webCryptoEntropy
32
- } from "./chunk-CV7GJO3B.js";
32
+ } from "./chunk-K4EXZDMU.js";
33
33
 
34
34
  // src/drivers/_shared/object-registry-keys.ts
35
35
  var REGISTRY_SUFFIX = ".reg";
package/dist/index.d.ts CHANGED
@@ -39,6 +39,10 @@ export type { LeaseDeps, LeaseTake, TakenLease } from './core/leases.js';
39
39
  export { PinnedStorageChunkSource } from './core/pinned-storage-source.js';
40
40
  export type { PinnedAt } from './core/pinned-storage-source.js';
41
41
  export { loadSegment, loadSegmentChunks } from './core/load.js';
42
+ export { compileCombineMany, rebindCombineMany, runCombineMany } from './core/combine-many.js';
43
+ export type { CombineExpr, CombineManyDeps, CombineManyFeed, CombineManyFeedRecord, CombineManyHeld, CombineManyOperand, CombineManyOperandStats, CombineManyOutcome, CombineManyOutput, CombineManyOutputStats, CombineManyRequest, CombineManyRun, CombineManyStats, CombineManyWrite, CompiledCombineMany, } from './core/combine-many.js';
44
+ export { prepareHeld } from './core/combine-held.js';
45
+ export type { HeldChunks } from './core/combine-held.js';
42
46
  export type { LoadDeps, LoadOptions, LoadGuard, LoadResult, LoadRefusal } from './core/load.js';
43
47
  export type { LoadInput, PortableBitmap } from './core/load-input.js';
44
48
  export { decodeSerialized } from './core/load-input.js';
@@ -49,7 +53,7 @@ export type { EraseIdDeps, EraseIdResult } from './core/erase-id.js';
49
53
  export type { CodecInterface, CodecBitmap, EncodedChunk } from './core/codec.js';
50
54
  export type { Clock, Entropy, Rng } from './core/determinism.js';
51
55
  export type { StorageChunkSource, IStorageDriver, StorageCaps, ChunkRef, ChunkRead, ReadChunksOptions, SegmentRef, GenKey, IRegistryDriver, StorageBackend, RegistryRecord, NewRegistryRecord, RegistryPatch, RegistryStatus, RegistrySummary, RegistryWriteOptions, LeaseEntry, ReapLegacyTombstonesOptions, ReapLegacyTombstonesResult, ClearRegistrySummary, SealedRegistrySummary, GenerationMetadata, GenerationSummary, RegCaps, GovernanceMeta, SegmentSize, } from './core/ports.js';
52
- export { CloudRoaringError, ValidationError, WriteConflictError, IntegrityError, NotFoundError, UnsupportedError, CapabilityError, TransientError, KeyUnavailableError, BudgetExceededError, LeaseExpiredError, LeaseLimitError, isCloudRoaringError, isWriteConflictError, isTransientError, isNotFoundError, isIntegrityError, isValidationError, isLeaseExpiredError, isLeaseLimitError, } from './core/errors.js';
56
+ export { CloudRoaringError, ValidationError, WriteConflictError, IntegrityError, NotFoundError, UnsupportedError, CapabilityError, TransientError, KeyUnavailableError, BudgetExceededError, LeaseExpiredError, LeaseLimitError, StaleOperandError, isCloudRoaringError, isWriteConflictError, isTransientError, isNotFoundError, isIntegrityError, isValidationError, isLeaseExpiredError, isLeaseLimitError, isStaleOperandError, } from './core/errors.js';
53
57
  export type { Aead, AeadSealed, IKeystore, WrappedDek, CrbmCrypto } from './core/crypto.js';
54
58
  export { aadFor } from './core/crypto.js';
55
59
  export { NodeAead, InProcessKeystore } from './drivers/crypto.js';