zonemapdb 0.8.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dist/block-fetch.d.ts +11 -0
  4. package/dist/block-fetch.d.ts.map +1 -0
  5. package/dist/block-fetch.js +29 -0
  6. package/dist/block-fetch.js.map +1 -0
  7. package/dist/client.d.ts +3 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +584 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/errors.d.ts +40 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +24 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/fetch-file.d.ts +39 -0
  16. package/dist/fetch-file.d.ts.map +1 -0
  17. package/dist/fetch-file.js +179 -0
  18. package/dist/fetch-file.js.map +1 -0
  19. package/dist/filter.d.ts +9 -0
  20. package/dist/filter.d.ts.map +1 -0
  21. package/dist/filter.js +104 -0
  22. package/dist/filter.js.map +1 -0
  23. package/dist/index-fetch.d.ts +3 -0
  24. package/dist/index-fetch.d.ts.map +1 -0
  25. package/dist/index-fetch.js +5 -0
  26. package/dist/index-fetch.js.map +1 -0
  27. package/dist/index.d.ts +6 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +5 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/manifest.d.ts +127 -0
  32. package/dist/manifest.d.ts.map +1 -0
  33. package/dist/manifest.js +86 -0
  34. package/dist/manifest.js.map +1 -0
  35. package/dist/normalize.d.ts +25 -0
  36. package/dist/normalize.d.ts.map +1 -0
  37. package/dist/normalize.js +43 -0
  38. package/dist/normalize.js.map +1 -0
  39. package/dist/secondary-index.d.ts +32 -0
  40. package/dist/secondary-index.d.ts.map +1 -0
  41. package/dist/secondary-index.js +80 -0
  42. package/dist/secondary-index.js.map +1 -0
  43. package/dist/types.d.ts +319 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +164 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/version.d.ts +9 -0
  48. package/dist/version.d.ts.map +1 -0
  49. package/dist/version.js +9 -0
  50. package/dist/version.js.map +1 -0
  51. package/dist/zonemap-fetch.d.ts +9 -0
  52. package/dist/zonemap-fetch.d.ts.map +1 -0
  53. package/dist/zonemap-fetch.js +11 -0
  54. package/dist/zonemap-fetch.js.map +1 -0
  55. package/dist/zonemap.d.ts +35 -0
  56. package/dist/zonemap.d.ts.map +1 -0
  57. package/dist/zonemap.js +139 -0
  58. package/dist/zonemap.js.map +1 -0
  59. package/package.json +53 -0
