@adonis-agora/telescope 0.21.1 → 0.23.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 (49) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -0
  3. package/dist/src/ai/index.d.ts +1 -1
  4. package/dist/src/ai/index.js +1 -1
  5. package/dist/src/alerts/index.d.ts +1 -1
  6. package/dist/src/alerts/index.js +1 -1
  7. package/dist/src/index.d.ts +9 -2
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js +4 -1
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/mcp/index.d.ts +1 -1
  12. package/dist/src/mcp/index.js +1 -1
  13. package/dist/src/profiling/index.d.ts +1 -1
  14. package/dist/src/profiling/index.js +1 -1
  15. package/dist/src/stores/factory.d.ts +79 -0
  16. package/dist/src/stores/factory.d.ts.map +1 -1
  17. package/dist/src/stores/factory.js +71 -0
  18. package/dist/src/stores/factory.js.map +1 -1
  19. package/dist/src/stores/parquet.d.ts +184 -0
  20. package/dist/src/stores/parquet.d.ts.map +1 -0
  21. package/dist/src/stores/parquet.js +461 -0
  22. package/dist/src/stores/parquet.js.map +1 -0
  23. package/dist/src/stores/parquet_duckdb.d.ts +52 -0
  24. package/dist/src/stores/parquet_duckdb.d.ts.map +1 -0
  25. package/dist/src/stores/parquet_duckdb.js +266 -0
  26. package/dist/src/stores/parquet_duckdb.js.map +1 -0
  27. package/dist/src/stores/parquet_format.d.ts +108 -0
  28. package/dist/src/stores/parquet_format.d.ts.map +1 -0
  29. package/dist/src/stores/parquet_format.js +175 -0
  30. package/dist/src/stores/parquet_format.js.map +1 -0
  31. package/dist/src/stores/parquet_hyparquet.d.ts +34 -0
  32. package/dist/src/stores/parquet_hyparquet.d.ts.map +1 -0
  33. package/dist/src/stores/parquet_hyparquet.js +212 -0
  34. package/dist/src/stores/parquet_hyparquet.js.map +1 -0
  35. package/dist/src/stores/parquet_location.d.ts +88 -0
  36. package/dist/src/stores/parquet_location.d.ts.map +1 -0
  37. package/dist/src/stores/parquet_location.js +194 -0
  38. package/dist/src/stores/parquet_location.js.map +1 -0
  39. package/dist/src/stores/tiered.d.ts +91 -0
  40. package/dist/src/stores/tiered.d.ts.map +1 -0
  41. package/dist/src/stores/tiered.js +254 -0
  42. package/dist/src/stores/tiered.js.map +1 -0
  43. package/dist/src/ui/index.d.ts +1 -1
  44. package/dist/src/ui/index.js +1 -1
  45. package/dist/src/watchers/index.d.ts +1 -1
  46. package/dist/src/watchers/index.js +1 -1
  47. package/package.json +57 -28
  48. package/skills/telescope-setup/SKILL.md +1 -1
  49. package/skills/telescope-storage-retention/SKILL.md +7 -4
