@cloudbitmaps/roaring 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23,8 +23,6 @@ import {
23
23
  excludingReservedRows,
24
24
  dropSegment,
25
25
  eraseIdFromSegment,
26
- estimateCost,
27
- groundedReport,
28
26
  judgeLoad,
29
27
  loadSegment,
30
28
  loadSegmentChunks,
@@ -45,7 +43,7 @@ import {
45
43
  splitId,
46
44
  takeLease
47
45
  } from "@cloudbitmaps/core";
48
- import { validateSegmentRef } from "@cloudbitmaps/core/driver-kit";
46
+ import { pointerIdOf, validateSegmentRef } from "@cloudbitmaps/core/driver-kit";
49
47
 
50
48
  // src/open-charging-storage.ts
51
49
  var OpenChargingStorage = class {
@@ -78,8 +76,9 @@ var OpenChargingStorage = class {
78
76
  if (!this.free.has(key.generation)) this.charge();
79
77
  return this.inner.getTail(key, maxBytes);
80
78
  }
81
- delete(key) {
82
- return this.inner.delete(key);
79
+ /** Handed through whole: the erasure's delete of a holder is conditioned on the object it searched. */
80
+ delete(key, options) {
81
+ return this.inner.delete(key, options);
83
82
  }
84
83
  list(ref) {
85
84
  return this.inner.list(ref);
@@ -648,10 +647,7 @@ import {
648
647
  BufferReader,
649
648
  CountingMetricsSink,
650
649
  RecordingAuditSink,
651
- DEFAULT_RETRY_POLICY as DEFAULT_RETRY_POLICY2,
652
- AWS_US_EAST_1_ONDEMAND,
653
- ELASTICACHE_REDIS_US_EAST_1_ONDEMAND,
654
- ONE_REDIS_HA_CLUSTER
650
+ DEFAULT_RETRY_POLICY as DEFAULT_RETRY_POLICY2
655
651
  } from "@cloudbitmaps/core";
656
652
  var SystemRng = class {
657
653
  /** A float in `[0, 1)`. Jitter only — never key material, never anything a caller can observe. */
@@ -661,6 +657,11 @@ var SystemRng = class {
661
657
  };
662
658
  var DEFAULT_CACHE_MAX_CHUNKS = 1024;
663
659
  var DEFAULT_ADMIN_CONCURRENCY = 8;
660
+ function rowVersionOfLive(version) {
661
+ if (version === null) return null;
662
+ const cut = version.lastIndexOf("#");
663
+ return cut < 0 ? version : version.slice(0, cut);
664
+ }
664
665
  function validateConcurrency(concurrency) {
665
666
  if (concurrency !== void 0 && (!Number.isInteger(concurrency) || concurrency < 1)) {
666
667
  throw new ValidationError2(`concurrency must be a positive integer; got ${concurrency}`);
@@ -768,23 +769,7 @@ var CALL_KEYS = {
768
769
  "concurrency",
769
770
  "summaries"
770
771
  ]),
771
- exportSegments: keysOf()(["format", "codec", "namespace", "ndjsonBatchBytes"]),
772
- costReport: keysOf()(["pricing", "workload"]),
773
- workload: keysOf()([
774
- "readsPerSec",
775
- "intersectsPerSec",
776
- "cacheHitRate",
777
- "chunksPerIntersect",
778
- "operandsPerIntersect",
779
- "loadsPerMonth",
780
- "requestsPerLoad",
781
- "hotSegments",
782
- "readerProcesses",
783
- "genTtlMs",
784
- "retirementsPerMonth",
785
- "purgesPerMonth",
786
- "conditionalDelete"
787
- ])
772
+ exportSegments: keysOf()(["format", "codec", "namespace", "ndjsonBatchBytes"])
788
773
  };
789
774
  var kindOf = (v) => v === null ? "null" : Array.isArray(v) ? "an array" : `a ${typeof v}`;
790
775
  function optionsError(options, op, known, booleans = []) {
@@ -1136,22 +1121,24 @@ var CloudRoaring = class _CloudRoaring {
1136
1121
  }
1137
1122
  /**
1138
1123
  * Get a handle to a segment. Validates the name (non-empty, well-formed, within the encoded-length cap). The options
1139
- * are `{ namespace }` and nothing else: anything else is refused with {@link ValidationError}, by name, since a
1140
- * misspelt `namespace` would otherwise address the default namespace. An `expiresAt` among them is refused with its own
1141
- * message: a handle carries no deadline, and one left unread would serve the data past it. A key whose value is
1142
- * `undefined` is read as absent, so a spread of options keeps working.
1124
+ * are a plain object holding `{ namespace }` and nothing else: any other own key, enumerable or not, is refused with
1125
+ * {@link ValidationError}, by name, since a misspelt `namespace` would otherwise address the default namespace, and a
1126
+ * deadline such as `expiresAt` would be left unread. A class instance, or an object built on another, is refused too,
1127
+ * since it can carry an option no scan of its own keys sees. A key whose value is `undefined` is read as absent, so a
1128
+ * spread of options keeps working.
1143
1129
  */
1144
1130
  segment(name, options) {
1145
1131
  if (options !== void 0 && options !== null) {
1146
1132
  if (typeof options !== "object" || Array.isArray(options)) {
1147
1133
  throw new ValidationError2("segment: options must be an object such as { namespace }");
1148
1134
  }
1149
- if (options.expiresAt !== void 0) {
1135
+ const proto = Object.getPrototypeOf(options);
1136
+ if (proto !== null && Object.getPrototypeOf(proto) !== null) {
1150
1137
  throw new ValidationError2(
1151
- "segment: `expiresAt` is not an option of a handle; check a deadline where you read, or record it with `store.setRetention(ref, { expiresAt })` and run `store.retireExpired()`"
1138
+ "segment: options must be a plain object such as { namespace }, not a class instance or an object built on another"
1152
1139
  );
1153
1140
  }
1154
- const unknown = Object.keys(options).filter(
1141
+ const unknown = Object.getOwnPropertyNames(options).filter(
1155
1142
  (k) => k !== "namespace" && options[k] !== void 0
1156
1143
  );
1157
1144
  if (unknown.length > 0) {
@@ -1176,23 +1163,29 @@ var CloudRoaring = class _CloudRoaring {
1176
1163
  /**
1177
1164
  * Write `ids` as a **new generation of `dest`** and publish it — the shared body of the `*Into` verbs. An `*Into`
1178
1165
  * materialisation is a load, and publishes the same way (hard invariant 1): every load that finds a row fences its
1179
- * publish on the row's token; a guarded load (the default, since the empty refusal needs the size of the current generation)
1180
- * also fences on the pointer it judged (`expectFrom`), and one that found no row fences on that absence instead.
1181
- * Only an unguarded load (`allowEmpty: true`, with neither `guard.minRetained` nor `guard.maxGrowth`) onto a segment with no row publishes bare
1182
- * forward-only. The destination's previous generation stays readable until the publish lands (readers re-resolve
1166
+ * publish on the row's token, and every load that finds none on that absence, guarded or not; a guarded load (the
1167
+ * default, since the empty refusal needs the size of the current generation) also fences on the pointer it judged
1168
+ * (`expectFrom`). The destination's previous generation stays readable until the publish lands (readers re-resolve
1183
1169
  * within `cache.genTtlMs`).
1184
1170
  *
1185
1171
  * This routes through `loadSegment` rather than writing the generation itself, and that is the whole point
1186
1172
  * of it. A materialisation is a load whose ids happen to come from a combine instead of from upstream, so
1187
1173
  * everything `load()` learned the hard way applies unchanged: the generation is written UNPUBLISHED, the
1188
1174
  * guard runs while the old generation is still authoritative, the publish is fenced as above, and a refused
1189
- * object is reclaimed only when a re-read finds the row unchanged (the same token) or gone (hard invariant 1:
1190
- * deleting it after a purge-and-recreate would put a live row over a missing generation).
1191
- *
1192
- * That last check narrows the window rather than closing it: the row read and the delete are two round
1193
- * trips, and `IStorageDriver` has no conditional delete to make them one. the collection a load runs carries
1194
- * the same residual. The failure it leaves is an orphan object, which costs storage until
1195
- * something collects it — deliberately the cheaper side of the trade.
1175
+ * object is reclaimed only when a re-read finds the row unchanged (the same token, or one that differs only in
1176
+ * its leases), `destroyed`, or gone, or finds key material on it when the load wrote cleartext; under any other
1177
+ * row it is kept (hard invariant 1: deleting it after a purge-and-recreate would put a live row over a missing
1178
+ * generation).
1179
+ *
1180
+ * Where the row is gone, or keyed over a cleartext write, the object is proved the load's own by its footer, and
1181
+ * the delete passes the version that read reported, so on a storage driver that reports `conditionalDelete` an
1182
+ * object put under the number since is kept. Where the row is unchanged or `destroyed`, the check narrows the
1183
+ * window rather than closing it: the row read and the delete are two round trips, and the delete is by number,
1184
+ * since the write reports no version of the object it made. The other deletes a load leads to are by number too: its
1185
+ * collection deletes what a listing, or the row's list of kept generations, names below the pointer, and a drop's
1186
+ * sweep and a tombstoned segment's collection delete what a listing names under a `destroyed` row. The failure the
1187
+ * checks leave when they refuse is an orphan object, which costs storage until something collects it —
1188
+ * deliberately the cheaper side of the trade.
1196
1189
  *
1197
1190
  * Written and published in one step, with no guard, an empty combine — a typo'd operand, an `exclude` that
1198
1191
  * swallowed everything, an operand that had not loaded yet — would silently replace `dest` with an empty
@@ -1206,9 +1199,10 @@ var CloudRoaring = class _CloudRoaring {
1206
1199
  * **A `WriteConflictError` does not by itself mean nothing was published**, and that is worth knowing
1207
1200
  * before you write the retry. `'superseded'` covers five different causes — the write-once PUT collided,
1208
1201
  * the pointer moved, a row appeared where the load found none, the row's token changed, the row was purged —
1209
- * and only the first three are the "somebody beat us" the name suggests. A token can also change on a write
1210
- * that is not a supersession at all, such as a `setRetention` on the destination. On top of that, the collection pass that runs AFTER a
1211
- * successful publish can raise the same error. So: treat it as "re-read the destination and decide",
1202
+ * and only the first two are always the "somebody beat us" the name suggests. A row can appear, and a token can
1203
+ * change, on a write that is not a supersession at all: a `setRetention` on the destination creates its row when it
1204
+ * has none, and rewrites it when it has one. On top of that, the collection pass that runs AFTER a successful
1205
+ * publish can raise the same error. So: treat it as "re-read the destination and decide",
1212
1206
  * never as "the write did not happen".
1213
1207
  *
1214
1208
  * **And by default it collects nothing**, unlike `load()`. See the `keep` default below.
@@ -1240,7 +1234,7 @@ var CloudRoaring = class _CloudRoaring {
1240
1234
  if (reason === "superseded") {
1241
1235
  const wrote = result.size > 0 ? `generation ${result.generation} was written and is not current` : `nothing was written \u2014 another writer took generation ${result.generation} first`;
1242
1236
  throw new WriteConflictError(
1243
- `${op}: the destination "${dest.segment}" changed while this materialisation was in flight, so its result is not the destination's current generation: ${wrote}. The pointer may have moved, the row may have been rewritten (a retention policy does this), dropped or purged. Re-read the destination and re-run.`
1237
+ `${op}: the destination "${dest.segment}" changed while this materialisation was in flight, so its result is not the destination's current generation: ${wrote}. The pointer may have moved, the row may have been created or rewritten (a retention policy does either), dropped or purged. Re-read the destination and re-run.`
1244
1238
  );
1245
1239
  }
1246
1240
  return {
@@ -1556,7 +1550,7 @@ var CloudRoaring = class _CloudRoaring {
1556
1550
  }
1557
1551
  }
1558
1552
  const row = await this.withRetries(() => registry.get(ref));
1559
- return row === null ? null : { generation: row.currentGen, token: row.token };
1553
+ return row === null ? null : { generation: row.currentGen, token: pointerIdOf(row) };
1560
1554
  }
1561
1555
  /** Throw what a read of, or a publish to, `handle` must throw now: its lease error, if it has one. */
1562
1556
  assertLease(handle) {
@@ -1601,8 +1595,8 @@ var CloudRoaring = class _CloudRoaring {
1601
1595
  const ref = { segment: rec.segment, namespace: rec.namespace };
1602
1596
  if (this.crbmSource !== void 0) {
1603
1597
  const held = await this.crbmSource.currentVersion(ref);
1604
- const listed = rec.currentGen === null ? null : `${rec.currentGen}:${String(rec.token)}`;
1605
- if (held !== listed) this.engine.invalidate(ref);
1598
+ const listed = rec.currentGen === null ? null : `${rec.currentGen}:${pointerIdOf(rec)}`;
1599
+ if (rowVersionOfLive(held) !== listed) this.engine.invalidate(ref);
1606
1600
  }
1607
1601
  return await this.engine.has(ref, id) ? { segment: rec.segment, namespace: rec.namespace } : null;
1608
1602
  }
@@ -1621,10 +1615,14 @@ var CloudRoaring = class _CloudRoaring {
1621
1615
  * can still hold it, and so can one above the pointer after a {@link CloudRoaring.rollback}, which the rollback
1622
1616
  * could make current again. Each holder is deleted — below the pointer by a `keep: 0` collection, above it one
1623
1617
  * by one, re-proved against the row first — and the generations above the pointer that never held the id stay
1624
- * as rollback targets. An entry says `erased: true` only once the call has listed the bucket and read what is
1625
- * left: **no generation of the segment holds the id**. The returned per-segment record is your **erasure ledger** —
1626
- * persist it / route it to your audit sink as the proof of deletion (a `segment.rewrite` audit event is also
1627
- * emitted per rewrite when you pass `audit`).
1618
+ * as rollback targets, but for any object no read of the segment can open, which goes whatever the id. An entry
1619
+ * says `erased: true` only once the call has listed the bucket and read what is left: **no generation of the
1620
+ * segment holds the id**. The returned per-segment record is your **erasure ledger** —
1621
+ * persist it / route it to your audit sink as the proof of deletion (when you pass `audit`, an audit event is also
1622
+ * emitted per segment erased: `segment.rewrite` for a rewrite, `segment.collect` where only other generations held
1623
+ * the id and nothing was rewritten). A segment where the erasure deleted only objects no read of it can open (a first
1624
+ * load's sealed under a key no row holds) found the id in none, so the ledger does not list it; the audit sink gets
1625
+ * `segment.collect` for it with no `fromGeneration`, which is the only record of that deletion.
1628
1626
  *
1629
1627
  * Uses the backend's **own** two halves, so the membership check and the rewrite provably run
1630
1628
  * over the same generation. Requires the store built with a **backend** (throws
@@ -1646,13 +1644,21 @@ var CloudRoaring = class _CloudRoaring {
1646
1644
  * an error, read off the row: a moved pointer is a `'superseded'` entry, which a re-run settles, and a segment
1647
1645
  * that a concurrent `dropSegment` tombstoned or a retention sweep purged is left out of the ledger. A tombstoned
1648
1646
  * segment is still searched: a cleartext object left under it that holds the id is deleted, with everything under
1649
- * the tombstone, and the entry reads `erased: true`.
1647
+ * the tombstone, and the entry reads `erased: true`. So is a segment whose row names no generation yet (a retention
1648
+ * policy set before its first load): a first load's object that holds the id is deleted, once the row's `pointerId`
1649
+ * is renewed so that the load, if still running, is refused at its publish, and the entry reads `erased: true`. An
1650
+ * encrypted first load's object there cannot be searched, so it is deleted whatever the id: on an encrypted store,
1651
+ * an erasure of any id refuses an encrypted first load in flight that has written its object onto a segment made
1652
+ * ahead of its data. Each such delete, and each of a holder above the pointer, names the object the erasure read:
1653
+ * on a storage driver that reports `conditionalDelete`, another erasure of the id that deletes it first, followed by
1654
+ * a load that takes the number freed and publishes, does not lose that load's generation to this erasure's delete,
1655
+ * which is refused, and the entry says what the row says; on one that does not, it can.
1650
1656
  *
1651
1657
  * **Read `note` on any `erased: false` entry — the two reasons mean different things.** `'superseded'` means
1652
- * another writer (a load, another erasure, or a rollback) moved the pointer mid-call, so **this call** did not
1653
- * erase the id. Re-run: it erases the id if it is still there, and lists nothing for the segment if a racing
1654
- * erasure of the same id already removed it. Do not read `'superseded'` as "the id is still present" —
1655
- * read it as "not done by this call, and the re-run settles it".
1658
+ * another writer (a load, another erasure, or a rollback) moved the pointer, or replaced an object the call meant to
1659
+ * delete, mid-call, so **this call** did not erase the id. Re-run: it erases the id if it is still there, and lists
1660
+ * nothing for the segment if a racing erasure of the same id already removed it. Do not read `'superseded'` as
1661
+ * "the id is still present" — read it as "not done by this call, and the re-run settles it".
1656
1662
  * `` `error: …` `` is a per-segment fault (caught so one segment can't discard the whole ledger) and it can land
1657
1663
  * on either side of the publish: if the rewrite had not published, the id is still there and a re-run erases
1658
1664
  * it; if the publish succeeded and only the **collection** of the old generation failed, the id is already
@@ -1847,8 +1853,9 @@ var CloudRoaring = class _CloudRoaring {
1847
1853
  * and are then *above* `currentGen`, where collection never looks. They remain until loads pass them (the first
1848
1854
  * load whose number one of them holds numbers above them all, and collection then keeps the newest `keep` of what is
1849
1855
  * below its pointer), {@link CloudRoaring.dropSegment}
1850
- * deletes them, or {@link CloudRoaring.eraseSubject} does: all of those present when it rewrites, and only those holding
1851
- * the id when the current generation does not. An operator who has just undone a bad load should not have the
1856
+ * deletes them, or {@link CloudRoaring.eraseSubject} does: all of those present when it rewrites, and, when the
1857
+ * current generation does not hold the id, only those holding it and any no read of the segment can open, whatever
1858
+ * the id. An operator who has just undone a bad load should not have the
1852
1859
  * evidence collected out from under them, while a rollback target that still holds erased data would make the
1853
1860
  * erasure undoable.
1854
1861
  *
@@ -1917,10 +1924,12 @@ var CloudRoaring = class _CloudRoaring {
1917
1924
  * published, a retention change, a rollback or an erasure wrote the row, or the row was deleted.
1918
1925
  *
1919
1926
  * A refused load deletes the object it wrote before returning — it sits above `currentGen`, where generation
1920
- * collection deliberately never looks — but only while the segment's registry row is unchanged or gone. Once
1921
- * another write has changed the row, the generation number it holds may name another incarnation's live object,
1922
- * so it leaves the orphan rather than risk deleting live data. No row's list names it, so it takes no place in a
1923
- * window, and a listing deletes it once a later generation is current above it.
1927
+ * collection deliberately never looks — but only while the segment's registry row is unchanged (or differs only
1928
+ * in its leases), `destroyed` or gone, or has key material when the load wrote cleartext, which has no place in an
1929
+ * encrypted segment's bucket. Under a row that is gone or keyed, a read of the object's footer must prove it the
1930
+ * load's own first. Once another write has otherwise changed the row, the generation number it holds may name
1931
+ * another incarnation's live object, so it leaves the orphan rather than risk deleting live data. No row's list
1932
+ * names it, so it takes no place in a window, and a listing deletes it once a later generation is current above it.
1924
1933
  *
1925
1934
  * **Collection is by name at any `keep` up to 64.** The segment's row records the generations a load keeps, so a load
1926
1935
  * that found nothing above the pointer deletes the generations its publish pushed out of the window and lists
@@ -2133,8 +2142,8 @@ var CloudRoaring = class _CloudRoaring {
2133
2142
  * Pass `purgeTombstones: false` to keep every tombstone, that row included. On a backend whose registry reports
2134
2143
  * `conditionalDelete` (AWS S3, Azure Blob, the local filesystem and memory, by default; GCS when you set `conditionalDelete: true`)
2135
2144
  * the purge removes the row from the bucket for good, by a delete the store applies only to the version it judged,
2136
- * so a full sweep reads what is live or inside its grace rather than every name a namespace ever held; elsewhere,
2137
- * and for a row a release before 0.12 wrote, it leaves a tombstone. Each retirement files a pointer in the due index
2145
+ * so a full sweep reads what is live or inside its grace rather than every name a namespace ever held; elsewhere it
2146
+ * leaves a tombstone. Each retirement files a pointer in the due index
2138
2147
  * under the day its tombstone's grace ends, so `scan: 'index'` purges as well as retires.
2139
2148
  *
2140
2149
  * Needs the store built with a **backend** (throws {@link UnsupportedError} otherwise),
@@ -2358,7 +2367,8 @@ var CloudRoaring = class _CloudRoaring {
2358
2367
  * A segment whose pointer names a missing object is the torn restore this reports; a cold `count()` of it still
2359
2368
  * answers the number its row records, while a read of the object throws, so the count alone never shows it. With
2360
2369
  * `summaries: true` it also opens each segment's current object (one tail read each) and reports a segment whose
2361
- * row's summary says another id count or metadata than the object holds as `summary-mismatch`, which is what a
2370
+ * row's summary names another object by its fingerprint, or says another id count or metadata than the object holds,
2371
+ * as `summary-mismatch`, which is what a
2362
2372
  * restore of the registry from another point than the bucket leaves a count to answer. A sealed summary is held
2363
2373
  * against its object when this store has the key, and counted in `summariesUnchecked` when it does not.
2364
2374
  *
@@ -2394,15 +2404,6 @@ var CloudRoaring = class _CloudRoaring {
2394
2404
  const registry = this.requireRegistry("exportSegments");
2395
2405
  return runExport(this, registry, sink, { ...opts, codec: opts.codec ?? roaringCodec });
2396
2406
  }
2397
- /**
2398
- * Planning cost estimate — pure, no instance/data needed: sizing, sales, what-if. For a real, grounded report
2399
- * from live segment sizes, use `store.segment(name).costReport()`. See {@link CostReport}.
2400
- * @deprecated Moves to `@cloudbitmaps/tools`, a package of its own, with a `size` on `stat()` so a grounded report
2401
- * needs nothing internal. It is a planning tool, and its price list is as old as the release that ships it.
2402
- */
2403
- static estimateCost(input) {
2404
- return estimateCost(input);
2405
- }
2406
2407
  };
2407
2408
  var withBatches = (gen, batches) => Object.assign(gen, { batches });
2408
2409
  var failing = (err) => {
@@ -2799,8 +2800,8 @@ var Segment = class _Segment {
2799
2800
  * Cardinality of the generation this handle reads: **one registry read when cold, none when warm, and no read of the
2800
2801
  * object**, with **zero payload reads**. The registry row records the id count of the generation it names, written
2801
2802
  * by the write that made it current, and a count answers from that. A row with no summary it can use (one written
2802
- * before rows carried it, one that names another generation, a sealed one that does not open) sends the count to the
2803
- * `.crbm` index, summed with a tail read of the object. A segment whose pointer names a missing object (a torn
2803
+ * without it, as a registry of your own may, one that names another generation, a sealed one that does not open)
2804
+ * sends the count to the `.crbm` index, summed with a tail read of the object. A segment whose pointer names a missing object (a torn
2804
2805
  * restore) still counts the row's number, while a read of the object throws; `checkConsistency` is what finds it.
2805
2806
  *
2806
2807
  * What this trusts: the row's summary, or the index's sum, and no payload is decoded to confirm it. The summary is
@@ -2819,17 +2820,30 @@ var Segment = class _Segment {
2819
2820
  return this.timed("count", () => this.engine.count(this.ref));
2820
2821
  }
2821
2822
  /**
2822
- * What the generation this handle reads is, from one resolution: its number, its id count and the metadata it
2823
- * was loaded with (absent when it has none). It is what answers {@link Segment.count}, so the three describe one
2824
- * generation and cannot straddle a publish. One registry read when cold, none while warm, and none on a pinned
2825
- * handle, which answers for the generation it pinned. A segment with no generation answers
2826
- * `{ generation: null, cardinality: 0 }`.
2827
- *
2828
- * Trust is as for `count()`: the registry row's word, not confirmed against the object until the object is
2829
- * opened, when a disagreement makes this process stop using that row's summary.
2823
+ * What the generation this handle reads is, from one resolution: its number, its id count, the metadata it was
2824
+ * loaded with (absent when it has none), and `sizeBytes`, its object's bytes in storage. All four come from the
2825
+ * registry row when it has a summary this store can use, as `count()`'s do: the summary records the object's
2826
+ * fingerprint, its size with its checksum. That is **one registry read when cold, none when warm, and no read of the
2827
+ * object**. With no summary it can use, they come from the generation's object, opened once: its footer and index,
2828
+ * with no payload read, which is a tail read of the object more when cold (and a range read for an index longer than
2829
+ * the tail) and keeps the generation in the reader cache as a read does. On a pinned handle it answers for the
2830
+ * generation it pinned, from the pinned object. A segment with no generation answers
2831
+ * `{ generation: null, cardinality: 0, sizeBytes: null }`, and a store whose source cannot report a size answers
2832
+ * `sizeBytes: null`. A pointer that names a missing object (a torn restore) still answers from the row's summary, as
2833
+ * `count()` does, while a read of the object throws `NotFoundError`; with no summary to use, `stat()` throws it too.
2834
+ * `checkConsistency` is what finds such a row.
2835
+ *
2836
+ * Trust is as for `count()`: what the row's summary says is believed until the object is next opened. Every open of
2837
+ * the generation holds the object to the fingerprint the summary records, so another object under the number is
2838
+ * refused when it is opened, and holds its count against the summary's; a disagreement in count makes this process
2839
+ * stop using that summary, so `stat()` then answers from the object, whose index is checked for internal consistency
2840
+ * and whose count is the index's sum. A reader already open is not checked again until the row changes, it is
2841
+ * evicted or it is invalidated.
2842
+ *
2843
+ * `sizeBytes` is what `groundedReport` in `@cloudbitmaps/tools` prices storage from.
2830
2844
  *
2831
2845
  * ```ts
2832
- * const { generation, cardinality, metadata } = await store.segment('active-30d').stat();
2846
+ * const { generation, cardinality, metadata, sizeBytes } = await store.segment('active-30d').stat();
2833
2847
  * ```
2834
2848
  */
2835
2849
  async stat() {
@@ -3119,38 +3133,8 @@ var Segment = class _Segment {
3119
3133
  )
3120
3134
  );
3121
3135
  }
3122
- /**
3123
- * Grounded cost report for this segment: storage cost from its **real** `.crbm` size (exact, no payload
3124
- * reads); request cost from the supplied `workload` rates. A segment with no Storage generation reports zero
3125
- * storage. The pointer refresh is priced at the store's own `cache.genTtlMs`, or at none when the store never
3126
- * refreshes, unless the workload sets `genTtlMs`. See {@link CostReport} — it always includes a verdict (incl.
3127
- * the lose-zone).
3128
- * @deprecated Moves to `@cloudbitmaps/tools`, a package of its own, with a `size` on `stat()` so a grounded report
3129
- * needs nothing internal. It is a planning tool, and its price list is as old as the release that ships it.
3130
- */
3131
- async costReport(options) {
3132
- checkOptions(options, "costReport", CALL_KEYS.costReport);
3133
- const shape = options?.workload;
3134
- if (shape !== void 0 && shape !== null && (typeof shape !== "object" || Array.isArray(shape))) {
3135
- throw new ValidationError2("costReport: workload must be an object");
3136
- }
3137
- this.assertLeases([this]);
3138
- const canMeasure = this.engine.supportsStorageSize;
3139
- const size = canMeasure ? await this.engine.segmentSize(this.ref) : null;
3140
- const refreshMs = this.engine.pointerRefreshMs;
3141
- const given = options?.workload === void 0 || options.workload === null ? void 0 : picked(options.workload, CALL_KEYS.workload);
3142
- const workload = refreshMs === void 0 || given?.genTtlMs !== void 0 ? given : { ...given, genTtlMs: refreshMs };
3143
- return groundedReport({
3144
- storageBytes: size?.sizeBytes ?? 0,
3145
- grounded: canMeasure,
3146
- workload,
3147
- pricing: options?.pricing,
3148
- extraNotes: canMeasure ? void 0 : ["storage source has no sizeOf() \u2014 storage not measured, reported as $0."]
3149
- });
3150
- }
3151
3136
  };
3152
3137
  export {
3153
- AWS_US_EAST_1_ONDEMAND,
3154
3138
  BudgetExceededError,
3155
3139
  BufferReader,
3156
3140
  CapabilityError,
@@ -3160,7 +3144,6 @@ export {
3160
3144
  CrbmReader,
3161
3145
  CrbmStorageChunkSource2 as CrbmStorageChunkSource,
3162
3146
  DEFAULT_RETRY_POLICY2 as DEFAULT_RETRY_POLICY,
3163
- ELASTICACHE_REDIS_US_EAST_1_ONDEMAND,
3164
3147
  InProcessKeystore,
3165
3148
  IntegrityError3 as IntegrityError,
3166
3149
  KeyUnavailableError,
@@ -3174,7 +3157,6 @@ export {
3174
3157
  MemoryStorage,
3175
3158
  NodeAead,
3176
3159
  NotFoundError2 as NotFoundError,
3177
- ONE_REDIS_HA_CLUSTER,
3178
3160
  RecordingAuditSink,
3179
3161
  Segment,
3180
3162
  StaleOperandError,