@gscdump/engine 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/inspection.d.mts +66 -11
- package/dist/entities/inspection.mjs +170 -24
- package/dist/entities.d.mts +3 -3
- package/dist/entities.mjs +3 -3
- package/dist/entity-keys.d.mts +12 -0
- package/dist/entity-keys.mjs +7 -1
- package/package.json +4 -4
|
@@ -200,16 +200,25 @@ export interface InspectionStore {
|
|
|
200
200
|
rowCount: number;
|
|
201
201
|
}>;
|
|
202
202
|
/**
|
|
203
|
-
* Fold every outstanding event file into
|
|
204
|
-
*
|
|
205
|
-
* `firstCheckedAt` per url.
|
|
206
|
-
*
|
|
207
|
-
* re-runnable: a crash after the base write but before the delete just
|
|
208
|
-
* re-folds the same events (newest-wins makes that a no-op). A real read
|
|
209
|
-
* failure on the existing base propagates rather than rebuilding from events
|
|
210
|
-
* alone (which would drop URLs only the base held).
|
|
203
|
+
* Fold every outstanding event file into a new base: latest-per-url by max
|
|
204
|
+
* `inspectedAt` (newest-wins), preserving the earliest non-null
|
|
205
|
+
* `firstCheckedAt` per url. The first fold reads the legacy in-place
|
|
206
|
+
* `base.parquet`; later folds read the base the manifest names.
|
|
211
207
|
*
|
|
212
|
-
*
|
|
208
|
+
* Writes the new base under a new immutable key, then publishes the inspection
|
|
209
|
+
* base manifest that names it. The superseded base and the folded event files
|
|
210
|
+
* are retired, not deleted: reads that resolved the previous manifest keep
|
|
211
|
+
* scanning them. A later compaction deletes each retired object once the
|
|
212
|
+
* grace has passed. It also deletes a base that an interrupted compaction
|
|
213
|
+
* wrote but never published. File-level only, never row-level (ADR-0002).
|
|
214
|
+
*
|
|
215
|
+
* Callers serialize compaction per site. Re-runnable: a crash before the
|
|
216
|
+
* manifest write leaves the previous manifest current, and the retry
|
|
217
|
+
* re-folds the same events. A real read failure on the current base
|
|
218
|
+
* propagates rather than rebuilding from events alone.
|
|
219
|
+
*
|
|
220
|
+
* `eventFilesDeleted` counts event files this run deleted, which an earlier
|
|
221
|
+
* run folded. No-op when no event file exists.
|
|
213
222
|
*/
|
|
214
223
|
compactInspections: (ctx: TenantCtx, opts?: {
|
|
215
224
|
/**
|
|
@@ -224,8 +233,9 @@ export interface InspectionStore {
|
|
|
224
233
|
transitionsWritten: number;
|
|
225
234
|
}>;
|
|
226
235
|
/**
|
|
227
|
-
*
|
|
228
|
-
* canonical pair it already retains. Outstanding events must be compacted
|
|
236
|
+
* Publish a copy of the current base with the canonical kind derived from the
|
|
237
|
+
* canonical pair it already retains. Outstanding events must be compacted
|
|
238
|
+
* first. Like compaction, it writes a new immutable base and retires the old one.
|
|
229
239
|
*/
|
|
230
240
|
backfillCanonicalMismatchKinds: (ctx: TenantCtx) => Promise<{
|
|
231
241
|
baseRowCount: number;
|
|
@@ -246,5 +256,50 @@ export interface InspectionStore {
|
|
|
246
256
|
}
|
|
247
257
|
export interface CreateInspectionStoreOptions {
|
|
248
258
|
dataSource: DataSource;
|
|
259
|
+
/** Clock for retirement times and the grace check. Defaults to `Date.now`. */
|
|
260
|
+
now?: () => number;
|
|
261
|
+
/** How long a retired object stays readable. Defaults to {@link INSPECTION_RETIRED_GRACE_MS}. */
|
|
262
|
+
graceMs?: number;
|
|
249
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* How long compaction keeps a superseded base or a folded event file after it
|
|
266
|
+
* retires it. Every read must finish within this window after it resolves its
|
|
267
|
+
* {@link InspectionReadPlan}.
|
|
268
|
+
*
|
|
269
|
+
* The longest hosted reader is a queue job that holds one plan across several
|
|
270
|
+
* DuckDB queries. The Workers queue wall clock caps that job at 15 minutes, so
|
|
271
|
+
* one hour leaves a wide margin.
|
|
272
|
+
*/
|
|
273
|
+
export declare const INSPECTION_RETIRED_GRACE_MS: number;
|
|
274
|
+
/**
|
|
275
|
+
* The base one read scans.
|
|
276
|
+
*
|
|
277
|
+
* - `legacy`: no manifest exists yet. The key is the in-place base an older
|
|
278
|
+
* engine wrote, which may be absent. It stays readable until the first
|
|
279
|
+
* compaction under the manifest retires it.
|
|
280
|
+
* - `published`: an immutable base the manifest names. It never changes, and it
|
|
281
|
+
* exists for at least the grace after a later manifest supersedes it.
|
|
282
|
+
*/
|
|
283
|
+
export type InspectionBaseRef = {
|
|
284
|
+
_tag: 'legacy';
|
|
285
|
+
key: string;
|
|
286
|
+
} | {
|
|
287
|
+
_tag: 'published';
|
|
288
|
+
key: string;
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* What one read scans. Resolve it once per read, then list event files, then
|
|
292
|
+
* scan. Skip each listed event key in `foldedEventKeys`: the base already holds
|
|
293
|
+
* its rows, and the file remains only for reads that resolved an older plan.
|
|
294
|
+
*/
|
|
295
|
+
export interface InspectionReadPlan {
|
|
296
|
+
base: InspectionBaseRef;
|
|
297
|
+
foldedEventKeys: ReadonlySet<string>;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Resolve the base a read scans and the event files it must skip. Reads one
|
|
301
|
+
* small manifest object; never the base itself. Throws when the manifest is
|
|
302
|
+
* corrupt, because no base choice is safe then.
|
|
303
|
+
*/
|
|
304
|
+
export declare function resolveInspectionReadPlan(source: Pick<DataSource, 'read'>, ctx: TenantCtx): Promise<InspectionReadPlan>;
|
|
250
305
|
export declare function createInspectionStore(opts: CreateInspectionStoreOptions): InspectionStore;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionParquetKey, inspectionTransitionsMonthKey } from "../entity-keys.mjs";
|
|
1
|
+
import { inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionParquetKey, inspectionTransitionsMonthKey } from "../entity-keys.mjs";
|
|
2
2
|
import { readOptional } from "../adapters/read-optional.mjs";
|
|
3
3
|
import { decodeParquetToRows, encodeRowsToParquetFlex } from "../adapters/hyparquet.mjs";
|
|
4
4
|
import { mapEntityIo } from "./io.mjs";
|
|
@@ -6,8 +6,82 @@ import { encodeJsonBigintSafe } from "@gscdump/lakehouse/bigint";
|
|
|
6
6
|
import { GSCDUMP_INDEXING_TRANSITION_FIELDS } from "@gscdump/contracts";
|
|
7
7
|
import { classifyCanonicalDifference } from "gscdump";
|
|
8
8
|
const YEAR_MONTH_RE = /^(\d{4})-(\d{2})-/;
|
|
9
|
-
const INSPECTION_EVENT_KEY_RE = /\/inspections\/events\/\d{4}-\d{2}\/[^/]+\.parquet$/;
|
|
10
9
|
const INSPECTION_HISTORY_MAX_BYTES = 5242880;
|
|
10
|
+
const INSPECTION_RETIRED_GRACE_MS = 36e5;
|
|
11
|
+
const EVENT_FILE_RE = /^\d{4}-\d{2}\/[^/]+\.parquet$/;
|
|
12
|
+
const IMMUTABLE_BASE_FILE_RE = /^(\d{13,})__[\w-]+\.parquet$/;
|
|
13
|
+
function isInspectionEventKey(ctx, key) {
|
|
14
|
+
const prefix = `${inspectionEventsPrefix(ctx)}/`;
|
|
15
|
+
return key.startsWith(prefix) && EVENT_FILE_RE.test(key.slice(prefix.length));
|
|
16
|
+
}
|
|
17
|
+
function immutableBaseKey(ctx, writtenAt, id) {
|
|
18
|
+
return `${inspectionBasesPrefix(ctx)}/${String(writtenAt).padStart(13, "0")}__${id}.parquet`;
|
|
19
|
+
}
|
|
20
|
+
function immutableBaseWrittenAt(ctx, key) {
|
|
21
|
+
const prefix = `${inspectionBasesPrefix(ctx)}/`;
|
|
22
|
+
if (!key.startsWith(prefix)) return void 0;
|
|
23
|
+
const match = IMMUTABLE_BASE_FILE_RE.exec(key.slice(prefix.length));
|
|
24
|
+
return match ? Number(match[1]) : void 0;
|
|
25
|
+
}
|
|
26
|
+
function invalidManifest(key, reason) {
|
|
27
|
+
throw new Error(`invalid inspection base manifest ${key}: ${reason}`);
|
|
28
|
+
}
|
|
29
|
+
function parseBaseManifest(ctx, key, bytes) {
|
|
30
|
+
let input;
|
|
31
|
+
try {
|
|
32
|
+
input = JSON.parse(new TextDecoder().decode(bytes));
|
|
33
|
+
} catch {
|
|
34
|
+
return invalidManifest(key, "not JSON");
|
|
35
|
+
}
|
|
36
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return invalidManifest(key, "not an object");
|
|
37
|
+
const manifest = input;
|
|
38
|
+
if (manifest.version !== 1) return invalidManifest(key, `unknown version ${String(manifest.version)}`);
|
|
39
|
+
const baseKey = manifest.baseKey;
|
|
40
|
+
if (typeof baseKey !== "string" || immutableBaseWrittenAt(ctx, baseKey) === void 0) return invalidManifest(key, "base key is not an immutable base of this tenant");
|
|
41
|
+
if (!Array.isArray(manifest.retired)) return invalidManifest(key, "retired is not an array");
|
|
42
|
+
return {
|
|
43
|
+
version: 1,
|
|
44
|
+
baseKey,
|
|
45
|
+
retired: manifest.retired.map((entry) => {
|
|
46
|
+
if (!entry || typeof entry !== "object") return invalidManifest(key, "retired entry is not an object");
|
|
47
|
+
const { key: retiredKey, retiredAt } = entry;
|
|
48
|
+
if (typeof retiredKey !== "string" || retiredKey === baseKey || !(retiredKey === inspectionBaseKey(ctx) || immutableBaseWrittenAt(ctx, retiredKey) !== void 0 || isInspectionEventKey(ctx, retiredKey))) return invalidManifest(key, `retired key ${String(retiredKey)} is not a superseded inspection file`);
|
|
49
|
+
if (typeof retiredAt !== "number" || !Number.isSafeInteger(retiredAt) || retiredAt < 0) return invalidManifest(key, `retired time for ${retiredKey} is invalid`);
|
|
50
|
+
return {
|
|
51
|
+
key: retiredKey,
|
|
52
|
+
retiredAt
|
|
53
|
+
};
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function readBaseState(source, ctx) {
|
|
58
|
+
const key = inspectionBaseManifestKey(ctx);
|
|
59
|
+
const bytes = await readOptional(source, key);
|
|
60
|
+
return bytes ? {
|
|
61
|
+
_tag: "published",
|
|
62
|
+
manifest: parseBaseManifest(ctx, key, bytes)
|
|
63
|
+
} : {
|
|
64
|
+
_tag: "legacy",
|
|
65
|
+
key: inspectionBaseKey(ctx)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function resolveInspectionReadPlan(source, ctx) {
|
|
69
|
+
const state = await readBaseState(source, ctx);
|
|
70
|
+
if (state._tag === "legacy") return {
|
|
71
|
+
base: {
|
|
72
|
+
_tag: "legacy",
|
|
73
|
+
key: state.key
|
|
74
|
+
},
|
|
75
|
+
foldedEventKeys: /* @__PURE__ */ new Set()
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
base: {
|
|
79
|
+
_tag: "published",
|
|
80
|
+
key: state.manifest.baseKey
|
|
81
|
+
},
|
|
82
|
+
foldedEventKeys: new Set(state.manifest.retired.map((entry) => entry.key).filter((key) => isInspectionEventKey(ctx, key)))
|
|
83
|
+
};
|
|
84
|
+
}
|
|
11
85
|
const INSPECTION_PARQUET_COLUMNS = [
|
|
12
86
|
{
|
|
13
87
|
name: "urlHash",
|
|
@@ -246,8 +320,40 @@ async function appendTransitions(ds, ctx, rows) {
|
|
|
246
320
|
function transitionMonth(row) {
|
|
247
321
|
return String(row.changedBefore ?? "").slice(0, 7) || "unknown";
|
|
248
322
|
}
|
|
323
|
+
const EMPTY_COMPACTION = {
|
|
324
|
+
baseRowCount: 0,
|
|
325
|
+
eventsFolded: 0,
|
|
326
|
+
eventFilesDeleted: 0,
|
|
327
|
+
transitionsWritten: 0
|
|
328
|
+
};
|
|
249
329
|
function createInspectionStore(opts) {
|
|
250
330
|
const ds = opts.dataSource;
|
|
331
|
+
const now = () => Math.floor((opts.now ?? Date.now)());
|
|
332
|
+
const graceMs = opts.graceMs ?? 36e5;
|
|
333
|
+
async function writeImmutableBase(ctx, bytes) {
|
|
334
|
+
const key = immutableBaseKey(ctx, now(), randomBatchId());
|
|
335
|
+
await ds.write(key, bytes);
|
|
336
|
+
return key;
|
|
337
|
+
}
|
|
338
|
+
async function publishManifest(ctx, manifest) {
|
|
339
|
+
await ds.write(inspectionBaseManifestKey(ctx), encodeJsonBigintSafe(manifest));
|
|
340
|
+
}
|
|
341
|
+
async function sweepRetired(ctx, retired, live, at) {
|
|
342
|
+
const retiredKeys = new Set(retired.map((entry) => entry.key));
|
|
343
|
+
const expired = retired.filter((entry) => entry.retiredAt + graceMs <= at).map((entry) => entry.key);
|
|
344
|
+
const unpublished = (await ds.list(`${inspectionBasesPrefix(ctx)}/`)).filter((key) => {
|
|
345
|
+
const writtenAt = immutableBaseWrittenAt(ctx, key);
|
|
346
|
+
return writtenAt !== void 0 && !retiredKeys.has(key) && writtenAt + graceMs <= at;
|
|
347
|
+
});
|
|
348
|
+
const doomed = [...expired, ...unpublished].filter((key) => !live.has(key));
|
|
349
|
+
if (doomed.length > 0) await ds.delete(doomed);
|
|
350
|
+
return new Set(doomed);
|
|
351
|
+
}
|
|
352
|
+
function countEventKeys(ctx, keys) {
|
|
353
|
+
let count = 0;
|
|
354
|
+
for (const key of keys) if (isInspectionEventKey(ctx, key)) count++;
|
|
355
|
+
return count;
|
|
356
|
+
}
|
|
251
357
|
function shardFor(record) {
|
|
252
358
|
const m = YEAR_MONTH_RE.exec(record.inspectedAt);
|
|
253
359
|
return m ? `${m[1]}-${m[2]}` : "unknown";
|
|
@@ -358,15 +464,28 @@ function createInspectionStore(opts) {
|
|
|
358
464
|
};
|
|
359
465
|
},
|
|
360
466
|
async compactInspections(ctx, opts) {
|
|
361
|
-
const
|
|
362
|
-
if (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const baseKey =
|
|
467
|
+
const listed = (await ds.list(`${inspectionEventsPrefix(ctx)}/`)).filter((key) => isInspectionEventKey(ctx, key));
|
|
468
|
+
if (listed.length === 0) return EMPTY_COMPACTION;
|
|
469
|
+
const startedAt = now();
|
|
470
|
+
const state = await readBaseState(ds, ctx);
|
|
471
|
+
const retired = state._tag === "published" ? state.manifest.retired : [];
|
|
472
|
+
const retiredKeys = new Set(retired.map((entry) => entry.key));
|
|
473
|
+
const eventKeys = listed.filter((key) => !retiredKeys.has(key));
|
|
474
|
+
const baseKey = state._tag === "published" ? state.manifest.baseKey : state.key;
|
|
475
|
+
if (eventKeys.length === 0) {
|
|
476
|
+
const deleted = await sweepRetired(ctx, retired, /* @__PURE__ */ new Set([baseKey]), startedAt);
|
|
477
|
+
if (state._tag === "published" && retired.some((entry) => deleted.has(entry.key))) await publishManifest(ctx, {
|
|
478
|
+
version: 1,
|
|
479
|
+
baseKey,
|
|
480
|
+
retired: retired.filter((entry) => !deleted.has(entry.key))
|
|
481
|
+
});
|
|
482
|
+
return {
|
|
483
|
+
...EMPTY_COMPACTION,
|
|
484
|
+
eventFilesDeleted: countEventKeys(ctx, deleted)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
369
487
|
const baseBytes = await readOptional(ds, baseKey);
|
|
488
|
+
if (!baseBytes && state._tag === "published") throw new Error(`published inspection base missing: ${baseKey}`);
|
|
370
489
|
const baseRows = baseBytes ? await decodeParquetToRows(baseBytes) : [];
|
|
371
490
|
const latest = /* @__PURE__ */ new Map();
|
|
372
491
|
const earliestChecked = /* @__PURE__ */ new Map();
|
|
@@ -418,23 +537,43 @@ function createInspectionStore(opts) {
|
|
|
418
537
|
sortKey: ["urlHash"]
|
|
419
538
|
});
|
|
420
539
|
const transitionsWritten = opts?.transitions ? await appendTransitions(ds, ctx, transitions) : 0;
|
|
421
|
-
await
|
|
422
|
-
|
|
540
|
+
const nextBaseKey = await writeImmutableBase(ctx, bytes);
|
|
541
|
+
const deleted = await sweepRetired(ctx, retired, /* @__PURE__ */ new Set([baseKey, nextBaseKey]), startedAt);
|
|
542
|
+
const retiredAt = now();
|
|
543
|
+
await publishManifest(ctx, {
|
|
544
|
+
version: 1,
|
|
545
|
+
baseKey: nextBaseKey,
|
|
546
|
+
retired: [
|
|
547
|
+
...retired.filter((entry) => !deleted.has(entry.key)),
|
|
548
|
+
...baseBytes ? [{
|
|
549
|
+
key: baseKey,
|
|
550
|
+
retiredAt
|
|
551
|
+
}] : [],
|
|
552
|
+
...consumed.map((key) => ({
|
|
553
|
+
key,
|
|
554
|
+
retiredAt
|
|
555
|
+
}))
|
|
556
|
+
]
|
|
557
|
+
});
|
|
423
558
|
return {
|
|
424
559
|
baseRowCount: merged.length,
|
|
425
560
|
eventsFolded,
|
|
426
|
-
eventFilesDeleted:
|
|
561
|
+
eventFilesDeleted: countEventKeys(ctx, deleted),
|
|
427
562
|
transitionsWritten
|
|
428
563
|
};
|
|
429
564
|
},
|
|
430
565
|
async backfillCanonicalMismatchKinds(ctx) {
|
|
431
|
-
const
|
|
566
|
+
const state = await readBaseState(ds, ctx);
|
|
567
|
+
const baseKey = state._tag === "published" ? state.manifest.baseKey : state.key;
|
|
432
568
|
const baseBytes = await readOptional(ds, baseKey);
|
|
433
|
-
if (!baseBytes)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
569
|
+
if (!baseBytes) {
|
|
570
|
+
if (state._tag === "published") throw new Error(`published inspection base missing: ${baseKey}`);
|
|
571
|
+
return {
|
|
572
|
+
baseRowCount: 0,
|
|
573
|
+
rowsBackfilled: 0,
|
|
574
|
+
rewritten: false
|
|
575
|
+
};
|
|
576
|
+
}
|
|
438
577
|
const rows = await decodeParquetToRows(baseBytes);
|
|
439
578
|
let rowsBackfilled = 0;
|
|
440
579
|
for (const row of rows) if (populateCanonicalMismatchKind(row)) rowsBackfilled++;
|
|
@@ -443,10 +582,17 @@ function createInspectionStore(opts) {
|
|
|
443
582
|
rowsBackfilled: 0,
|
|
444
583
|
rewritten: false
|
|
445
584
|
};
|
|
446
|
-
await
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
585
|
+
await publishManifest(ctx, {
|
|
586
|
+
version: 1,
|
|
587
|
+
baseKey: await writeImmutableBase(ctx, encodeRowsToParquetFlex(rows, {
|
|
588
|
+
columns: INSPECTION_EVENT_COLUMNS,
|
|
589
|
+
sortKey: ["urlHash"]
|
|
590
|
+
})),
|
|
591
|
+
retired: [...state._tag === "published" ? state.manifest.retired : [], {
|
|
592
|
+
key: baseKey,
|
|
593
|
+
retiredAt: now()
|
|
594
|
+
}]
|
|
595
|
+
});
|
|
450
596
|
return {
|
|
451
597
|
baseRowCount: rows.length,
|
|
452
598
|
rowsBackfilled,
|
|
@@ -458,4 +604,4 @@ function createInspectionStore(opts) {
|
|
|
458
604
|
}
|
|
459
605
|
};
|
|
460
606
|
}
|
|
461
|
-
export { INSPECTION_HISTORY_MAX_BYTES, createInspectionStore };
|
|
607
|
+
export { INSPECTION_HISTORY_MAX_BYTES, INSPECTION_RETIRED_GRACE_MS, createInspectionStore, resolveInspectionReadPlan };
|
package/dist/entities.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CreateEmptyTypesStoreOptions, EmptyTypesDoc, EmptyTypesStore, createEmptyTypesStore } from "./entities/empty-types.mjs";
|
|
2
2
|
import { CreateIndexingMetadataStoreOptions, IndexingMetadataIndex, IndexingMetadataRecord, IndexingMetadataStore, createIndexingMetadataStore } from "./entities/indexing-metadata.mjs";
|
|
3
|
-
import { CreateInspectionStoreOptions, INSPECTION_HISTORY_MAX_BYTES, InspectionEventRow, InspectionHistoryShard, InspectionIndex, InspectionParquetRow, InspectionRecord, InspectionStore, createInspectionStore } from "./entities/inspection.mjs";
|
|
4
|
-
import { SitemapFeedIdentityResult, SitemapGenerationKey, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix } from "./entity-keys.mjs";
|
|
3
|
+
import { CreateInspectionStoreOptions, INSPECTION_HISTORY_MAX_BYTES, INSPECTION_RETIRED_GRACE_MS, InspectionBaseRef, InspectionEventRow, InspectionHistoryShard, InspectionIndex, InspectionParquetRow, InspectionReadPlan, InspectionRecord, InspectionStore, createInspectionStore, resolveInspectionReadPlan } from "./entities/inspection.mjs";
|
|
4
|
+
import { SitemapFeedIdentityResult, SitemapGenerationKey, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix } from "./entity-keys.mjs";
|
|
5
5
|
import { QueryDimDeps, QueryDimMeta, QueryDimRecord, QueryDimStore, buildQueryDimRecords, createQueryDimStore } from "./entities/query-dim.mjs";
|
|
6
6
|
import { CompleteSitemapGeneration, CompleteSitemapTraversal, CreateSitemapReadStoreOptions, CreateSitemapStoreOptions, DateRange, FinalizeSitemapGenerationResult, IterateSitemapGenerationUrlsOptions, IterateSitemapGenerationUrlsResult, ListSitemapGenerationUrlsOptions, ListSitemapGenerationUrlsResult, ParsedUrl, QuerySitemapGenerationMembershipResult, RecordSitemapLegacyImportResult, SitemapGenerationFeedManifest, SitemapGenerationReadResult, SitemapLegacyImportEvidence, SitemapMembershipEvent, SitemapMutation, SitemapReadStore, SitemapSiteGenerationManifest, SitemapStagedFeed, SitemapStore, SitemapUrlRecord, StageSitemapGenerationFeedResult } from "./entities/sitemap-shared.mjs";
|
|
7
7
|
import { createSitemapReadStore } from "./entities/sitemap.mjs";
|
|
8
8
|
import { CreateSitemapListStoreOptions, SitemapListContent, SitemapListDoc, SitemapListEntry, SitemapListStore, createSitemapListStore } from "./entities/sitemap-list.mjs";
|
|
9
9
|
import { createSitemapStore } from "./entities/sitemap-write.mjs";
|
|
10
|
-
export { type CompleteSitemapGeneration, type CompleteSitemapTraversal, type CreateEmptyTypesStoreOptions, type CreateIndexingMetadataStoreOptions, CreateInspectionStoreOptions, type CreateSitemapListStoreOptions, type CreateSitemapReadStoreOptions, type CreateSitemapStoreOptions, type DateRange, type EmptyTypesDoc, type EmptyTypesStore, type FinalizeSitemapGenerationResult, INSPECTION_HISTORY_MAX_BYTES, type IndexingMetadataIndex, type IndexingMetadataRecord, type IndexingMetadataStore, InspectionEventRow, InspectionHistoryShard, InspectionIndex, InspectionParquetRow, InspectionRecord, InspectionStore, type IterateSitemapGenerationUrlsOptions, type IterateSitemapGenerationUrlsResult, type ListSitemapGenerationUrlsOptions, type ListSitemapGenerationUrlsResult, type ParsedUrl, QueryDimDeps, QueryDimMeta, QueryDimRecord, QueryDimStore, type QuerySitemapGenerationMembershipResult, type RecordSitemapLegacyImportResult, SitemapFeedIdentityResult, type SitemapGenerationFeedManifest, SitemapGenerationKey, type SitemapGenerationReadResult, type SitemapLegacyImportEvidence, type SitemapListContent, type SitemapListDoc, type SitemapListEntry, type SitemapListStore, type SitemapMembershipEvent, type SitemapMutation, type SitemapReadStore, type SitemapSiteGenerationManifest, type SitemapStagedFeed, type SitemapStore, type SitemapUrlRecord, type StageSitemapGenerationFeedResult, buildQueryDimRecords, createEmptyTypesStore, createIndexingMetadataStore, createInspectionStore, createQueryDimStore, createSitemapListStore, createSitemapReadStore, createSitemapStore, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
|
10
|
+
export { type CompleteSitemapGeneration, type CompleteSitemapTraversal, type CreateEmptyTypesStoreOptions, type CreateIndexingMetadataStoreOptions, CreateInspectionStoreOptions, type CreateSitemapListStoreOptions, type CreateSitemapReadStoreOptions, type CreateSitemapStoreOptions, type DateRange, type EmptyTypesDoc, type EmptyTypesStore, type FinalizeSitemapGenerationResult, INSPECTION_HISTORY_MAX_BYTES, INSPECTION_RETIRED_GRACE_MS, type IndexingMetadataIndex, type IndexingMetadataRecord, type IndexingMetadataStore, InspectionBaseRef, InspectionEventRow, InspectionHistoryShard, InspectionIndex, InspectionParquetRow, InspectionReadPlan, InspectionRecord, InspectionStore, type IterateSitemapGenerationUrlsOptions, type IterateSitemapGenerationUrlsResult, type ListSitemapGenerationUrlsOptions, type ListSitemapGenerationUrlsResult, type ParsedUrl, QueryDimDeps, QueryDimMeta, QueryDimRecord, QueryDimStore, type QuerySitemapGenerationMembershipResult, type RecordSitemapLegacyImportResult, SitemapFeedIdentityResult, type SitemapGenerationFeedManifest, SitemapGenerationKey, type SitemapGenerationReadResult, type SitemapLegacyImportEvidence, type SitemapListContent, type SitemapListDoc, type SitemapListEntry, type SitemapListStore, type SitemapMembershipEvent, type SitemapMutation, type SitemapReadStore, type SitemapSiteGenerationManifest, type SitemapStagedFeed, type SitemapStore, type SitemapUrlRecord, type StageSitemapGenerationFeedResult, buildQueryDimRecords, createEmptyTypesStore, createIndexingMetadataStore, createInspectionStore, createQueryDimStore, createSitemapListStore, createSitemapReadStore, createSitemapStore, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, resolveInspectionReadPlan, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
package/dist/entities.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix } from "./entity-keys.mjs";
|
|
1
|
+
import { emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix } from "./entity-keys.mjs";
|
|
2
2
|
import { createEmptyTypesStore } from "./entities/empty-types.mjs";
|
|
3
3
|
import { createIndexingMetadataStore } from "./entities/indexing-metadata.mjs";
|
|
4
|
-
import { INSPECTION_HISTORY_MAX_BYTES, createInspectionStore } from "./entities/inspection.mjs";
|
|
4
|
+
import { INSPECTION_HISTORY_MAX_BYTES, INSPECTION_RETIRED_GRACE_MS, createInspectionStore, resolveInspectionReadPlan } from "./entities/inspection.mjs";
|
|
5
5
|
import { buildQueryDimRecords, createQueryDimStore } from "./entities/query-dim.mjs";
|
|
6
6
|
import { createSitemapReadStore } from "./entities/sitemap.mjs";
|
|
7
7
|
import { createSitemapListStore } from "./entities/sitemap-list.mjs";
|
|
8
8
|
import { createSitemapStore } from "./entities/sitemap-write.mjs";
|
|
9
|
-
export { INSPECTION_HISTORY_MAX_BYTES, buildQueryDimRecords, createEmptyTypesStore, createIndexingMetadataStore, createInspectionStore, createQueryDimStore, createSitemapListStore, createSitemapReadStore, createSitemapStore, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
|
9
|
+
export { INSPECTION_HISTORY_MAX_BYTES, INSPECTION_RETIRED_GRACE_MS, buildQueryDimRecords, createEmptyTypesStore, createIndexingMetadataStore, createInspectionStore, createQueryDimStore, createSitemapListStore, createSitemapReadStore, createSitemapStore, emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, resolveInspectionReadPlan, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
package/dist/entity-keys.d.mts
CHANGED
|
@@ -4,7 +4,19 @@ export declare function emptyTypesKey(ctx: TenantCtx): string;
|
|
|
4
4
|
export declare function inspectionParquetKey(ctx: TenantCtx): string;
|
|
5
5
|
export declare function inspectionEventsPrefix(ctx: TenantCtx): string;
|
|
6
6
|
export declare function inspectionEventKey(ctx: TenantCtx, yearMonth: string, batchId: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Names only the legacy base that compaction rewrote in place.
|
|
9
|
+
* Compaction now publishes immutable bases through the inspection base
|
|
10
|
+
* manifest. Resolve the current base with `resolveInspectionReadPlan`.
|
|
11
|
+
*/
|
|
7
12
|
export declare function inspectionBaseKey(ctx: TenantCtx): string;
|
|
13
|
+
/**
|
|
14
|
+
* The inspection base manifest: the mutable pointer to the current immutable
|
|
15
|
+
* base. Compaction writes it last, so it is the only publication point.
|
|
16
|
+
*/
|
|
17
|
+
export declare function inspectionBaseManifestKey(ctx: TenantCtx): string;
|
|
18
|
+
/** Directory of immutable inspection bases. Each compaction writes one new key. */
|
|
19
|
+
export declare function inspectionBasesPrefix(ctx: TenantCtx): string;
|
|
8
20
|
/**
|
|
9
21
|
* Append-only record of URL-inspection STATE CHANGES, partitioned by month.
|
|
10
22
|
*
|
package/dist/entity-keys.mjs
CHANGED
|
@@ -19,6 +19,12 @@ function inspectionEventKey(ctx, yearMonth, batchId) {
|
|
|
19
19
|
function inspectionBaseKey(ctx) {
|
|
20
20
|
return `${tenantEntityPrefix(ctx)}/inspections/base.parquet`;
|
|
21
21
|
}
|
|
22
|
+
function inspectionBaseManifestKey(ctx) {
|
|
23
|
+
return `${tenantEntityPrefix(ctx)}/inspections/base-manifest.json`;
|
|
24
|
+
}
|
|
25
|
+
function inspectionBasesPrefix(ctx) {
|
|
26
|
+
return `${tenantEntityPrefix(ctx)}/inspections/bases`;
|
|
27
|
+
}
|
|
22
28
|
function inspectionTransitionsPrefix(ctx) {
|
|
23
29
|
return `${tenantEntityPrefix(ctx)}/inspections/transitions`;
|
|
24
30
|
}
|
|
@@ -144,4 +150,4 @@ function queryDimParquetKey(ctx) {
|
|
|
144
150
|
function queryDimMetaKey(ctx) {
|
|
145
151
|
return `${queryDimPrefix(ctx)}/index.json`;
|
|
146
152
|
}
|
|
147
|
-
export { emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
|
153
|
+
export { emptyTypesKey, hashUrl, indexingMetadataIndexKey, inspectionBaseKey, inspectionBaseManifestKey, inspectionBasesPrefix, inspectionEventKey, inspectionEventsPrefix, inspectionHistoryPrefix, inspectionHistoryShardKey, inspectionIndexKey, inspectionParquetKey, inspectionTransitionsMonthKey, inspectionTransitionsPrefix, parseSitemapFeedIdentity, queryDimMetaKey, queryDimParquetKey, sitemapImmutableBaseKey, sitemapLegacyImportKey, sitemapListKey, sitemapPayloadHashV1, sitemapSiteGenerationManifestKey, sitemapSiteManifestKey, sitemapSiteManifestsPrefix, sitemapStagedFeedKey, sitemapStagedGenerationPrefix, sitemapUrlsEventKey, sitemapUrlsEventsPrefix, sitemapUrlsPrefix };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.3.0",
|
|
5
5
|
"description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -189,10 +189,10 @@
|
|
|
189
189
|
}
|
|
190
190
|
},
|
|
191
191
|
"dependencies": {
|
|
192
|
-
"@gscdump/contracts": "^5.
|
|
193
|
-
"@gscdump/lakehouse": "^5.
|
|
192
|
+
"@gscdump/contracts": "^5.3.0",
|
|
193
|
+
"@gscdump/lakehouse": "^5.3.0",
|
|
194
194
|
"drizzle-orm": "1.0.0-rc.4",
|
|
195
|
-
"gscdump": "^5.
|
|
195
|
+
"gscdump": "^5.3.0",
|
|
196
196
|
"pathe": "^2.0.3",
|
|
197
197
|
"proper-lockfile": "^4.1.2"
|
|
198
198
|
},
|