@@ -0,0 +1,212 @@
1
+ import { compareNewestFirst, fromParquetRow, toDate } from './parquet_format.js';
2
+ import { isNotFound } from './parquet_location.js';
3
+ /**
4
+ * The default cold engine: pure JavaScript (hyparquet), nothing native and nothing
5
+ * fetched at runtime.
6
+ *
7
+ * Reads walk files newest-first and, inside each file, row groups newest-first,
8
+ * skipping any group whose `created_at` statistics fall outside the query, and stop
9
+ * as soon as the page is full and nothing older can still outrank it. Equality
10
+ * filters on `id` / `trace_id` also consult the bloom filters the writer emits.
11
+ */
12
+ export class HyparquetEngine {
13
+ ctx;
14
+ name = 'hyparquet';
15
+ constructor(ctx) {
16
+ this.ctx = ctx;
17
+ }
18
+ async list(files, query, limit) {
19
+ let results = [];
20
+ const filter = pushdownFilter(query);
21
+ // Bloom filters exist for `trace_id` (and `id`); they pay off on point lookups only.
22
+ const useBloom = query.traceId !== undefined || query.traceIds !== undefined;
23
+ const before = query.before?.getTime();
24
+ const after = query.after?.getTime();
25
+ const full = () => limit !== undefined && results.length >= limit;
26
+ const floor = () => results[results.length - 1].createdAt.getTime();
27
+ for (const file of files) {
28
+ if (full() && file.maxMs < floor())
29
+ break;
30
+ for (const group of newestGroups(file, before, after)) {
31
+ if (full() && group.maxMs < floor())
32
+ break;
33
+ const rows = await this.readGroup(file, group, undefined, filter, useBloom);
34
+ for (const row of rows) {
35
+ if (!rowMatches(row, query))
36
+ continue;
37
+ results.push(fromParquetRow(row));
38
+ }
39
+ results.sort(compareNewestFirst);
40
+ if (limit !== undefined && results.length > limit)
41
+ results = results.slice(0, limit);
42
+ }
43
+ }
44
+ return results;
45
+ }
46
+ async get(files, id) {
47
+ const filter = { id: { $eq: id } };
48
+ for (const file of files) {
49
+ for (const group of newestGroups(file, undefined, undefined)) {
50
+ const rows = await this.readGroup(file, group, undefined, filter, true);
51
+ const hit = rows.find((row) => row.id === id);
52
+ if (hit)
53
+ return fromParquetRow(hit);
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ async traceIds(files, query, limit) {
59
+ const lastAt = new Map();
60
+ const before = query.before?.getTime();
61
+ const after = query.after?.getTime();
62
+ // Once `limit` traces are newer than everything left to read, nothing older can enter.
63
+ const kth = () => {
64
+ if (lastAt.size < limit)
65
+ return Number.NEGATIVE_INFINITY;
66
+ return [...lastAt.values()].sort((a, b) => b - a)[limit - 1];
67
+ };
68
+ for (const file of files) {
69
+ if (file.maxMs < kth())
70
+ break;
71
+ for (const group of newestGroups(file, before, after)) {
72
+ if (group.maxMs < kth())
73
+ break;
74
+ const rows = await this.readGroup(file, group, ['trace_id', 'created_at']);
75
+ for (const row of rows) {
76
+ if (row.trace_id == null)
77
+ continue;
78
+ const at = toDate(row.created_at).getTime();
79
+ if (before !== undefined && !(at < before))
80
+ continue;
81
+ if (after !== undefined && !(at > after))
82
+ continue;
83
+ const traceId = String(row.trace_id);
84
+ const seen = lastAt.get(traceId);
85
+ if (seen === undefined || at > seen)
86
+ lastAt.set(traceId, at);
87
+ }
88
+ }
89
+ }
90
+ return [...lastAt.entries()]
91
+ .sort((a, b) => b[1] - a[1])
92
+ .slice(0, limit)
93
+ .map(([traceId, at]) => ({ traceId, lastAt: new Date(at) }));
94
+ }
95
+ async countByBucket(files, query) {
96
+ const startMs = query.after.getTime();
97
+ const endMs = query.before.getTime();
98
+ const bucketMs = Math.max(1, Math.floor(query.bucketMs));
99
+ const tally = new Map();
100
+ for (const file of files) {
101
+ for (const group of newestGroups(file, endMs + 1, startMs)) {
102
+ const rows = await this.readGroup(file, group, ['type', 'created_at']);
103
+ for (const row of rows) {
104
+ const type = String(row.type);
105
+ if (query.type !== undefined && type !== query.type)
106
+ continue;
107
+ const at = toDate(row.created_at).getTime();
108
+ if (at <= startMs || at > endMs)
109
+ continue;
110
+ const index = Math.floor((at - startMs) / bucketMs);
111
+ const key = `${index}\u0000${type}`;
112
+ const seen = tally.get(key);
113
+ if (seen === undefined)
114
+ tally.set(key, { index, type, count: 1 });
115
+ else
116
+ seen.count += 1;
117
+ }
118
+ }
119
+ }
120
+ return [...tally.values()];
121
+ }
122
+ async close() { }
123
+ /** One row group as plain objects; a file that vanished since listing reads as empty. */
124
+ async readGroup(file, group, columns, filter, useBloomFilters = false) {
125
+ const { hyparquet, compressors } = this.ctx.libs;
126
+ try {
127
+ const metadata = await this.ctx.metadata(file);
128
+ return (await hyparquet.parquetReadObjects({
129
+ file: hyparquet.cachedAsyncBuffer(this.ctx.buffer(file)),
130
+ metadata,
131
+ compressors,
132
+ rowStart: group.rowStart,
133
+ rowEnd: group.rowEnd,
134
+ ...(columns !== undefined ? { columns } : {}),
135
+ ...(filter !== undefined ? { filter, useBloomFilters } : {}),
136
+ }));
137
+ }
138
+ catch (error) {
139
+ if (isNotFound(error))
140
+ return [];
141
+ throw error;
142
+ }
143
+ }
144
+ }
145
+ /** A file's row groups that overlap `(after, before)`, newest first. */
146
+ function newestGroups(file, before, after) {
147
+ return file.rowGroups
148
+ .filter((group) => {
149
+ if (before !== undefined && group.minMs >= before)
150
+ return false;
151
+ if (after !== undefined && group.maxMs <= after)
152
+ return false;
153
+ return true;
154
+ })
155
+ .sort((a, b) => b.maxMs - a.maxMs);
156
+ }
157
+ /**
158
+ * The equality predicates hyparquet can evaluate itself (and use to skip row groups).
159
+ * Everything else is checked in {@link rowMatches}.
160
+ */
161
+ function pushdownFilter(query) {
162
+ const clauses = [];
163
+ if (query.type !== undefined)
164
+ clauses.push({ type: { $eq: query.type } });
165
+ if (query.familyHash !== undefined)
166
+ clauses.push({ family_hash: { $eq: query.familyHash } });
167
+ if (query.traceId !== undefined)
168
+ clauses.push({ trace_id: { $eq: query.traceId } });
169
+ if (query.traceIds !== undefined)
170
+ clauses.push({ trace_id: { $in: query.traceIds } });
171
+ if (clauses.length === 0)
172
+ return undefined;
173
+ return clauses.length === 1 ? clauses[0] : { $and: clauses };
174
+ }
175
+ /**
176
+ * Every {@link EntryQuery} predicate, evaluated on the stored row before it is parsed.
177
+ * `tag` matches the quoted token inside the JSON text and `search` is a lower-cased
178
+ * substring over `content` and `tags` — the same semantics as the Lucid store.
179
+ */
180
+ export function rowMatches(row, query) {
181
+ if (query.type !== undefined && row.type !== query.type)
182
+ return false;
183
+ if (query.familyHash !== undefined && row.family_hash !== query.familyHash)
184
+ return false;
185
+ if (query.traceId !== undefined && row.trace_id !== query.traceId)
186
+ return false;
187
+ if (query.traceIds !== undefined) {
188
+ if (typeof row.trace_id !== 'string' || !query.traceIds.includes(row.trace_id))
189
+ return false;
190
+ }
191
+ if (query.before !== undefined || query.after !== undefined) {
192
+ const at = toDate(row.created_at).getTime();
193
+ if (query.before !== undefined && !(at < query.before.getTime()))
194
+ return false;
195
+ if (query.after !== undefined && !(at > query.after.getTime()))
196
+ return false;
197
+ }
198
+ const tags = String(row.tags ?? '');
199
+ if (query.tag !== undefined && !tags.includes(JSON.stringify(query.tag)))
200
+ return false;
201
+ if (query.search !== undefined) {
202
+ const needle = query.search.toLowerCase();
203
+ if (!String(row.content ?? '')
204
+ .toLowerCase()
205
+ .includes(needle) &&
206
+ !tags.toLowerCase().includes(needle)) {
207
+ return false;
208
+ }
209
+ }
210
+ return true;
211
+ }
212
+ //# sourceMappingURL=parquet_hyparquet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parquet_hyparquet.js","sourceRoot":"","sources":["../../../src/stores/parquet_hyparquet.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAInD;;;;;;;;GAQG;AACH,MAAM,OAAO,eAAe;IAGG,GAAG;IAFvB,IAAI,GAAG,WAAoB,CAAC;IAErC,YAA6B,GAAsB;mBAAtB,GAAG;IAAsB,CAAC;IAEvD,KAAK,CAAC,IAAI,CAAC,KAAiB,EAAE,KAAiB,EAAE,KAAyB;QACxE,IAAI,OAAO,GAAY,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,qFAAqF;QACrF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;QAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;QAClE,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAErE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,EAAE;gBAAE,MAAM;YAC1C,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,IAAI,EAAE,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,EAAE;oBAAE,MAAM;gBAC3C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAC5E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC;wBAAE,SAAS;oBACtC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;gBACpC,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBACjC,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK;oBAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAiB,EAAE,EAAU;QACrC,MAAM,MAAM,GAAuB,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC7D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;gBACxE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC9C,IAAI,GAAG;oBAAE,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,KAAiB,EACjB,KAAsC,EACtC,KAAa;QAEb,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QACrC,uFAAuF;QACvF,MAAM,GAAG,GAAG,GAAW,EAAE;YACvB,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK;gBAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;YACzD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAE,CAAC;QAChE,CAAC,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE;gBAAE,MAAM;YAC9B,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,KAAK,CAAC,KAAK,GAAG,GAAG,EAAE;oBAAE,MAAM;gBAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;gBAC3E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI;wBAAE,SAAS;oBACnC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;oBAC5C,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC;wBAAE,SAAS;oBACrD,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;wBAAE,SAAS;oBACnD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACrC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;oBACjC,IAAI,IAAI,KAAK,SAAS,IAAI,EAAE,GAAG,IAAI;wBAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;aACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;aAC3B,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAiB,EAAE,KAAuB;QAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;gBACvE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,CAAC,IAAI;wBAAE,SAAS;oBAC9D,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;oBAC5C,IAAI,EAAE,IAAI,OAAO,IAAI,EAAE,GAAG,KAAK;wBAAE,SAAS;oBAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;oBACpD,MAAM,GAAG,GAAG,GAAG,KAAK,SAAS,IAAI,EAAE,CAAC;oBACpC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAC5B,IAAI,IAAI,KAAK,SAAS;wBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;;wBAC7D,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,yFAAyF;IACjF,KAAK,CAAC,SAAS,CACrB,IAAc,EACd,KAAoB,EACpB,OAA6B,EAC7B,MAA2B,EAC3B,eAAe,GAAG,KAAK;QAEvB,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACjD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/C,OAAO,CAAC,MAAM,SAAS,CAAC,kBAAkB,CAAC;gBACzC,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACxD,QAAQ;gBACR,WAAW;gBACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7C,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7D,CAAC,CAA8B,CAAC;QACnC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACjC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,wEAAwE;AACxE,SAAS,YAAY,CACnB,IAAc,EACd,MAA0B,EAC1B,KAAyB;IAEzB,OAAO,IAAI,CAAC,SAAS;SAClB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QAChB,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,MAAM;YAAE,OAAO,KAAK,CAAC;QAChE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,KAAiB;IACvC,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1E,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC7F,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACpF,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACtF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAA4B,EAAE,KAAiB;IACxE,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACtE,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC,WAAW,KAAK,KAAK,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IACzF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAChF,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;IAC/F,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5D,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/E,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;IAC/E,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACvF,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC1C,IACE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;aACvB,WAAW,EAAE;aACb,QAAQ,CAAC,MAAM,CAAC;YACnB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EACpC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,88 @@
1
+ /** One immutable object (a Parquet file) in a cold location. */
2
+ export interface ColdObject {
3
+ /** Location-relative key, always `/`-separated. */
4
+ key: string;
5
+ /** Size in bytes. */
6
+ size: number;
7
+ }
8
+ /**
9
+ * The byte-level surface the Parquet cold store needs from where its files live.
10
+ * Two ship ({@link DirectoryLocation}, {@link S3Location}); anything else (GCS,
11
+ * Azure, a test double) implements these five calls.
12
+ *
13
+ * Files are written once and never modified, so implementations need no locking:
14
+ * a key either exists with its final bytes or does not exist.
15
+ */
16
+ export interface ColdObjectStore {
17
+ /** Every object whose key starts with `prefix` (location-relative). */
18
+ list(prefix: string): Promise<ColdObject[]>;
19
+ /** Bytes `[start, end)` of an object. `end` omitted means "to the end". */
20
+ read(key: string, start: number, end?: number): Promise<Uint8Array>;
21
+ /** Write a whole object. Must be atomic: readers never see a partial file. */
22
+ write(key: string, bytes: Uint8Array): Promise<void>;
23
+ /** Delete objects. Missing keys are not an error. */
24
+ delete(keys: string[]): Promise<void>;
25
+ /**
26
+ * The object's path on the local filesystem, when it has one. Engines that read
27
+ * files by path (DuckDB) use it directly; for remote locations they copy the
28
+ * object into a local cache first.
29
+ */
30
+ localPath?(key: string): string;
31
+ /** The directory every {@link localPath} lives under, when the location is local. */
32
+ readonly localRoot?: string;
33
+ }
34
+ /** A directory on the local filesystem (or a mounted volume). */
35
+ export declare class DirectoryLocation implements ColdObjectStore {
36
+ private readonly root;
37
+ readonly localRoot: string;
38
+ constructor(root: string);
39
+ list(prefix: string): Promise<ColdObject[]>;
40
+ private walk;
41
+ read(key: string, start: number, end?: number): Promise<Uint8Array>;
42
+ write(key: string, bytes: Uint8Array): Promise<void>;
43
+ delete(keys: string[]): Promise<void>;
44
+ localPath(key: string): string;
45
+ /** Whole-file read, used by tests and tooling. */
46
+ readAll(key: string): Promise<Uint8Array>;
47
+ }
48
+ /**
49
+ * The slice of `@aws-sdk/client-s3`'s `S3Client` the S3 location uses. The host
50
+ * passes its own configured client, so credentials, region, endpoint (GovCloud, a
51
+ * VPC endpoint, MinIO) and retry policy are the host's.
52
+ */
53
+ export interface S3ClientLike {
54
+ send(command: unknown): Promise<unknown>;
55
+ }
56
+ /** Options for {@link S3Location}. */
57
+ export interface S3LocationOptions {
58
+ /** The host's `S3Client`. */
59
+ client: S3ClientLike;
60
+ bucket: string;
61
+ /** Key prefix every file goes under, e.g. `telescope/v1`. A trailing `/` is added. */
62
+ prefix?: string;
63
+ }
64
+ /**
65
+ * An S3 bucket (or any S3-compatible store) through the host's own client. Reads are
66
+ * ranged `GetObject` calls, so a footer or a row group is fetched without the file.
67
+ */
68
+ export declare class S3Location implements ColdObjectStore {
69
+ private readonly options;
70
+ private readonly prefix;
71
+ private commands;
72
+ constructor(options: S3LocationOptions);
73
+ private sdk;
74
+ list(prefix: string): Promise<ColdObject[]>;
75
+ read(key: string, start: number, end?: number): Promise<Uint8Array>;
76
+ write(key: string, bytes: Uint8Array): Promise<void>;
77
+ delete(keys: string[]): Promise<void>;
78
+ }
79
+ /**
80
+ * Import an optional peer dependency, turning "module not found" into an error
81
+ * that names the package and the config that needs it. Anything else (a broken
82
+ * native binding, a syntax error) is rethrown as-is.
83
+ */
84
+ export declare function importOptionalPeer<T>(name: string, neededBy: string, importer: () => Promise<T>): Promise<T>;
85
+ export declare function isNotFound(error: unknown): boolean;
86
+ /** Make sure a directory exists (used for the DuckDB local file cache). */
87
+ export declare function ensureDir(path: string): Promise<void>;
88
+ //# sourceMappingURL=parquet_location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parquet_location.d.ts","sourceRoot":"","sources":["../../../src/stores/parquet_location.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,194 @@
1
+ import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
2
+ import { dirname, join, relative, sep } from 'node:path';
3
+ /** A directory on the local filesystem (or a mounted volume). */
4
+ export class DirectoryLocation {
5
+ root;
6
+ localRoot;
7
+ constructor(root) {
8
+ this.root = root;
9
+ this.localRoot = root;
10
+ }
11
+ async list(prefix) {
12
+ const out = [];
13
+ // Walk only the deepest existing directory the prefix names, not the whole root.
14
+ const slash = prefix.lastIndexOf('/');
15
+ const start = slash >= 0 ? prefix.slice(0, slash) : '';
16
+ await this.walk(join(this.root, start), prefix, out);
17
+ return out;
18
+ }
19
+ async walk(dir, prefix, out) {
20
+ let names;
21
+ try {
22
+ names = await readdir(dir, { withFileTypes: true });
23
+ }
24
+ catch (error) {
25
+ if (isNotFound(error))
26
+ return;
27
+ throw error;
28
+ }
29
+ for (const dirent of names) {
30
+ const full = join(dir, dirent.name);
31
+ if (dirent.isDirectory()) {
32
+ await this.walk(full, prefix, out);
33
+ continue;
34
+ }
35
+ if (!dirent.isFile() || !dirent.name.endsWith('.parquet'))
36
+ continue;
37
+ const key = relative(this.root, full).split(sep).join('/');
38
+ if (!key.startsWith(prefix))
39
+ continue;
40
+ try {
41
+ out.push({ key, size: (await stat(full)).size });
42
+ }
43
+ catch (error) {
44
+ // Deleted between readdir and stat (retention or compaction on another tick).
45
+ if (!isNotFound(error))
46
+ throw error;
47
+ }
48
+ }
49
+ }
50
+ async read(key, start, end) {
51
+ const { open } = await import('node:fs/promises');
52
+ const handle = await open(this.localPath(key), 'r');
53
+ try {
54
+ const last = end ?? (await handle.stat()).size;
55
+ const length = Math.max(0, last - start);
56
+ const buffer = new Uint8Array(length);
57
+ let offset = 0;
58
+ while (offset < length) {
59
+ const { bytesRead } = await handle.read(buffer, offset, length - offset, start + offset);
60
+ if (bytesRead === 0)
61
+ break;
62
+ offset += bytesRead;
63
+ }
64
+ return offset === length ? buffer : buffer.subarray(0, offset);
65
+ }
66
+ finally {
67
+ await handle.close();
68
+ }
69
+ }
70
+ async write(key, bytes) {
71
+ const target = this.localPath(key);
72
+ await mkdir(dirname(target), { recursive: true });
73
+ // Write-then-rename so a concurrent reader's directory walk never sees a partial file
74
+ // (the temp name does not end in `.parquet`, so `list` skips it).
75
+ const temp = `${target}.${process.pid}.tmp`;
76
+ await writeFile(temp, bytes);
77
+ await rename(temp, target);
78
+ }
79
+ async delete(keys) {
80
+ for (const key of keys) {
81
+ await rm(this.localPath(key), { force: true });
82
+ }
83
+ }
84
+ localPath(key) {
85
+ return join(this.root, ...key.split('/'));
86
+ }
87
+ /** Whole-file read, used by tests and tooling. */
88
+ readAll(key) {
89
+ return readFile(this.localPath(key));
90
+ }
91
+ }
92
+ /**
93
+ * An S3 bucket (or any S3-compatible store) through the host's own client. Reads are
94
+ * ranged `GetObject` calls, so a footer or a row group is fetched without the file.
95
+ */
96
+ export class S3Location {
97
+ options;
98
+ prefix;
99
+ commands = null;
100
+ constructor(options) {
101
+ this.options = options;
102
+ const raw = options.prefix ?? '';
103
+ this.prefix = raw === '' || raw.endsWith('/') ? raw : `${raw}/`;
104
+ }
105
+ async sdk() {
106
+ if (this.commands === null) {
107
+ this.commands = await importOptionalPeer('@aws-sdk/client-s3', 'the S3 location of storage.parquet()', () => import('@aws-sdk/client-s3'));
108
+ }
109
+ return this.commands;
110
+ }
111
+ async list(prefix) {
112
+ const { ListObjectsV2Command } = await this.sdk();
113
+ const out = [];
114
+ let token;
115
+ do {
116
+ const page = (await this.options.client.send(new ListObjectsV2Command({
117
+ Bucket: this.options.bucket,
118
+ Prefix: this.prefix + prefix,
119
+ ...(token !== undefined ? { ContinuationToken: token } : {}),
120
+ })));
121
+ for (const object of page.Contents ?? []) {
122
+ if (object.Key === undefined || !object.Key.endsWith('.parquet'))
123
+ continue;
124
+ out.push({ key: object.Key.slice(this.prefix.length), size: object.Size ?? 0 });
125
+ }
126
+ token = page.IsTruncated ? page.NextContinuationToken : undefined;
127
+ } while (token !== undefined);
128
+ return out;
129
+ }
130
+ async read(key, start, end) {
131
+ const { GetObjectCommand } = await this.sdk();
132
+ if (end !== undefined && end <= start)
133
+ return new Uint8Array(0);
134
+ const range = end === undefined ? `bytes=${start}-` : `bytes=${start}-${end - 1}`;
135
+ const response = (await this.options.client.send(new GetObjectCommand({ Bucket: this.options.bucket, Key: this.prefix + key, Range: range })));
136
+ if (!response.Body)
137
+ return new Uint8Array(0);
138
+ return response.Body.transformToByteArray();
139
+ }
140
+ async write(key, bytes) {
141
+ const { PutObjectCommand } = await this.sdk();
142
+ await this.options.client.send(new PutObjectCommand({
143
+ Bucket: this.options.bucket,
144
+ Key: this.prefix + key,
145
+ Body: bytes,
146
+ ContentType: 'application/vnd.apache.parquet',
147
+ }));
148
+ }
149
+ async delete(keys) {
150
+ if (keys.length === 0)
151
+ return;
152
+ const { DeleteObjectsCommand } = await this.sdk();
153
+ for (let i = 0; i < keys.length; i += 1000) {
154
+ await this.options.client.send(new DeleteObjectsCommand({
155
+ Bucket: this.options.bucket,
156
+ Delete: { Objects: keys.slice(i, i + 1000).map((key) => ({ Key: this.prefix + key })) },
157
+ }));
158
+ }
159
+ }
160
+ }
161
+ /**
162
+ * Import an optional peer dependency, turning "module not found" into an error
163
+ * that names the package and the config that needs it. Anything else (a broken
164
+ * native binding, a syntax error) is rethrown as-is.
165
+ */
166
+ export async function importOptionalPeer(name, neededBy, importer) {
167
+ try {
168
+ return await importer();
169
+ }
170
+ catch (error) {
171
+ if (isModuleNotFound(error, name)) {
172
+ throw new Error(`@adonis-agora/telescope: ${neededBy} needs the optional peer dependency "${name}", which is not installed. Install it (e.g. \`npm install ${name}\`) or choose a different option.`, { cause: error });
173
+ }
174
+ throw error;
175
+ }
176
+ }
177
+ function isModuleNotFound(error, name) {
178
+ if (typeof error !== 'object' || error === null)
179
+ return false;
180
+ const code = error.code;
181
+ const message = String(error.message ?? '');
182
+ return (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') && message.includes(name);
183
+ }
184
+ export function isNotFound(error) {
185
+ if (typeof error !== 'object' || error === null)
186
+ return false;
187
+ const { code, name } = error;
188
+ return code === 'ENOENT' || name === 'NoSuchKey' || name === 'NotFound';
189
+ }
190
+ /** Make sure a directory exists (used for the DuckDB local file cache). */
191
+ export async function ensureDir(path) {
192
+ await mkdir(path, { recursive: true });
193
+ }
194
+ //# sourceMappingURL=parquet_location.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parquet_location.js","sourceRoot":"","sources":["../../../src/stores/parquet_location.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import type { Entry, RecordInput } from '../entry.js';
2
+ import type { BucketCountQuery, BucketCountRow, EntryQuery, TelescopeStore, TraceIdQuery, TraceIdRow } from '../store.js';
3
+ import { type ParquetColdStore } from './parquet.js';
4
+ /** Where the tiered store reports cold-tier trouble. Defaults to `console`. */
5
+ export interface TieredStoreLogger {
6
+ warn(message: string): void;
7
+ }
8
+ /** Options for {@link TieredTelescopeStore}. */
9
+ export interface TieredStoreOptions {
10
+ /** The live store every entry is recorded into, e.g. the app's database via Lucid. */
11
+ hot: TelescopeStore;
12
+ /** Where entries go once they are older than {@link hotForMs}. */
13
+ cold: ParquetColdStore;
14
+ /** How long an entry stays in the hot store, in ms. */
15
+ hotForMs: number;
16
+ /** Hot entries read per page while moving them to cold. Default 5,000. */
17
+ moveBatchSize?: number;
18
+ /** Entries buffered before a move writes them out as files. Default 50,000. */
19
+ moveFlushSize?: number;
20
+ /** Merge each closed hour's small files during prune. Default `true`. */
21
+ compact?: boolean;
22
+ logger?: TieredStoreLogger;
23
+ }
24
+ /** What the most recent {@link TieredTelescopeStore.prune} did. */
25
+ export interface TieredPruneReport {
26
+ /** Hot entries written to the cold tier. */
27
+ moved: number;
28
+ /** Entries deleted from the hot tier (moved ones included). */
29
+ hotDeleted: number;
30
+ /** Cold rows deleted by retention. */
31
+ coldExpired: number;
32
+ /** Cold files replaced by compaction. */
33
+ compactedFiles: number;
34
+ /** A cold-tier failure during the cycle, when there was one. */
35
+ error?: string;
36
+ }
37
+ /**
38
+ * A two-tier {@link TelescopeStore}: a hot store kept minutes deep and a Parquet cold
39
+ * tier for everything older.
40
+ *
41
+ * - **Writes** only reach the hot store.
42
+ * - **`prune(olderThan, keepLast)`** first moves hot entries older than
43
+ * `now - hotFor` (and newer than `olderThan`) to cold, deleting them from hot only
44
+ * after the files are written; then applies the retention cutoff to the cold tier
45
+ * (whole hourly files); then compacts closed hours. A failed write deletes the files
46
+ * it wrote and leaves the hot store untouched, so the next cycle retries.
47
+ * - **Reads** go to hot first and to cold for whatever the answer still needs, merged
48
+ * newest-first without duplicate ids, so `{ page, size }` pages straight across the
49
+ * tier boundary. If the cold tier cannot be read, hot results are returned and a
50
+ * warning is logged; the dashboard never fails because of the cold tier.
51
+ */
52
+ export declare class TieredTelescopeStore implements TelescopeStore {
53
+ readonly hot: TelescopeStore;
54
+ readonly cold: ParquetColdStore;
55
+ private readonly hotForMs;
56
+ private readonly moveBatchSize;
57
+ private readonly moveFlushSize;
58
+ private readonly compactEnabled;
59
+ private readonly logger;
60
+ private lastWarnAt;
61
+ private report;
62
+ constructor(options: TieredStoreOptions);
63
+ record<TContent>(input: RecordInput<TContent>): Promise<Entry<TContent>>;
64
+ get(id: string): Promise<Entry | null>;
65
+ list(query?: EntryQuery): Promise<Entry[]>;
66
+ count(): Promise<number>;
67
+ /**
68
+ * The union's top traces: each tier's top `offset + size` by last-seen, merged by the
69
+ * newer of the two timestamps. A trace in the union's top N is necessarily in the top
70
+ * N of the tier where it was last seen, so nothing is missed.
71
+ */
72
+ listTraceIds(query: TraceIdQuery): Promise<TraceIdRow[]>;
73
+ countByBucket(query: BucketCountQuery): Promise<BucketCountRow[]>;
74
+ prune(olderThan: Date, keepLast?: number): Promise<number>;
75
+ /** What the last prune cycle moved, deleted and compacted (null before the first). */
76
+ lastPrune(): TieredPruneReport | null;
77
+ clear(): Promise<void>;
78
+ /** Release the cold engine (DuckDB holds a native instance). */
79
+ close(): Promise<void>;
80
+ /**
81
+ * Copy hot entries in `[after, before)` to cold. Pages are offset-based over a fixed
82
+ * window that nothing is deleted from until the whole move succeeded, so no entry is
83
+ * skipped; entries reach the window only by ageing past `before`, after this cycle's
84
+ * snapshot. Resolves to the number of entries written.
85
+ */
86
+ private moveToCold;
87
+ private bucketsFromHotList;
88
+ /** Run a cold read; on failure log (at most once a minute) and use `fallback`. */
89
+ private coldRead;
90
+ }
91
+ //# sourceMappingURL=tiered.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiered.d.ts","sourceRoot":"","sources":["../../../src/stores/tiered.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,cAAc,EACd,YAAY,EACZ,UAAU,EACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGvE,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,sFAAsF;IACtF,GAAG,EAAE,cAAc,CAAC;IACpB,kEAAkE;IAClE,IAAI,EAAE,gBAAgB,CAAC;IACvB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAAkC;IAEhD,YAAY,OAAO,EAAE,kBAAkB,EAWtC;IAED,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAEvE;IAEK,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAI3C;IAEK,IAAI,CAAC,KAAK,GAAE,UAAe,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CA0BnD;IAEK,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAM7B;IAED;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyB7D;IAEK,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAatE;IAEK,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B/D;IAED,sFAAsF;IACtF,SAAS,IAAI,iBAAiB,GAAG,IAAI,CAEpC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,gEAAgE;IAC1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED;;;;;OAKG;YACW,UAAU;YA0BV,kBAAkB;IAmBhC,kFAAkF;YACpE,QAAQ;CAcvB"}