package/dist/client.js ADDED
@@ -0,0 +1,584 @@
1
+ import { fetchIndexChunk } from "./index-fetch.js";
2
+ import { ZonemapDbError } from "./errors.js";
3
+ import { parseCorruptible } from "./fetch-file.js";
4
+ import { matchesWhere } from "./filter.js";
5
+ import { datasetCompression, fetchManifest, manifestReferences } from "./manifest.js";
6
+ import { chunksForFilter, decodeIndexChunk, reverseString, blockIndicesForFilter, trigramsOf, } from "./secondary-index.js";
7
+ import { fetchBlockRecords } from "./block-fetch.js";
8
+ import { assertWhereHasPruning, compactWhere, } from "./types.js";
9
+ import { candidateBlockIndices, pairCandidateBlockIndices, } from "./zonemap.js";
10
+ import { fetchZonemapSidecar } from "./zonemap-fetch.js";
11
+ /** Only equals/in/startsWith prune via the inverted index (ADR-0003 §7); other keys (e.g. `not`) don't. */
12
+ function secondaryFilterOf(rawFilter) {
13
+ const { equals, in: inValues, startsWith } = rawFilter;
14
+ if (equals === undefined && inValues === undefined && startsWith === undefined)
15
+ return undefined;
16
+ return { equals, in: inValues, startsWith: startsWith };
17
+ }
18
+ /**
19
+ * The part of a filter a per-block [min,max] pair can prune: point lookups plus ranges. Ranges are
20
+ * zonemap-only — the inverted index is a dictionary of exact values, and a range has no key to look
21
+ * up — so they are extracted separately from `secondaryFilterOf` rather than widening it.
22
+ */
23
+ function pairFilterOf(rawFilter) {
24
+ const { equals, in: inValues, gt, gte, lt, lte } = rawFilter;
25
+ if (equals === undefined && inValues === undefined && gt === undefined && gte === undefined && lt === undefined && lte === undefined) {
26
+ return undefined;
27
+ }
28
+ return { equals, in: inValues, gt, gte, lt, lte };
29
+ }
30
+ /**
31
+ * A multi-valued field's index is built over its elements, so pruning reads through `some`/`every`
32
+ * to their element filter (T7, ADR-0010): `"x"` unwraps to `{ equals: "x" }`, an object form is used
33
+ * as-is.
34
+ */
35
+ function unwrapElementFilter(elementFilter) {
36
+ if (typeof elementFilter === "object" && elementFilter !== null)
37
+ return elementFilter;
38
+ return { equals: elementFilter };
39
+ }
40
+ /** `a ∪ b` over block ordinals. */
41
+ function unionSets(a, b) {
42
+ return new Set([...a, ...b]);
43
+ }
44
+ /**
45
+ * `callerSignal` is the query's `signal` option: when it fires, the same controller that the first
46
+ * failure fires aborts every fetch still pending in this query.
47
+ */
48
+ function makeFetchContext(basePath, fetchImpl, callerSignal) {
49
+ const controller = new AbortController();
50
+ const onCallerAbort = () => controller.abort(callerSignal.reason);
51
+ // An abort event has already fired for a signal that is aborted by now, so the listener would never run.
52
+ if (callerSignal?.aborted)
53
+ onCallerAbort();
54
+ else
55
+ callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
56
+ const abortAndRethrow = (error) => {
57
+ controller.abort(error);
58
+ throw error;
59
+ };
60
+ return {
61
+ basePath,
62
+ fetchImpl,
63
+ chunkCache: new Map(),
64
+ zonemapCache: new Map(),
65
+ signal: controller.signal,
66
+ track: (promise) => promise.catch(abortAndRethrow),
67
+ trackSync: (fn) => {
68
+ try {
69
+ return fn();
70
+ }
71
+ catch (error) {
72
+ return abortAndRethrow(error);
73
+ }
74
+ },
75
+ dispose: () => callerSignal?.removeEventListener("abort", onCallerAbort),
76
+ };
77
+ }
78
+ function abortedError(signal) {
79
+ return new ZonemapDbError({
80
+ code: "ABORTED",
81
+ message: "zonemapdb: the query was cancelled by its signal, and its pending fetches were aborted. Nothing is wrong " +
82
+ "with the deploy; if a newer query superseded this one, ignore it.",
83
+ cause: signal.reason,
84
+ });
85
+ }
86
+ /**
87
+ * Settles with `promise`, or rejects with ABORTED as soon as `signal` fires, whichever comes first.
88
+ * Used for waits a query doesn't own: the shared manifest fetch keeps going for the other queries,
89
+ * and an injected fetch that ignores its signal can't hold a cancelled query open.
90
+ */
91
+ function raceAbort(promise, signal) {
92
+ if (signal === undefined)
93
+ return promise;
94
+ if (signal.aborted) {
95
+ // Nobody else may be listening to `promise`; its later rejection mustn't surface as unhandled.
96
+ promise.catch(() => { });
97
+ return Promise.reject(abortedError(signal));
98
+ }
99
+ return new Promise((resolve, reject) => {
100
+ const onAbort = () => reject(abortedError(signal));
101
+ signal.addEventListener("abort", onAbort, { once: true });
102
+ promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
103
+ });
104
+ }
105
+ /**
106
+ * Resolves a secondary field's zonemap — already-inline `pairs`, or a lazy fetch of its sidecar
107
+ * the first time this query touches it (ADR-0003 §3: root stays "routing-essential only", rich
108
+ * pruning data is pay-on-use). `undefined` when the field carries no zonemap entry at all (e.g.
109
+ * it isn't indexed, or is the sort field, which is pruned separately via `splitPoints`).
110
+ */
111
+ async function resolveSecondaryZonemap(manifest, ctx, field) {
112
+ const entry = manifest.zonemap[field];
113
+ if (!entry || "splitPoints" in entry)
114
+ return undefined;
115
+ if (!("sidecar" in entry))
116
+ return entry;
117
+ let promise = ctx.zonemapCache.get(entry.sidecar);
118
+ if (!promise) {
119
+ promise = ctx.track(fetchZonemapSidecar(ctx.basePath, entry.sidecar, ctx.fetchImpl, ctx.signal));
120
+ ctx.zonemapCache.set(entry.sidecar, promise);
121
+ }
122
+ return await promise;
123
+ }
124
+ /** `a ∩ b` over block ordinals — the one intersection shape every AND-combination step shares. */
125
+ function intersectSets(a, b) {
126
+ return new Set([...a].filter((i) => b.has(i)));
127
+ }
128
+ /** Fetches+decodes the chunks a filter could touch, resolving them into a candidate block set. */
129
+ async function candidatesFromChunkedIndex(ctx, chunks, kind, filter) {
130
+ const blockIndices = new Set();
131
+ for (const chunkDir of chunksForFilter(chunks, filter)) {
132
+ let chunkPromise = ctx.chunkCache.get(chunkDir.file);
133
+ if (!chunkPromise) {
134
+ chunkPromise = ctx.track(fetchIndexChunk(ctx.basePath, chunkDir.file, ctx.fetchImpl, ctx.signal));
135
+ ctx.chunkCache.set(chunkDir.file, chunkPromise);
136
+ }
137
+ const awaitedChunk = await chunkPromise;
138
+ const decoded = ctx.trackSync(() => parseCorruptible(`${ctx.basePath}/${chunkDir.file}`, () => decodeIndexChunk(awaitedChunk, kind)));
139
+ for (const blockIndex of blockIndicesForFilter(decoded, filter))
140
+ blockIndices.add(blockIndex);
141
+ }
142
+ return blockIndices;
143
+ }
144
+ /**
145
+ * `contains`'s candidate set (ADR-0003 §7): AND-intersect the block sets of
146
+ * every query trigram — any block truly holding a match has ALL of them
147
+ * present somewhere, so intersecting can only over-approximate, never miss.
148
+ * A query shorter than 3 chars has no trigrams to route on — `undefined`
149
+ * signals "can't prune via this field," same as an absent index.
150
+ */
151
+ async function containsCandidates(ctx, chunks, substring) {
152
+ const grams = trigramsOf(substring);
153
+ if (grams.length === 0)
154
+ return undefined;
155
+ let result;
156
+ for (const gram of grams) {
157
+ const gramSet = await candidatesFromChunkedIndex(ctx, chunks, "string", { equals: gram });
158
+ result = result === undefined ? gramSet : intersectSets(result, gramSet);
159
+ if (result.size === 0)
160
+ break;
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Fetches+intersects EVERY structure one secondary field's filter constrains
166
+ * — the base index (equals/in/startsWith), the reversed index (endsWith),
167
+ * and the trigram index (contains) are independent structures, so each
168
+ * contributes its own candidate set and they AND together (ADR-0003 §7/§9).
169
+ */
170
+ async function secondaryFieldCandidates(manifest, ctx, field, rawFilter) {
171
+ const indexDescriptor = manifest.indexes[field];
172
+ if (!indexDescriptor)
173
+ return undefined;
174
+ const fieldMeta = manifest.schema.fields[field];
175
+ if (fieldMeta.multi)
176
+ return listFieldCandidates(manifest, ctx, field, indexDescriptor, rawFilter);
177
+ return valueFilterCandidates(manifest, ctx, field, indexDescriptor, rawFilter);
178
+ }
179
+ /**
180
+ * A multi-valued field's candidates: each list operator present contributes a set, and they AND
181
+ * together like any keys on one field (ADR-0010 §2/§4). An operator that can't prune contributes
182
+ * nothing rather than an empty set.
183
+ */
184
+ async function listFieldCandidates(manifest, ctx, field, indexDescriptor, rawFilter) {
185
+ const { some, every, hasEvery, isEmpty } = rawFilter;
186
+ // Missing on a manifest built before ADR-0010: unknown, so isEmpty/every can't prune — never "none".
187
+ const emptyBlocks = indexDescriptor.emptyBlocks && new Set(indexDescriptor.emptyBlocks);
188
+ const sets = [];
189
+ if (some !== undefined) {
190
+ const someSet = await valueFilterCandidates(manifest, ctx, field, indexDescriptor, unwrapElementFilter(some));
191
+ if (someSet)
192
+ sets.push(someSet);
193
+ }
194
+ // A list passing `every: F` either has an element — which satisfies F, so it sits in `some: F`'s
195
+ // postings — or is empty, so it sits in an emptyBlocks block.
196
+ if (every !== undefined && emptyBlocks) {
197
+ const elementSet = await valueFilterCandidates(manifest, ctx, field, indexDescriptor, unwrapElementFilter(every));
198
+ if (elementSet)
199
+ sets.push(unionSets(elementSet, emptyBlocks));
200
+ }
201
+ // Every value must be present, so a match sits in every value's postings: intersect, not union.
202
+ if (hasEvery !== undefined && hasEvery.length > 0) {
203
+ const kind = manifest.schema.fields[field].kind;
204
+ for (const value of hasEvery) {
205
+ sets.push(await candidatesFromChunkedIndex(ctx, indexDescriptor.chunks, kind, { equals: value }));
206
+ }
207
+ }
208
+ if (isEmpty === true && emptyBlocks)
209
+ sets.push(emptyBlocks);
210
+ if (sets.length === 0)
211
+ return undefined;
212
+ return sets.reduce(intersectSets);
213
+ }
214
+ /** One value filter's candidates — a scalar field's filter, or a multi field's element filter. */
215
+ async function valueFilterCandidates(manifest, ctx, field, indexDescriptor, effectiveFilter) {
216
+ const kind = manifest.schema.fields[field].kind;
217
+ const { endsWith, contains } = effectiveFilter;
218
+ const sets = [];
219
+ // ADR-0003 §6 step 1: free zonemap pruning before the pay-on-use index-chunk fetch. The zonemap can
220
+ // only over-approximate (never wrongly excludes a real match — ADR-0003 §2), so intersecting it in
221
+ // never changes the final (already-exact) index result; it's how a secondary field's zonemap —
222
+ // inline or a lazily-fetched sidecar (T13, ADR-0003 §3) — gets exercised at all, since equals/in are
223
+ // otherwise resolved exactly via the index alone. For a RANGE it is the only pruning available, and
224
+ // the pairs are exact for number/date (only string pairs are truncated), so it prunes precisely.
225
+ const pairFilter = pairFilterOf(effectiveFilter);
226
+ if (pairFilter) {
227
+ const zonemap = await resolveSecondaryZonemap(manifest, ctx, field);
228
+ const zonemapSet = zonemap && pairCandidateBlockIndices(zonemap.pairs, pairFilter);
229
+ if (zonemapSet)
230
+ sets.push(zonemapSet);
231
+ }
232
+ // Step 2: the inverted index, for the shapes that have a dictionary key to look up.
233
+ const baseFilter = secondaryFilterOf(effectiveFilter);
234
+ if (baseFilter) {
235
+ sets.push(await candidatesFromChunkedIndex(ctx, indexDescriptor.chunks, kind, baseFilter));
236
+ }
237
+ if (endsWith !== undefined && indexDescriptor.reversed) {
238
+ sets.push(await candidatesFromChunkedIndex(ctx, indexDescriptor.reversed.chunks, "string", {
239
+ startsWith: reverseString(endsWith),
240
+ }));
241
+ }
242
+ if (contains !== undefined && indexDescriptor.trigram) {
243
+ const trigramSet = await containsCandidates(ctx, indexDescriptor.trigram.chunks, contains);
244
+ if (trigramSet)
245
+ sets.push(trigramSet);
246
+ }
247
+ if (sets.length === 0)
248
+ return undefined;
249
+ return sets.reduce(intersectSets);
250
+ }
251
+ /**
252
+ * Block ordinals surviving zonemap + postings pruning for `where`, ascending.
253
+ * Free zonemap pruning on the sort field first (ADR-0003 §6 step 1), then
254
+ * fetch+intersect the index chunks for every equals/in/startsWith-constrained
255
+ * secondary field (step 2) — cheap chunk fetches before blocks.
256
+ */
257
+ async function candidateIndicesForWhere(manifest, ctx, where) {
258
+ const sortField = manifest.dataset.sortField;
259
+ const sortFieldFilter = where?.[sortField];
260
+ const sortZonemap = manifest.zonemap[sortField];
261
+ const splitPoints = sortZonemap?.splitPoints ?? [];
262
+ let candidateSet = new Set(candidateBlockIndices(splitPoints, sortFieldFilter));
263
+ const secondaryEntries = Object.entries(where ?? {}).filter(([field]) => field !== sortField);
264
+ const secondarySets = await Promise.all(secondaryEntries.map(([field, filter]) => secondaryFieldCandidates(manifest, ctx, field, filter)));
265
+ for (const set of secondarySets) {
266
+ if (set === undefined)
267
+ continue;
268
+ candidateSet = intersectSets(candidateSet, set);
269
+ }
270
+ return [...candidateSet].sort((a, b) => a - b);
271
+ }
272
+ /**
273
+ * Approximate upper bound with zero data-block fetches (ADR-0008 §2): sum
274
+ * `manifest.blocks[i].count` over the blocks surviving zonemap + postings
275
+ * pruning. `exact: true` only for an empty where and pruned-to-zero (§3).
276
+ */
277
+ async function executeCount(manifest, ctx, where) {
278
+ if (!where || Object.keys(where).length === 0) {
279
+ return { count: manifest.dataset.recordCount, exact: true };
280
+ }
281
+ const candidateIndices = await candidateIndicesForWhere(manifest, ctx, where);
282
+ if (candidateIndices.length === 0)
283
+ return { count: 0, exact: true };
284
+ let count = 0;
285
+ for (const index of candidateIndices)
286
+ count += manifest.blocks[index].count;
287
+ return { count, exact: false };
288
+ }
289
+ const DEFAULT_MAX_RESULTS = 10_000;
290
+ /** The explicit-limit half of the maxResults guardrail — pure validation, runs before any fetch. */
291
+ function assertLimitWithinCeiling(limit, maxResults) {
292
+ if (limit !== undefined && limit > maxResults) {
293
+ throw new ZonemapDbError({
294
+ code: "LIMIT_EXCEEDED",
295
+ message: `zonemapdb: limit ${limit} exceeds the maxResults ceiling ${maxResults} — ` +
296
+ `lower the query's limit, or raise maxResults in connect() if you truly need more.`,
297
+ });
298
+ }
299
+ }
300
+ /**
301
+ * `orderBy` may name any indexed field, not just the sort field (ADR-0001 item 42). Records are
302
+ * already fully materialized in memory by the time this runs, so a plain multi-key stable sort
303
+ * (iterating `orderBy`'s own key order for tiebreaks) is correct and doesn't disturb the exact
304
+ * `hasMore` accounting, which only depends on `matches.length`, not on ordering.
305
+ */
306
+ function compareByOrderBy(a, b, orderBy) {
307
+ for (const [field, direction] of Object.entries(orderBy)) {
308
+ const av = a[field];
309
+ const bv = b[field];
310
+ if (av === bv)
311
+ continue;
312
+ let cmp;
313
+ if (av === undefined || av === null)
314
+ cmp = -1;
315
+ else if (bv === undefined || bv === null)
316
+ cmp = 1;
317
+ else if (av < bv)
318
+ cmp = -1;
319
+ else if (av > bv)
320
+ cmp = 1;
321
+ else
322
+ cmp = 0;
323
+ if (cmp !== 0)
324
+ return direction === "desc" ? -cmp : cmp;
325
+ }
326
+ return 0;
327
+ }
328
+ function fetchBlockAt(manifest, ctx, index) {
329
+ return ctx.track(fetchBlockRecords(ctx.basePath, manifest.blocks[index].hash, manifest.blocks.length, datasetCompression(manifest), ctx.fetchImpl, ctx.signal));
330
+ }
331
+ /**
332
+ * Blocks per round of the walk. Fetching strictly one at a time would minimise bytes but serialise a
333
+ * round trip per block; a small window keeps the requests parallel while still stopping within
334
+ * `BLOCK_WALK_BATCH - 1` blocks of the page being filled. The comparison that matters is against
335
+ * fetching *every* candidate, which is what this replaces.
336
+ */
337
+ const BLOCK_WALK_BATCH = 4;
338
+ /**
339
+ * A `scan: "block-order"` query skips the rider rule, which is only safe while the walk can stop at
340
+ * the first full page: a `limit`, and no ordering the blocks don't already have.
341
+ */
342
+ function assertBlockOrderScan(manifest, args) {
343
+ const sortField = manifest.dataset.sortField;
344
+ if (args.scan !== "block-order") {
345
+ throw new ZonemapDbError({
346
+ code: "CONFIG",
347
+ message: `zonemapdb: unknown scan mode ${JSON.stringify(args.scan)} — the only one is "block-order".`,
348
+ });
349
+ }
350
+ if (blockWalkDirection(manifest, args) !== undefined)
351
+ return;
352
+ throw new ZonemapDbError({
353
+ code: "NEEDS_PRUNING",
354
+ message: `zonemapdb: scan: "block-order" walks the data files in sort order and stops once the page is full, so it ` +
355
+ `needs a \`limit\` and no \`orderBy\` other than the sort field "${sortField}"` +
356
+ (args.limit === undefined ? `. This query has no limit.` : `. This query's orderBy can't be answered in block order.`) +
357
+ ` See "Scanning in block order" in docs/query-guide.md.`,
358
+ });
359
+ }
360
+ /**
361
+ * Which direction to walk candidate blocks when a bounded query's requested order already matches
362
+ * their physical order — `undefined` when it doesn't, meaning every candidate has to be fetched
363
+ * before the ordering (and therefore the page) is known.
364
+ */
365
+ function blockWalkDirection(manifest, args) {
366
+ // Without a limit every match is returned, so there is no page to stop at.
367
+ if (args?.limit === undefined)
368
+ return undefined;
369
+ const orderBy = args.orderBy;
370
+ const keys = orderBy === undefined ? [] : Object.keys(orderBy);
371
+ // No orderBy: the result order IS block order, so walking is exactly equivalent to the full fetch.
372
+ if (keys.length === 0)
373
+ return "asc";
374
+ const sortField = manifest.dataset.sortField;
375
+ if (keys.length !== 1 || keys[0] !== sortField)
376
+ return undefined;
377
+ // An explicit orderBy on the sort field agrees with block order only when nothing has a
378
+ // null/absent sort value: those sit at the HIGH end on disk (ADR-0002 §9) but compare as lowest,
379
+ // so the two disagree and only materialize-then-sort places them correctly.
380
+ const zonemap = manifest.zonemap[sortField];
381
+ if (zonemap !== undefined && "splitPoints" in zonemap && zonemap.missing !== undefined)
382
+ return undefined;
383
+ return orderBy[sortField] === "desc" ? "desc" : "asc";
384
+ }
385
+ /**
386
+ * ADR-0008 §5: walk candidate blocks in sort order accumulating post-filtered matches until
387
+ * `offset + limit + 1` exist, then stop. The `+1` is what makes `hasMore` exact without a second
388
+ * query. Because the accumulated matches are a prefix of the globally ordered result set, slicing
389
+ * the page out of them is identical to slicing it out of every match — for a fraction of the bytes
390
+ * when the filter is unselective (the case where fetching all candidates hurt most).
391
+ */
392
+ async function findManyByBlockWalk(manifest, ctx, candidateIndices, args, direction) {
393
+ const limit = args.limit;
394
+ const offset = args.offset ?? 0;
395
+ const needed = offset + limit + 1;
396
+ const order = direction === "asc" ? candidateIndices : [...candidateIndices].reverse();
397
+ const matches = [];
398
+ // How many candidates the walk actually read. Pruning is conservative — every match lives in a
399
+ // candidate — so reading all of them means `matches` IS the whole match set and its size is exact.
400
+ let read = 0;
401
+ for (let i = 0; i < order.length && matches.length < needed; i += BLOCK_WALK_BATCH) {
402
+ const batch = order.slice(i, i + BLOCK_WALK_BATCH);
403
+ const fetched = await Promise.all(batch.map((index) => fetchBlockAt(manifest, ctx, index)));
404
+ for (const records of fetched) {
405
+ // Records within a block are ascending by the sort field; a descending walk reverses each
406
+ // block as well as the block order. Ties among equal sort values are unordered either way.
407
+ for (const record of direction === "asc" ? records : [...records].reverse()) {
408
+ if (matchesWhere(record, args.where))
409
+ matches.push(record);
410
+ }
411
+ }
412
+ read += batch.length;
413
+ }
414
+ const windowed = matches.slice(offset);
415
+ return {
416
+ records: windowed.slice(0, limit),
417
+ hasMore: windowed.length > limit,
418
+ // Stopping early is the walk's whole point, and it means the tail was never seen — no total then.
419
+ ...(read === order.length ? { total: matches.length } : {}),
420
+ };
421
+ }
422
+ async function executeFindMany(manifest, ctx, args, maxResults) {
423
+ const candidateIndices = await candidateIndicesForWhere(manifest, ctx, args?.where);
424
+ const walkDirection = blockWalkDirection(manifest, args);
425
+ if (walkDirection !== undefined) {
426
+ return await findManyByBlockWalk(manifest, ctx, candidateIndices, args, walkDirection);
427
+ }
428
+ const fetched = await Promise.all(candidateIndices.map(async (index) => ({ index, records: await fetchBlockAt(manifest, ctx, index) })));
429
+ fetched.sort((a, b) => a.index - b.index);
430
+ // Fetched blocks are individually sorted ascending by the sort field, and
431
+ // fetched/concatenated in ascending block-index order — the concatenation
432
+ // is already globally ascending; filtering never reorders it.
433
+ let matches = [];
434
+ for (const { records } of fetched) {
435
+ for (const record of records) {
436
+ if (matchesWhere(record, args?.where))
437
+ matches.push(record);
438
+ }
439
+ }
440
+ // The unbounded half of the maxResults guardrail: a query with no explicit
441
+ // limit that would exceed the ceiling throws rather than silently truncating
442
+ // (ADR-0004 — partial results are indistinguishable from smaller correct ones).
443
+ if (args?.limit === undefined && matches.length > maxResults) {
444
+ throw new ZonemapDbError({
445
+ code: "LIMIT_EXCEEDED",
446
+ message: `zonemapdb: this unbounded query matched more than the maxResults ceiling of ${maxResults} records — ` +
447
+ `add a limit ≤ ${maxResults} to paginate, or raise maxResults in connect(). Refusing to silently truncate.`,
448
+ });
449
+ }
450
+ if (args?.orderBy && Object.keys(args.orderBy).length > 0) {
451
+ const orderBy = args.orderBy;
452
+ matches = [...matches].sort((a, b) => compareByOrderBy(a, b, orderBy));
453
+ }
454
+ // This path read every candidate block, so `matches` is the complete match set — the exact total
455
+ // comes for free, even when only one page of it is returned.
456
+ const total = matches.length;
457
+ const offset = args?.offset ?? 0;
458
+ const windowed = matches.slice(offset);
459
+ if (args?.limit === undefined) {
460
+ return { records: windowed, hasMore: false, total };
461
+ }
462
+ return { records: windowed.slice(0, args.limit), hasMore: windowed.length > args.limit, total };
463
+ }
464
+ export function createClient(schema, opts) {
465
+ const basePath = opts.basePath.replace(/\/+$/, "");
466
+ const fetchImpl = opts.fetch ?? fetch;
467
+ const maxResults = opts.maxResults ?? DEFAULT_MAX_RESULTS;
468
+ const manifestCompression = opts.manifestCompression ?? (opts.manifestGzip === true ? "gzip" : "none");
469
+ let manifestPromise;
470
+ // A failed first fetch (a 503 on page load, a dropped connection) isn't remembered either: the next
471
+ // query tries again rather than inheriting the rejection until reload.
472
+ const getManifest = () => {
473
+ if (manifestPromise)
474
+ return manifestPromise;
475
+ const promise = fetchManifest(basePath, fetchImpl, manifestCompression).catch((error) => {
476
+ if (manifestPromise === promise)
477
+ manifestPromise = undefined;
478
+ throw error;
479
+ });
480
+ return (manifestPromise = promise);
481
+ };
482
+ // The one in-flight (or finished) refetch, keyed by the manifest it replaces. Every query that
483
+ // failed against that same stale manifest shares it, so a burst of concurrent queries after a
484
+ // redeploy costs one manifest request, not one each.
485
+ let refresh;
486
+ const refreshManifest = (stale) => {
487
+ if (refresh?.stale === stale)
488
+ return refresh.promise;
489
+ const promise = fetchManifest(basePath, fetchImpl, manifestCompression, "reload").then((fresh) => {
490
+ manifestPromise = Promise.resolve(fresh);
491
+ return fresh;
492
+ }, (error) => {
493
+ // A failed refetch isn't remembered: the next failing query tries again.
494
+ if (refresh?.promise === promise)
495
+ refresh = undefined;
496
+ throw error;
497
+ });
498
+ refresh = { stale, promise };
499
+ return promise;
500
+ };
501
+ /**
502
+ * Runs one query against the manifest, recovering once from a stale cached manifest (#32).
503
+ *
504
+ * Content-hashed files never go stale, but the manifest's name is the same across deploys, and a
505
+ * host that caches it (despite the `no-cache` revalidation, e.g. a CDN or a caching fetch wrapper)
506
+ * can hand back the previous deploy's copy, which names files the new deploy removed. So a
507
+ * DEPLOY_INTEGRITY 404 refetches the manifest with `cache: "reload"`. If the fresh manifest no
508
+ * longer names the missing file it replaces the cached one and the query reruns once against it
509
+ * (index chunks and sidecars are cached per query, so there is nothing else to drop). If it still
510
+ * names the file, that's a real partial deploy and the original error is thrown. A second
511
+ * failure on the rerun throws as-is: the retry is bounded at one, so it can never loop.
512
+ *
513
+ * `signal` is the caller's: it aborts this query's own fetches, and a cancelled query rejects with
514
+ * ABORTED and never retries. The shared manifest fetch and refetch are only raced, never aborted,
515
+ * because other queries may be waiting on them.
516
+ */
517
+ const withManifest = async (signal, run) => {
518
+ const attempt = async (manifest) => {
519
+ // The signal can fire while the manifest resolves; don't start fetches for a cancelled query.
520
+ if (signal?.aborted)
521
+ throw abortedError(signal);
522
+ const ctx = makeFetchContext(basePath, fetchImpl, signal);
523
+ try {
524
+ return await raceAbort(run(manifest, ctx), signal);
525
+ }
526
+ finally {
527
+ ctx.dispose();
528
+ }
529
+ };
530
+ const manifest = await raceAbort(getManifest(), signal);
531
+ try {
532
+ return await attempt(manifest);
533
+ }
534
+ catch (error) {
535
+ // Whatever a cancelled query's fetches threw on the way out, the caller asked for this.
536
+ if (signal?.aborted)
537
+ throw abortedError(signal);
538
+ if (!(error instanceof ZonemapDbError) || error.code !== "DEPLOY_INTEGRITY" || error.url === undefined)
539
+ throw error;
540
+ // A refetch that itself fails (a 5xx, a FORMAT_VERSION from a newer build) throws its own,
541
+ // more telling, error.
542
+ const fresh = await raceAbort(refreshManifest(manifest), signal);
543
+ if (manifestReferences(fresh, basePath, error.url))
544
+ throw error;
545
+ return await attempt(fresh);
546
+ }
547
+ };
548
+ const makeCollection = (meta) => {
549
+ const collection = {
550
+ findMany: async (args) => {
551
+ assertLimitWithinCeiling(args?.limit, maxResults);
552
+ if (args?.where !== undefined)
553
+ args = { ...args, where: compactWhere(args.where) };
554
+ return withManifest(args?.signal, (manifest, ctx) => {
555
+ // After the manifest (which says what prunes on this dataset), before any index or block fetch.
556
+ if (args?.scan !== undefined)
557
+ assertBlockOrderScan(manifest, args);
558
+ else
559
+ assertWhereHasPruning(args?.where, manifest.schema);
560
+ return executeFindMany(manifest, ctx, args, maxResults);
561
+ });
562
+ },
563
+ count: async (where, opts) => withManifest(opts?.signal, (manifest, ctx) => executeCount(manifest, ctx, compactWhere(where))),
564
+ getSchema: () => meta,
565
+ };
566
+ // `get(id)` is equality-on-PK through the same candidate-block machinery as
567
+ // `findMany` (ADR-0003 §10) — free (≤1 block) when the PK is the sort field
568
+ // (zonemap alone pinpoints it), else ≤1 index chunk + ≤1 block. Omitted
569
+ // entirely (not even a stubbed throw) when no PK was declared (T1/ADR-0004).
570
+ if (meta.pk !== undefined) {
571
+ const pkField = meta.pk;
572
+ collection.get = async (id, opts) => {
573
+ const { records } = await withManifest(opts?.signal, (manifest, ctx) => executeFindMany(manifest, ctx, { where: { [pkField]: { equals: id } }, limit: 1 }, maxResults));
574
+ return records[0] ?? null;
575
+ };
576
+ }
577
+ return collection;
578
+ };
579
+ const out = {};
580
+ for (const name of Object.keys(schema))
581
+ out[name] = makeCollection(schema[name]);
582
+ return out;
583
+ }
584
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,EAAuF,MAAM,eAAe,CAAC;AAC3K,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,UAAU,GAGX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,YAAY,GAOb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAI1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAWzD,2GAA2G;AAC3G,SAAS,iBAAiB,CAAC,SAAkC;IAC3D,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACvD,IAAI,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACjG,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAiC,EAAE,UAAU,EAAE,UAAgC,EAAE,CAAC;AACzG,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,SAAkC;IACtD,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC;IAC7D,IAAI,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACrI,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAiC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,aAAsB;IACjD,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAwC,CAAC;IACjH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnC,CAAC;AAED,mCAAmC;AACnC,SAAS,SAAS,CAAC,CAAc,EAAE,CAAc;IAC/C,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAmBD;;;GAGG;AACH,SAAS,gBAAgB,CAAC,QAAgB,EAAE,SAAuB,EAAE,YAA0B;IAC7F,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,YAAa,CAAC,MAAM,CAAC,CAAC;IACnE,yGAAyG;IACzG,IAAI,YAAY,EAAE,OAAO;QAAE,aAAa,EAAE,CAAC;;QACtC,YAAY,EAAE,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,MAAM,eAAe,GAAG,CAAC,KAAc,EAAS,EAAE;QAChD,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC;IACF,OAAO;QACL,QAAQ;QACR,SAAS;QACT,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAClD,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE;YAChB,IAAI,CAAC;gBACH,OAAO,EAAE,EAAE,CAAC;YACd,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,EAAE,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC;KACzE,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAmB;IACvC,OAAO,IAAI,cAAc,CAAC;QACxB,IAAI,EAAE,SAAS;QACf,OAAO,EACL,2GAA2G;YAC3G,mEAAmE;QACrE,KAAK,EAAE,MAAM,CAAC,MAAM;KACrB,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAI,OAAmB,EAAE,MAA+B;IACxE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,+FAA+F;QAC/F,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxB,OAAO,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAAkB,EAClB,GAAiB,EACjB,KAAa;IAEb,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,IAAI,aAAa,IAAI,KAAK;QAAE,OAAO,SAAS,CAAC;IACvD,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAExC,IAAI,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACjG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,MAAM,OAAO,CAAC;AACvB,CAAC;AAED,kGAAkG;AAClG,SAAS,aAAa,CAAC,CAAc,EAAE,CAAc;IACnD,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,kGAAkG;AAClG,KAAK,UAAU,0BAA0B,CACvC,GAAiB,EACjB,MAA4B,EAC5B,IAAe,EACf,MAA4B;IAE5B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,KAAK,MAAM,QAAQ,IAAI,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QACvD,IAAI,YAAY,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YAClG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC;QACxC,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CACjC,gBAAgB,CAAC,GAAG,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CACjG,CAAC;QACF,KAAK,MAAM,UAAU,IAAI,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC;YAAE,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,kBAAkB,CAC/B,GAAiB,EACjB,MAA4B,EAC5B,SAAiB;IAEjB,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,IAAI,MAA+B,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzE,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,MAAM;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,wBAAwB,CACrC,QAAkB,EAClB,GAAiB,EACjB,KAAa,EACb,SAAkC;IAElC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC,eAAe;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC;IACjD,IAAI,SAAS,CAAC,KAAK;QAAE,OAAO,mBAAmB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;IAClG,OAAO,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,mBAAmB,CAChC,QAAkB,EAClB,GAAiB,EACjB,KAAa,EACb,eAAgC,EAChC,SAAkC;IAElC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,SAK1C,CAAC;IACF,qGAAqG;IACrG,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,IAAI,IAAI,GAAG,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IACxF,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9G,IAAI,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,iGAAiG;IACjG,8DAA8D;IAC9D,IAAI,KAAK,KAAK,SAAS,IAAI,WAAW,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;QAClH,IAAI,UAAU;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,gGAAgG;IAChG,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,IAAiB,CAAC;QAC9D,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,0BAA0B,CAAC,GAAG,EAAE,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACpG,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,IAAI,IAAI,WAAW;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE5D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC;AAED,kGAAkG;AAClG,KAAK,UAAU,qBAAqB,CAClC,QAAkB,EAClB,GAAiB,EACjB,KAAa,EACb,eAAgC,EAChC,eAAwC;IAExC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,IAAiB,CAAC;IAC9D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,eAA2D,CAAC;IAC3F,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,oGAAoG;IACpG,mGAAmG;IACnG,+FAA+F;IAC/F,qGAAqG;IACrG,oGAAoG;IACpG,iGAAiG;IACjG,MAAM,UAAU,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;IACjD,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,OAAO,IAAI,yBAAyB,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACnF,IAAI,UAAU;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,oFAAoF;IACpF,MAAM,UAAU,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACtD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC,IAAI,CAAC,MAAM,0BAA0B,CAAC,GAAG,EAAE,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,eAAe,CAAC,QAAQ,EAAE,CAAC;QACvD,IAAI,CAAC,IAAI,CACP,MAAM,0BAA0B,CAAC,GAAG,EAAE,eAAe,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE;YAC/E,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC;SACpC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3F,IAAI,UAAU;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,wBAAwB,CACrC,QAAkB,EAClB,GAAiB,EACjB,KAA0D;IAE1D,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;IAC7C,MAAM,eAAe,GAAG,KAAK,EAAE,CAAC,SAAS,CAAgC,CAAC;IAC1E,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAA8C,CAAC;IAC7F,MAAM,WAAW,GAAG,WAAW,EAAE,WAAW,IAAI,EAAE,CAAC;IAEnD,IAAI,YAAY,GAAG,IAAI,GAAG,CAAC,qBAAqB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC,CAAC;IAChF,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAC9F,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAClG,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,YAAY,GAAG,aAAa,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,YAAY,CACzB,QAAkB,EAClB,GAAiB,EACjB,KAA0D;IAE1D,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9E,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACpE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,gBAAgB;QAAE,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,KAAK,CAAC;IAC7E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,oGAAoG;AACpG,SAAS,wBAAwB,CAAC,KAAyB,EAAE,UAAkB;IAC7E,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;QAC9C,MAAM,IAAI,cAAc,CAAC;YACvB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EACL,oBAAoB,KAAK,mCAAmC,UAAU,KAAK;gBAC3E,mFAAmF;SACtF,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CACvB,CAA0B,EAC1B,CAA0B,EAC1B,OAAuC;IAEvC,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QACxB,IAAI,GAAW,CAAC;QAChB,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI;YAAE,GAAG,GAAG,CAAC,CAAC,CAAC;aACzC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI;YAAE,GAAG,GAAG,CAAC,CAAC;aAC7C,IAAI,EAAE,GAAG,EAAE;YAAE,GAAG,GAAG,CAAC,CAAC,CAAC;aACtB,IAAI,EAAE,GAAG,EAAE;YAAE,GAAG,GAAG,CAAC,CAAC;;YACrB,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,GAAG,KAAK,CAAC;YAAE,OAAO,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,YAAY,CAAC,QAAkB,EAAE,GAAiB,EAAE,KAAa;IACxE,OAAO,GAAG,CAAC,KAAK,CACd,iBAAiB,CACf,GAAG,CAAC,QAAQ,EACZ,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,IAAI,EAC5B,QAAQ,CAAC,MAAM,CAAC,MAAM,EACtB,kBAAkB,CAAC,QAAQ,CAAC,EAC5B,GAAG,CAAC,SAAS,EACb,GAAG,CAAC,MAAM,CACX,CACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B;;;GAGG;AACH,SAAS,oBAAoB,CAAC,QAAkB,EAAE,IAAqB;IACrE,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;IAC7C,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAChC,MAAM,IAAI,cAAc,CAAC;YACvB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,gCAAgC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC;SACtG,CAAC,CAAC;IACL,CAAC;IACD,IAAI,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO;IAC7D,MAAM,IAAI,cAAc,CAAC;QACvB,IAAI,EAAE,eAAe;QACrB,OAAO,EACL,2GAA2G;YAC3G,mEAAmE,SAAS,GAAG;YAC/E,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,0DAA0D,CAAC;YACtH,wDAAwD;KAC3D,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,QAAkB,EAAE,IAAiC;IAC/E,2EAA2E;IAC3E,IAAI,IAAI,EAAE,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/D,mGAAmG;IACnG,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEpC,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;IAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEjE,wFAAwF;IACxF,iGAAiG;IACjG,4EAA4E;IAC5E,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,aAAa,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzG,OAAO,OAAQ,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAChC,QAAkB,EAClB,GAAiB,EACjB,gBAA0B,EAC1B,IAAqB,EACrB,SAAyB;IAEzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC;IAEvF,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,+FAA+F;IAC/F,mGAAmG;IACnG,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACnF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5F,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC9B,0FAA0F;YAC1F,2FAA2F;YAC3F,KAAK,MAAM,MAAM,IAAI,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC5E,IAAI,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO;QACL,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QACjC,OAAO,EAAE,QAAQ,CAAC,MAAM,GAAG,KAAK;QAChC,kGAAkG;QAClG,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,QAAkB,EAClB,GAAiB,EACjB,IAAiC,EACjC,UAAkB;IAElB,MAAM,gBAAgB,GAAG,MAAM,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAEpF,MAAM,aAAa,GAAG,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,MAAM,mBAAmB,CAAC,QAAQ,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAK,EAAE,aAAa,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CACtG,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE1C,0EAA0E;IAC1E,0EAA0E;IAC1E,8DAA8D;IAC9D,IAAI,OAAO,GAA8B,EAAE,CAAC;IAC5C,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;QAClC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,6EAA6E;IAC7E,gFAAgF;IAChF,IAAI,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;QAC7D,MAAM,IAAI,cAAc,CAAC;YACvB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EACL,+EAA+E,UAAU,aAAa;gBACtG,iBAAiB,UAAU,gFAAgF;SAC9G,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,EAAE,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,iGAAiG;IACjG,6DAA6D;IAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,IAAI,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACtD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;AAClG,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAAS,EACT,IAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAC1D,MAAM,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACvG,IAAI,eAA8C,CAAC;IACnD,oGAAoG;IACpG,uEAAuE;IACvE,MAAM,WAAW,GAAG,GAAsB,EAAE;QAC1C,IAAI,eAAe;YAAE,OAAO,eAAe,CAAC;QAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC/F,IAAI,eAAe,KAAK,OAAO;gBAAE,eAAe,GAAG,SAAS,CAAC;YAC7D,MAAM,KAAK,CAAC;QACd,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,+FAA+F;IAC/F,8FAA8F;IAC9F,qDAAqD;IACrD,IAAI,OAAoE,CAAC;IACzE,MAAM,eAAe,GAAG,CAAC,KAAe,EAAqB,EAAE;QAC7D,IAAI,OAAO,EAAE,KAAK,KAAK,KAAK;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC;QACrD,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC,IAAI,CACpF,CAAC,KAAK,EAAE,EAAE;YACR,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,yEAAyE;YACzE,IAAI,OAAO,EAAE,OAAO,KAAK,OAAO;gBAAE,OAAO,GAAG,SAAS,CAAC;YACtD,MAAM,KAAK,CAAC;QACd,CAAC,CACF,CAAC;QACF,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAC7B,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF;;;;;;;;;;;;;;;OAeG;IACH,MAAM,YAAY,GAAG,KAAK,EACxB,MAA+B,EAC/B,GAA0D,EAC9C,EAAE;QACd,MAAM,OAAO,GAAG,KAAK,EAAE,QAAkB,EAAc,EAAE;YACvD,8FAA8F;YAC9F,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC;gBACH,OAAO,MAAM,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;oBAAS,CAAC;gBACT,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wFAAwF;YACxF,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;YAChD,IAAI,CAAC,CAAC,KAAK,YAAY,cAAc,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,MAAM,KAAK,CAAC;YACpH,2FAA2F;YAC3F,uBAAuB;YACvB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;YACjE,IAAI,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC;gBAAE,MAAM,KAAK,CAAC;YAChE,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAC,IAAoB,EAAE,EAAE;QAC9C,MAAM,UAAU,GAA4B;YAC1C,QAAQ,EAAE,KAAK,EAAE,IAAsB,EAAE,EAAE;gBACzC,wBAAwB,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;gBAClD,IAAI,IAAI,EAAE,KAAK,KAAK,SAAS;oBAAE,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnF,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;oBAClD,gGAAgG;oBAChG,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS;wBAAE,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;;wBAC9D,qBAAqB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;oBACzD,OAAO,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC1D,CAAC,CAAC,CAAC;YACL,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,KAA+C,EAAE,IAA+B,EAAE,EAAE,CAChG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;YACjG,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;SACtB,CAAC;QAEF,4EAA4E;QAC5E,4EAA4E;QAC5E,wEAAwE;QACxE,6EAA6E;QAC7E,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,GAAG,GAAG,KAAK,EAAE,EAAW,EAAE,IAA+B,EAAE,EAAE;gBACtE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,CACrE,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,CAC/F,CAAC;gBACF,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;YAC5B,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;IAEF,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAE,CAAC,CAAC;IAClF,OAAO,GAAgC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Every runtime failure maps to exactly one code — as fine-grained as the
3
+ * caller's *reaction* differs, no finer (ADR-0007 §5):
4
+ *
5
+ * - `CONFIG` — manifest.json itself 404s / is unreachable (wrong basePath). Not retryable.
6
+ * - `FORMAT_VERSION` — manifest major ≠ runtime major, checked when the manifest loads. Not retryable.
7
+ * - `DEPLOY_INTEGRITY` — a manifest-referenced content-hashed block/chunk/sidecar 404s, and a freshly
8
+ * refetched manifest still names it (the client retries once past a stale cached manifest, #32). Not retryable.
9
+ * - `NETWORK` — fetch rejected, or resolved non-ok non-404; optional `.status`. The one maybe-transient bucket.
10
+ * - `CORRUPT_DATA` — 2xx body won't parse into JSON/NDJSON/domain structure. Not retryable.
11
+ * - `LIMIT_EXCEEDED` — the `maxResults` ceiling (fail-loud, never truncates). Not retryable.
12
+ * - `NEEDS_PRUNING` — a `findMany` where made only of riders, which would read every block (ADR-0013). Not retryable.
13
+ * - `ABORTED` — the caller's `signal` fired, and the query's pending fetches were cancelled. Not a failure:
14
+ * usually a newer query superseded this one, so there is nothing to retry or log.
15
+ */
16
+ export type ZonemapDbErrorCode = "CONFIG" | "FORMAT_VERSION" | "DEPLOY_INTEGRITY" | "NETWORK" | "CORRUPT_DATA" | "LIMIT_EXCEEDED" | "NEEDS_PRUNING" | "ABORTED";
17
+ export interface ZonemapDbErrorInit {
18
+ readonly code: ZonemapDbErrorCode;
19
+ /** Human-readable, with remediation (ADR-0007 §8). */
20
+ readonly message: string;
21
+ /** The underlying thrown error, chained via native ES2022 `Error.cause`. */
22
+ readonly cause?: unknown;
23
+ /** The file being fetched when it failed — absent for LIMIT_EXCEEDED, NEEDS_PRUNING and ABORTED. */
24
+ readonly url?: string;
25
+ /** HTTP status — present on NETWORK-from-response and the two 404 codes. */
26
+ readonly status?: number;
27
+ }
28
+ /**
29
+ * The one error `findMany`/`count`/`get` ever throw for fetch/parse/limit
30
+ * failures: `catch (e) { if (e instanceof ZonemapDbError && e.code === "…") … }`.
31
+ * The triggering query object is deliberately NOT attached — a `where` can hold
32
+ * PII-ish filter values that would land in logs (ADR-0007 §8).
33
+ */
34
+ export declare class ZonemapDbError extends Error {
35
+ readonly code: ZonemapDbErrorCode;
36
+ readonly url?: string;
37
+ readonly status?: number;
38
+ constructor(init: ZonemapDbErrorInit);
39
+ }
40
+ //# sourceMappingURL=errors.d.ts.map