@chkit/plugin-ingest 0.2.0-beta.11
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/README.md +43 -0
- package/dist/destination.d.ts +40 -0
- package/dist/destination.d.ts.map +1 -0
- package/dist/destination.js +65 -0
- package/dist/destination.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +133 -0
- package/dist/errors.js.map +1 -0
- package/dist/executor.d.ts +30 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +552 -0
- package/dist/executor.js.map +1 -0
- package/dist/incremental.d.ts +45 -0
- package/dist/incremental.d.ts.map +1 -0
- package/dist/incremental.js +72 -0
- package/dist/incremental.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/journal-history.d.ts +15 -0
- package/dist/journal-history.d.ts.map +1 -0
- package/dist/journal-history.js +366 -0
- package/dist/journal-history.js.map +1 -0
- package/dist/journal-records.d.ts +28 -0
- package/dist/journal-records.d.ts.map +1 -0
- package/dist/journal-records.js +76 -0
- package/dist/journal-records.js.map +1 -0
- package/dist/journal.d.ts +16 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +72 -0
- package/dist/journal.js.map +1 -0
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +37 -0
- package/dist/loader.js.map +1 -0
- package/dist/paginate.d.ts +24 -0
- package/dist/paginate.d.ts.map +1 -0
- package/dist/paginate.js +37 -0
- package/dist/paginate.js.map +1 -0
- package/dist/plugin.d.ts +155 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +353 -0
- package/dist/plugin.js.map +1 -0
- package/dist/queue.d.ts +9 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +47 -0
- package/dist/queue.js.map +1 -0
- package/dist/recovery.d.ts +41 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +145 -0
- package/dist/recovery.js.map +1 -0
- package/dist/registry.d.ts +48 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +109 -0
- package/dist/registry.js.map +1 -0
- package/dist/retry.d.ts +12 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +69 -0
- package/dist/retry.js.map +1 -0
- package/dist/testing.d.ts +18 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +54 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
export function toJournalRow(event, targetId, at) {
|
|
3
|
+
const checkpointJson = event.checkpoint ? canonicalJson(event.checkpoint) : '';
|
|
4
|
+
const detailJson = canonicalJson(event.detail);
|
|
5
|
+
// Identity covers what makes the fact unique; the payload hash covers every
|
|
6
|
+
// authoritative field a retry of that same fact must reproduce. Only the
|
|
7
|
+
// physical append time (event_at) is excluded.
|
|
8
|
+
const eventId = digest([targetId, event.namespaceId, event.runId, String(event.eventSeq), event.eventKind, event.workId, event.batchId, String(event.attemptNo)]);
|
|
9
|
+
const payload = digest([
|
|
10
|
+
eventId,
|
|
11
|
+
String(event.expectedCheckpointVersion),
|
|
12
|
+
String(event.checkpointVersion),
|
|
13
|
+
checkpointJson,
|
|
14
|
+
event.workState,
|
|
15
|
+
event.sinkEvidence,
|
|
16
|
+
event.errorClass,
|
|
17
|
+
event.runId,
|
|
18
|
+
event.retryAt ? event.retryAt.toISOString() : '',
|
|
19
|
+
detailJson,
|
|
20
|
+
]);
|
|
21
|
+
return {
|
|
22
|
+
target_id: targetId,
|
|
23
|
+
namespace_id: event.namespaceId,
|
|
24
|
+
event_seq: String(event.eventSeq),
|
|
25
|
+
event_id: eventId,
|
|
26
|
+
payload_hash: BigInt(`0x${payload.slice(0, 16)}`).toString(),
|
|
27
|
+
event_at: toClickHouseDateTime(at),
|
|
28
|
+
event_kind: event.eventKind,
|
|
29
|
+
run_id: event.runId,
|
|
30
|
+
work_id: event.workId,
|
|
31
|
+
attempt_no: event.attemptNo,
|
|
32
|
+
batch_id: event.batchId,
|
|
33
|
+
expected_checkpoint_version: String(event.expectedCheckpointVersion),
|
|
34
|
+
checkpoint_version: String(event.checkpointVersion),
|
|
35
|
+
checkpoint_json: checkpointJson,
|
|
36
|
+
work_state: event.workState,
|
|
37
|
+
sink_evidence: event.sinkEvidence,
|
|
38
|
+
retry_at: event.retryAt ? toClickHouseDateTime(event.retryAt) : null,
|
|
39
|
+
error_class: event.errorClass,
|
|
40
|
+
detail_json: detailJson,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Stable key order so equal values always serialize identically. */
|
|
44
|
+
export function canonicalJson(value) {
|
|
45
|
+
// JSON.stringify(undefined) is undefined, not a string.
|
|
46
|
+
return JSON.stringify(sortKeys(value)) ?? 'null';
|
|
47
|
+
}
|
|
48
|
+
export function digest(parts) {
|
|
49
|
+
const hash = createHash('sha256');
|
|
50
|
+
for (const part of parts) {
|
|
51
|
+
hash.update(String(part.length));
|
|
52
|
+
hash.update(':');
|
|
53
|
+
hash.update(part);
|
|
54
|
+
}
|
|
55
|
+
return hash.digest('hex');
|
|
56
|
+
}
|
|
57
|
+
export function emptyCheckpoint() {
|
|
58
|
+
return { version: 0, envelope: undefined, checkpointId: '', successId: '', headSeq: 0, lastSuccessSeq: 0 };
|
|
59
|
+
}
|
|
60
|
+
function sortKeys(value) {
|
|
61
|
+
if (Array.isArray(value))
|
|
62
|
+
return value.map(sortKeys);
|
|
63
|
+
if (value instanceof Date)
|
|
64
|
+
return value.toISOString();
|
|
65
|
+
if (typeof value === 'object' && value !== null) {
|
|
66
|
+
return Object.fromEntries(Object.entries(value)
|
|
67
|
+
.filter(([, entry]) => entry !== undefined)
|
|
68
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
69
|
+
.map(([key, entry]) => [key, sortKeys(entry)]));
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
function toClickHouseDateTime(date) {
|
|
74
|
+
return date.toISOString().replace('T', ' ').replace('Z', '');
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=journal-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-records.js","sourceRoot":"","sources":["../src/journal-records.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AA2BxC,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,QAAgB,EAAE,EAAQ;IAC1E,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9E,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAC9C,4EAA4E;IAC5E,yEAAyE;IACzE,+CAA+C;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IACjK,MAAM,OAAO,GAAG,MAAM,CAAC;QACrB,OAAO;QACP,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC;QAC/B,cAAc;QACd,KAAK,CAAC,SAAS;QACf,KAAK,CAAC,YAAY;QAClB,KAAK,CAAC,UAAU;QAChB,KAAK,CAAC,KAAK;QACX,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;QAChD,UAAU;KACX,CAAC,CAAA;IACF,OAAO;QACL,SAAS,EAAE,QAAQ;QACnB,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;QACjC,QAAQ,EAAE,OAAO;QACjB,YAAY,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;QAC5D,QAAQ,EAAE,oBAAoB,CAAC,EAAE,CAAC;QAClC,UAAU,EAAE,KAAK,CAAC,SAAS;QAC3B,MAAM,EAAE,KAAK,CAAC,KAAK;QACnB,OAAO,EAAE,KAAK,CAAC,MAAM;QACrB,UAAU,EAAE,KAAK,CAAC,SAAS;QAC3B,QAAQ,EAAE,KAAK,CAAC,OAAO;QACvB,2BAA2B,EAAE,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC;QACpE,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC;QACnD,eAAe,EAAE,cAAc;QAC/B,UAAU,EAAE,KAAK,CAAC,SAAS;QAC3B,aAAa,EAAE,KAAK,CAAC,YAAY;QACjC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI;QACpE,WAAW,EAAE,KAAK,CAAC,UAAU;QAC7B,WAAW,EAAE,UAAU;KACxB,CAAA;AACH,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,wDAAwD;IACxD,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAwB;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QAChC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAA;AAC5G,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACpD,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;aAC1C,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CACjD,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAU;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;AAC9D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ClickHouseExecutor } from '@chkit/clickhouse';
|
|
2
|
+
import type { Journal } from './types.js';
|
|
3
|
+
export { canonicalJson, digest, emptyCheckpoint, toJournalRow, type JournalRow } from './journal-records.js';
|
|
4
|
+
export declare const DEFAULT_JOURNAL_TABLE = "_chkit_ingestion_journal";
|
|
5
|
+
export interface ClickHouseJournalOptions {
|
|
6
|
+
/** Must allow concurrent queries: use a stateless executor, not a session-bound one. */
|
|
7
|
+
executor: ClickHouseExecutor;
|
|
8
|
+
database: string;
|
|
9
|
+
targetId: string;
|
|
10
|
+
table?: string;
|
|
11
|
+
now?: () => Date;
|
|
12
|
+
}
|
|
13
|
+
/** Immutable run-scoped facts are projected from one ClickHouse snapshot. */
|
|
14
|
+
export declare function createClickHouseJournal(options: ClickHouseJournalOptions): Journal;
|
|
15
|
+
export declare function journalTableSql(qualified: string): string;
|
|
16
|
+
//# sourceMappingURL=journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAKzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAE5G,eAAO,MAAM,qBAAqB,6BAA6B,CAAA;AAG/D,MAAM,WAAW,wBAAwB;IACvC,wFAAwF;IACxF,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CA8BlF;AAMD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA0BzD"}
|
package/dist/journal.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { waitForTable } from '@chkit/clickhouse';
|
|
2
|
+
import { IngestConfigError } from './errors.js';
|
|
3
|
+
import { validateJournalHistory } from './journal-history.js';
|
|
4
|
+
import { digest, toJournalRow } from './journal-records.js';
|
|
5
|
+
export { canonicalJson, digest, emptyCheckpoint, toJournalRow } from './journal-records.js';
|
|
6
|
+
export const DEFAULT_JOURNAL_TABLE = '_chkit_ingestion_journal';
|
|
7
|
+
const TABLE_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8
|
+
/** Immutable run-scoped facts are projected from one ClickHouse snapshot. */
|
|
9
|
+
export function createClickHouseJournal(options) {
|
|
10
|
+
const table = options.table ?? DEFAULT_JOURNAL_TABLE;
|
|
11
|
+
validateTableName(table);
|
|
12
|
+
validateTableName(options.database);
|
|
13
|
+
const now = options.now ?? (() => new Date());
|
|
14
|
+
const qualified = `\`${options.database}\`.\`${table}\``;
|
|
15
|
+
return {
|
|
16
|
+
async ensure() {
|
|
17
|
+
await options.executor.command(journalTableSql(qualified));
|
|
18
|
+
await waitForTable(options.executor, options.database, table);
|
|
19
|
+
},
|
|
20
|
+
async append(events) {
|
|
21
|
+
if (events.length === 0)
|
|
22
|
+
return;
|
|
23
|
+
const at = now();
|
|
24
|
+
const rows = events.map((event) => toJournalRow(event, options.targetId, at));
|
|
25
|
+
await options.executor.insert({
|
|
26
|
+
table: `${options.database}.${table}`, values: rows,
|
|
27
|
+
settings: { insert_deduplication_token: digest(rows.flatMap((row) => [row.event_id, row.payload_hash])), async_insert: 0 },
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
async readCheckpoint(namespaceId) {
|
|
31
|
+
const rows = await options.executor.query(`SELECT * FROM ${qualified} WHERE target_id = ${sqlString(options.targetId)} AND namespace_id = ${sqlString(namespaceId)} ORDER BY run_id, event_seq, event_id, payload_hash`, { select_sequential_consistency: '1', use_query_cache: 0, output_format_json_quote_64bit_integers: 1 });
|
|
32
|
+
// A stale snapshot can cause replay, but its runs cannot overwrite the
|
|
33
|
+
// identities or checkpoint lineage of another run.
|
|
34
|
+
return validateJournalHistory(rows, namespaceId).checkpoint;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function validateTableName(name) {
|
|
39
|
+
if (!TABLE_NAME_PATTERN.test(name))
|
|
40
|
+
throw new IngestConfigError(`Invalid journal table or database name "${name}".`);
|
|
41
|
+
}
|
|
42
|
+
export function journalTableSql(qualified) {
|
|
43
|
+
return `CREATE TABLE IF NOT EXISTS ${qualified}
|
|
44
|
+
(
|
|
45
|
+
target_id LowCardinality(String),
|
|
46
|
+
namespace_id String,
|
|
47
|
+
event_seq UInt64,
|
|
48
|
+
event_id String,
|
|
49
|
+
payload_hash UInt64,
|
|
50
|
+
event_at DateTime64(6, 'UTC'),
|
|
51
|
+
event_kind LowCardinality(String),
|
|
52
|
+
run_id String,
|
|
53
|
+
work_id String,
|
|
54
|
+
attempt_no UInt32,
|
|
55
|
+
batch_id String,
|
|
56
|
+
expected_checkpoint_version UInt64,
|
|
57
|
+
checkpoint_version UInt64,
|
|
58
|
+
checkpoint_json String,
|
|
59
|
+
work_state LowCardinality(String),
|
|
60
|
+
sink_evidence LowCardinality(String),
|
|
61
|
+
retry_at Nullable(DateTime64(6, 'UTC')),
|
|
62
|
+
error_class LowCardinality(String),
|
|
63
|
+
detail_json String
|
|
64
|
+
)
|
|
65
|
+
ENGINE = MergeTree
|
|
66
|
+
PARTITION BY toYYYYMM(event_at)
|
|
67
|
+
ORDER BY (target_id, namespace_id, event_seq, event_id)`;
|
|
68
|
+
}
|
|
69
|
+
function sqlString(value) {
|
|
70
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA2B,MAAM,mBAAmB,CAAA;AAEzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,MAAM,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAA;AAG5E,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAA;AAE5G,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAA;AAC/D,MAAM,kBAAkB,GAAG,0BAA0B,CAAA;AAWrD,6EAA6E;AAC7E,MAAM,UAAU,uBAAuB,CAAC,OAAiC;IACvE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,qBAAqB,CAAA;IACpD,iBAAiB,CAAC,KAAK,CAAC,CAAA;IACxB,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IAC7C,MAAM,SAAS,GAAG,KAAK,OAAO,CAAC,QAAQ,QAAQ,KAAK,IAAI,CAAA;IAExD,OAAO;QACL,KAAK,CAAC,MAAM;YACV,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAA;YAC1D,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC/D,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAAM;YACjB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAM;YAC/B,MAAM,EAAE,GAAG,GAAG,EAAE,CAAA;YAChB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;YAC7E,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5B,KAAK,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI;gBACnD,QAAQ,EAAE,EAAE,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE;aAC3H,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,WAAW;YAC9B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,CACvC,iBAAiB,SAAS,sBAAsB,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,SAAS,CAAC,WAAW,CAAC,qDAAqD,EAC7K,EAAE,6BAA6B,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,EAAE,uCAAuC,EAAE,CAAC,EAAE,CAAC,CAAA;YACzG,uEAAuE;YACvE,mDAAmD;YACnD,OAAO,sBAAsB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,UAAU,CAAA;QAC7D,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,iBAAiB,CAAC,2CAA2C,IAAI,IAAI,CAAC,CAAA;AACtH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,8BAA8B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;wDAwBQ,CAAA;AACxD,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAA;AACjE,CAAC"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LoaderFactory } from './types.js';
|
|
2
|
+
export interface SimpleLoaderOptions {
|
|
3
|
+
/** Rows per physical INSERT. A larger batch is split into deterministic chunks. */
|
|
4
|
+
maxRowsPerInsert?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Direct at-least-once destination writes. Every write unit reuses one stable
|
|
8
|
+
* token across retries: a batch written by one INSERT has one token, a
|
|
9
|
+
* deterministically chunked batch has one distinct token per chunk.
|
|
10
|
+
*/
|
|
11
|
+
export declare function simpleLoader(options?: SimpleLoaderOptions): LoaderFactory;
|
|
12
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa,CA8B7E"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BATCH_ID_COLUMN, INGESTED_AT_COLUMN, RUN_ID_COLUMN } from './destination.js';
|
|
2
|
+
const DEFAULT_MAX_ROWS_PER_INSERT = 50_000;
|
|
3
|
+
/**
|
|
4
|
+
* Direct at-least-once destination writes. Every write unit reuses one stable
|
|
5
|
+
* token across retries: a batch written by one INSERT has one token, a
|
|
6
|
+
* deterministically chunked batch has one distinct token per chunk.
|
|
7
|
+
*/
|
|
8
|
+
export function simpleLoader(options = {}) {
|
|
9
|
+
const maxRows = options.maxRowsPerInsert ?? DEFAULT_MAX_ROWS_PER_INSERT;
|
|
10
|
+
return (ctx) => {
|
|
11
|
+
let rows = 0;
|
|
12
|
+
let writeUnits = 0;
|
|
13
|
+
return {
|
|
14
|
+
ctx,
|
|
15
|
+
async write(batch) {
|
|
16
|
+
for (let offset = 0, unit = 0; offset < batch.rows.length; offset += maxRows, unit += 1) {
|
|
17
|
+
ctx.signal.throwIfAborted();
|
|
18
|
+
const slice = batch.rows.slice(offset, offset + maxRows).map((row) => {
|
|
19
|
+
// Publication time is destination-owned: never let a mapped row supply it.
|
|
20
|
+
const { [INGESTED_AT_COLUMN]: _ignored, ...authored } = row;
|
|
21
|
+
return { ...authored, [BATCH_ID_COLUMN]: batch.batchId, [RUN_ID_COLUMN]: ctx.runId };
|
|
22
|
+
});
|
|
23
|
+
await ctx.destination.insert({ table: ctx.table, rows: slice, token: `${batch.batchId}:${unit}` });
|
|
24
|
+
rows += slice.length;
|
|
25
|
+
writeUnits += 1;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
async finalize() {
|
|
29
|
+
return { evidence: writeUnits === 0 ? 'none_required' : 'clickhouse_ack', rows, writeUnits };
|
|
30
|
+
},
|
|
31
|
+
async abort() {
|
|
32
|
+
// Direct writes cannot be withdrawn; replay reuses the same tokens.
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAQrF,MAAM,2BAA2B,GAAG,MAAM,CAAA;AAE1C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAA+B,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,IAAI,2BAA2B,CAAA;IAEvE,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,IAAI,UAAU,GAAG,CAAC,CAAA;QAElB,OAAO;YACL,GAAG;YACH,KAAK,CAAC,KAAK,CAAC,KAAK;gBACf,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;oBACxF,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;oBAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;wBACnE,2EAA2E;wBAC3E,MAAM,EAAE,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,CAAA;wBAC3D,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,CAAA;oBACtF,CAAC,CAAC,CAAA;oBACF,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC,CAAA;oBAClG,IAAI,IAAI,KAAK,CAAC,MAAM,CAAA;oBACpB,UAAU,IAAI,CAAC,CAAA;gBACjB,CAAC;YACH,CAAC;YACD,KAAK,CAAC,QAAQ;gBACZ,OAAO,EAAE,QAAQ,EAAE,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,CAAA;YAC9F,CAAC;YACD,KAAK,CAAC,KAAK;gBACT,oEAAoE;YACtE,CAAC;SACF,CAAA;IACH,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AttemptOptions, FetchContext } from './types.js';
|
|
2
|
+
export interface Page<TItem, TCursor, TMetadata = undefined> {
|
|
3
|
+
items: readonly TItem[];
|
|
4
|
+
/** Continuation for the next request; `undefined` ends the sequence. */
|
|
5
|
+
next: TCursor | undefined;
|
|
6
|
+
/** Provider metadata passed through unchanged; readers explicitly map it to candidate state. */
|
|
7
|
+
metadata?: TMetadata;
|
|
8
|
+
}
|
|
9
|
+
export interface PaginateOptions<TItem, TCursor, TMetadata = undefined> {
|
|
10
|
+
context: FetchContext;
|
|
11
|
+
fetchPage(cursor: TCursor | undefined, signal: AbortSignal): Promise<Page<TItem, TCursor, TMetadata>>;
|
|
12
|
+
initial?: TCursor;
|
|
13
|
+
label?: AttemptOptions['label'];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Pull-based pagination over one retryable Promise step per page. Every request
|
|
17
|
+
* runs through the executor attempt capability. A continuation that was already
|
|
18
|
+
* seen (compared by canonical serialization) is rejected, so a cyclic provider
|
|
19
|
+
* cursor cannot loop forever; other non-progress is bounded by execution budgets.
|
|
20
|
+
* Every complete page is yielded, including empty and terminal pages. Metadata
|
|
21
|
+
* does not advance checkpoints unless the reader includes it in SourceChunk.state.
|
|
22
|
+
*/
|
|
23
|
+
export declare function paginate<TItem, TCursor, TMetadata = undefined>(options: PaginateOptions<TItem, TCursor, TMetadata>): AsyncGenerator<Page<TItem, TCursor, TMetadata>, void, void>;
|
|
24
|
+
//# sourceMappingURL=paginate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginate.d.ts","sourceRoot":"","sources":["../src/paginate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9D,MAAM,WAAW,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,SAAS;IACzD,KAAK,EAAE,SAAS,KAAK,EAAE,CAAA;IACvB,wEAAwE;IACxE,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;IACzB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,SAAS;IACpE,OAAO,EAAE,YAAY,CAAA;IACrB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;IACrG,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,wBAAuB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,SAAS,EACnE,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,GAClD,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAwB7D"}
|
package/dist/paginate.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IngestConfigError } from './errors.js';
|
|
2
|
+
import { canonicalJson } from './journal.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pull-based pagination over one retryable Promise step per page. Every request
|
|
5
|
+
* runs through the executor attempt capability. A continuation that was already
|
|
6
|
+
* seen (compared by canonical serialization) is rejected, so a cyclic provider
|
|
7
|
+
* cursor cannot loop forever; other non-progress is bounded by execution budgets.
|
|
8
|
+
* Every complete page is yielded, including empty and terminal pages. Metadata
|
|
9
|
+
* does not advance checkpoints unless the reader includes it in SourceChunk.state.
|
|
10
|
+
*/
|
|
11
|
+
export async function* paginate(options) {
|
|
12
|
+
const seen = new Set();
|
|
13
|
+
let cursor = options.initial;
|
|
14
|
+
if (cursor !== undefined)
|
|
15
|
+
seen.add(canonicalJson(cursor));
|
|
16
|
+
while (true) {
|
|
17
|
+
options.context.signal.throwIfAborted();
|
|
18
|
+
const current = cursor;
|
|
19
|
+
const page = await options.context.attempt((signal) => options.fetchPage(current, signal), {
|
|
20
|
+
label: options.label,
|
|
21
|
+
});
|
|
22
|
+
options.context.signal.throwIfAborted();
|
|
23
|
+
const next = page.next;
|
|
24
|
+
if (next !== undefined && next !== null) {
|
|
25
|
+
const key = canonicalJson(next);
|
|
26
|
+
if (seen.has(key)) {
|
|
27
|
+
throw new IngestConfigError(`paginate: provider returned a repeated continuation ${key}; refusing to loop.`);
|
|
28
|
+
}
|
|
29
|
+
seen.add(key);
|
|
30
|
+
}
|
|
31
|
+
yield page;
|
|
32
|
+
if (next === undefined || next === null)
|
|
33
|
+
return;
|
|
34
|
+
cursor = next;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=paginate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginate.js","sourceRoot":"","sources":["../src/paginate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAkB5C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAC7B,OAAmD;IAEnD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,CAAA;IAC5B,IAAI,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IAEzD,OAAO,IAAI,EAAE,CAAC;QACZ,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;QACvC,MAAM,OAAO,GAAG,MAAM,CAAA;QACtB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE;YACzF,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAA;QACF,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,MAAM,IAAI,iBAAiB,CAAC,uDAAuD,GAAG,qBAAqB,CAAC,CAAA;YAC9G,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACf,CAAC;QACD,MAAM,IAAI,CAAA;QACV,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;YAAE,OAAM;QAC/C,MAAM,GAAG,IAAI,CAAA;IACf,CAAC;AACH,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { type ClickHouseExecutor } from '@chkit/clickhouse';
|
|
2
|
+
import { type ChxInlinePluginRegistration, type ResolvedChxConfig } from '@chkit/core';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { PipelineDefinition } from './types.js';
|
|
5
|
+
declare const IngestOptionsSchema: z.ZodObject<{
|
|
6
|
+
journalTable: z.ZodDefault<z.ZodString>;
|
|
7
|
+
maxDurationSeconds: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
prefetchBatches: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type IngestOptions = z.infer<typeof IngestOptionsSchema>;
|
|
11
|
+
export type IngestPluginOptions = Partial<IngestOptions>;
|
|
12
|
+
interface IngestPluginCommandContext {
|
|
13
|
+
args: string[];
|
|
14
|
+
flags: Record<string, string | string[] | boolean | undefined>;
|
|
15
|
+
jsonMode: boolean;
|
|
16
|
+
options: IngestOptions;
|
|
17
|
+
config: ResolvedChxConfig;
|
|
18
|
+
configPath: string;
|
|
19
|
+
print: (value: unknown) => void;
|
|
20
|
+
pluginContext?: {
|
|
21
|
+
executor: ClickHouseExecutor;
|
|
22
|
+
hasExecutor: boolean;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function createIngestPlugin(options?: IngestPluginOptions): {
|
|
26
|
+
manifest: {
|
|
27
|
+
name: "ingest";
|
|
28
|
+
apiVersion: 1;
|
|
29
|
+
};
|
|
30
|
+
optionsSchema: import("@chkit/core").SafeParseable<{
|
|
31
|
+
journalTable: string;
|
|
32
|
+
maxDurationSeconds: number;
|
|
33
|
+
prefetchBatches: number;
|
|
34
|
+
}>;
|
|
35
|
+
commands: ({
|
|
36
|
+
name: string;
|
|
37
|
+
description: string;
|
|
38
|
+
flags: readonly [{
|
|
39
|
+
readonly name: "--tag";
|
|
40
|
+
readonly type: "string[]";
|
|
41
|
+
readonly description: "Exact tag every selected stream must carry (repeatable, AND)";
|
|
42
|
+
readonly placeholder: "<tag>";
|
|
43
|
+
}, {
|
|
44
|
+
readonly name: "--backfill";
|
|
45
|
+
readonly type: "string";
|
|
46
|
+
readonly description: "Stable backfill id; uses an isolated checkpoint namespace";
|
|
47
|
+
readonly placeholder: "<id>";
|
|
48
|
+
}, {
|
|
49
|
+
readonly name: "--from";
|
|
50
|
+
readonly type: "string";
|
|
51
|
+
readonly description: "Backfill range lower bound (ISO timestamp)";
|
|
52
|
+
readonly placeholder: "<timestamp>";
|
|
53
|
+
}, {
|
|
54
|
+
readonly name: "--to";
|
|
55
|
+
readonly type: "string";
|
|
56
|
+
readonly description: "Backfill range upper bound (ISO timestamp)";
|
|
57
|
+
readonly placeholder: "<timestamp>";
|
|
58
|
+
}, {
|
|
59
|
+
readonly name: "--max-duration";
|
|
60
|
+
readonly type: "string";
|
|
61
|
+
readonly description: "Execution budget in seconds";
|
|
62
|
+
readonly placeholder: "<seconds>";
|
|
63
|
+
}];
|
|
64
|
+
optionsSchema: import("@chkit/core").SafeParseable<{
|
|
65
|
+
journalTable: string;
|
|
66
|
+
maxDurationSeconds: number;
|
|
67
|
+
prefetchBatches: number;
|
|
68
|
+
}>;
|
|
69
|
+
run: (context: IngestPluginCommandContext) => Promise<number | undefined>;
|
|
70
|
+
} | {
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
flags: readonly [{
|
|
74
|
+
readonly name: "--tag";
|
|
75
|
+
readonly type: "string[]";
|
|
76
|
+
readonly description: "Exact tag every selected stream must carry (repeatable, AND)";
|
|
77
|
+
readonly placeholder: "<tag>";
|
|
78
|
+
}];
|
|
79
|
+
optionsSchema: import("@chkit/core").SafeParseable<{
|
|
80
|
+
journalTable: string;
|
|
81
|
+
maxDurationSeconds: number;
|
|
82
|
+
prefetchBatches: number;
|
|
83
|
+
}>;
|
|
84
|
+
run: (context: IngestPluginCommandContext) => Promise<number | undefined>;
|
|
85
|
+
} | {
|
|
86
|
+
name: string;
|
|
87
|
+
description: string;
|
|
88
|
+
flags: readonly [{
|
|
89
|
+
readonly name: "--tag";
|
|
90
|
+
readonly type: "string[]";
|
|
91
|
+
readonly description: "Exact tag every selected stream must carry (repeatable, AND)";
|
|
92
|
+
readonly placeholder: "<tag>";
|
|
93
|
+
}, {
|
|
94
|
+
readonly name: "--backfill";
|
|
95
|
+
readonly type: "string";
|
|
96
|
+
readonly description: "Inspect an isolated backfill checkpoint namespace";
|
|
97
|
+
readonly placeholder: "<id>";
|
|
98
|
+
}];
|
|
99
|
+
optionsSchema: import("@chkit/core").SafeParseable<{
|
|
100
|
+
journalTable: string;
|
|
101
|
+
maxDurationSeconds: number;
|
|
102
|
+
prefetchBatches: number;
|
|
103
|
+
}>;
|
|
104
|
+
run: (context: IngestPluginCommandContext) => Promise<number | undefined>;
|
|
105
|
+
} | {
|
|
106
|
+
name: string;
|
|
107
|
+
description: string;
|
|
108
|
+
flags: readonly [{
|
|
109
|
+
readonly name: "--tag";
|
|
110
|
+
readonly type: "string[]";
|
|
111
|
+
readonly description: "Exact tag every selected stream must carry (repeatable, AND)";
|
|
112
|
+
readonly placeholder: "<tag>";
|
|
113
|
+
}, {
|
|
114
|
+
readonly name: "--backfill";
|
|
115
|
+
readonly type: "string";
|
|
116
|
+
readonly description: "Inspect an isolated backfill checkpoint namespace";
|
|
117
|
+
readonly placeholder: "<id>";
|
|
118
|
+
}, {
|
|
119
|
+
readonly name: "--apply";
|
|
120
|
+
readonly type: "string";
|
|
121
|
+
readonly description: "Materialize the reviewed fingerprint with writers stopped (select one stream)";
|
|
122
|
+
readonly placeholder: "<fingerprint>";
|
|
123
|
+
}];
|
|
124
|
+
optionsSchema: import("@chkit/core").SafeParseable<{
|
|
125
|
+
journalTable: string;
|
|
126
|
+
maxDurationSeconds: number;
|
|
127
|
+
prefetchBatches: number;
|
|
128
|
+
}>;
|
|
129
|
+
run: (context: IngestPluginCommandContext) => Promise<number | undefined>;
|
|
130
|
+
})[];
|
|
131
|
+
hooks: {
|
|
132
|
+
onCheck(context: {
|
|
133
|
+
config: ResolvedChxConfig;
|
|
134
|
+
}): Promise<{
|
|
135
|
+
plugin: string;
|
|
136
|
+
evaluated: boolean;
|
|
137
|
+
ok: boolean;
|
|
138
|
+
findings: {
|
|
139
|
+
code: string;
|
|
140
|
+
message: string;
|
|
141
|
+
severity: "info" | "warn" | "error";
|
|
142
|
+
}[];
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
export type IngestPlugin = ReturnType<typeof createIngestPlugin>;
|
|
147
|
+
export declare function ingest(options?: IngestPluginOptions): ChxInlinePluginRegistration<IngestPlugin, IngestPluginOptions>;
|
|
148
|
+
/** Local, zero-network graph checks: they hold in `--offline` mode too. */
|
|
149
|
+
export declare function checkGraph(pipelines: readonly PipelineDefinition[]): {
|
|
150
|
+
code: string;
|
|
151
|
+
message: string;
|
|
152
|
+
severity: "info" | "warn" | "error";
|
|
153
|
+
}[];
|
|
154
|
+
export {};
|
|
155
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC9F,OAAO,EAIL,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAIpD,QAAA,MAAM,mBAAmB;;;;iBAKvB,CAAA;AACF,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAExD,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;AAwBxD,UAAU,0BAA0B;IAClC,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IAC9D,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,iBAAiB,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/B,aAAa,CAAC,EAAE;QAAE,QAAQ,EAAE,kBAAkB,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAA;CACvE;AAID,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA2MvC;YAAE,MAAM,EAAE,iBAAiB,CAAA;SAAE;;;;;sBAqB1B,MAAM;yBAAW,MAAM;0BAAY,MAAM,GAAG,MAAM,GAAG,OAAO;;;;EAV3F;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEhE,wBAAgB,MAAM,CAAC,OAAO,GAAE,mBAAwB,GAAG,2BAA2B,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAExH;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE;UACnC,MAAM;aAAW,MAAM;cAAY,MAAM,GAAG,MAAM,GAAG,OAAO;IAkB3F"}
|