@descryy/runtime-database-observation 0.5.2 → 0.5.3

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 (55) hide show
  1. package/dist/index.d.ts +7 -5
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/mysql-row-collector.d.ts +33 -19
  6. package/dist/mysql-row-collector.d.ts.map +1 -1
  7. package/dist/mysql-row-collector.js +480 -26
  8. package/dist/mysql-row-collector.js.map +1 -1
  9. package/dist/postgres-log-parser.d.ts +15 -29
  10. package/dist/postgres-log-parser.d.ts.map +1 -1
  11. package/dist/postgres-log-parser.js +103 -32
  12. package/dist/postgres-log-parser.js.map +1 -1
  13. package/dist/postgres-log-source.d.ts +2 -0
  14. package/dist/postgres-log-source.d.ts.map +1 -1
  15. package/dist/postgres-log-source.js +171 -35
  16. package/dist/postgres-log-source.js.map +1 -1
  17. package/dist/postgres-query-collector.d.ts.map +1 -1
  18. package/dist/postgres-query-collector.js +43 -13
  19. package/dist/postgres-query-collector.js.map +1 -1
  20. package/dist/postgres-row-collector.d.ts +7 -0
  21. package/dist/postgres-row-collector.d.ts.map +1 -1
  22. package/dist/postgres-row-collector.js +112 -17
  23. package/dist/postgres-row-collector.js.map +1 -1
  24. package/dist/prisma-instrumentation.d.ts +20 -0
  25. package/dist/prisma-instrumentation.d.ts.map +1 -0
  26. package/dist/prisma-instrumentation.js +99 -0
  27. package/dist/prisma-instrumentation.js.map +1 -0
  28. package/dist/query-collector.d.ts +2 -0
  29. package/dist/query-collector.d.ts.map +1 -1
  30. package/dist/query-collector.js +38 -13
  31. package/dist/query-collector.js.map +1 -1
  32. package/dist/query-line-parser.d.ts.map +1 -1
  33. package/dist/query-line-parser.js +2 -1
  34. package/dist/query-line-parser.js.map +1 -1
  35. package/dist/query-marker.d.ts +10 -1
  36. package/dist/query-marker.d.ts.map +1 -1
  37. package/dist/query-marker.js +2 -0
  38. package/dist/query-marker.js.map +1 -1
  39. package/dist/row-capture-policy.d.ts +31 -0
  40. package/dist/row-capture-policy.d.ts.map +1 -0
  41. package/dist/row-capture-policy.js +95 -0
  42. package/dist/row-capture-policy.js.map +1 -0
  43. package/dist/smoke.d.ts.map +1 -1
  44. package/dist/smoke.js +2 -0
  45. package/dist/smoke.js.map +1 -1
  46. package/dist/sqlite-instrumentation.js +9 -2
  47. package/dist/sqlite-instrumentation.js.map +1 -1
  48. package/dist/sqlite-row-snapshot.d.ts +4 -0
  49. package/dist/sqlite-row-snapshot.d.ts.map +1 -1
  50. package/dist/sqlite-row-snapshot.js +153 -25
  51. package/dist/sqlite-row-snapshot.js.map +1 -1
  52. package/dist/table-extraction.d.ts.map +1 -1
  53. package/dist/table-extraction.js +124 -5
  54. package/dist/table-extraction.js.map +1 -1
  55. package/package.json +9 -8
@@ -1,31 +1,277 @@
1
- /**
2
- * MySQL/MariaDB row-change capture: a named, remediable refusal, not a
3
- * binlog implementation. See DEC-NEXT-mysql-row-and-schema-capture-refused-no-driver
4
- * (descry-core decisions inbox) for the full reasoning — in short, this
5
- * repo's `pnpm-lock.yaml` carries no MySQL driver (`mysql2` or otherwise)
6
- * today, and this lane cannot install one, so writing binlog-protocol
7
- * parsing code that has never run against a real driver would be a worse
8
- * violation of honest degradation (rule 7) than declining to write it.
9
- *
10
- * Shaped as a `Collector` for the same reason `createPostgresRowChangeCollector`
11
- * is: a caller wiring up database observation for a run can try to start
12
- * this collector unconditionally, exactly like the others, and get back a
13
- * refusal it can disclose rather than a branch it has to special-case.
14
- *
15
- * The moment `mysql2` (with `binlog_format=ROW` and full row images) becomes
16
- * an installed dependency, this refusal should be replaced with a real
17
- * binlog client, following `postgres-row-collector.ts`'s dynamic-import
18
- * pattern -- optional dependency, loaded lazily, refuse-by-name if absent.
19
- */
20
- export const MYSQL_ROW_CAPTURE_REFUSAL_REASON = "MySQL row-change capture needs the optional dependency \"mysql2\" (with binlog_format=ROW and full row images), " +
21
- "which is not installed in this build; the query-text channel is unaffected.";
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { COLLECTOR_VERSION } from "./collector-version.js";
10
+ import { approximateCellBytes, MAX_SNAPSHOT_BYTES, mergeTruncated, mergeWithheld, resolveRowCapturePolicy } from "./row-capture-policy.js";
11
+ import { diffTableSnapshot } from "./sqlite-row-snapshot.js";
12
+ export const MYSQL_ROW_CAPTURE_REFUSAL_REASON = 'MySQL row-change capture needs the optional dependency "mysql2", which is not installed next to ' +
13
+ "@descryy/runtime-database-observation; install it there to capture rows. The query-text channel is unaffected.";
14
+ const EVENT_TYPE = "DATABASE_QUERY";
15
+ const DEFAULT_ROW_CAP = 10_000;
16
+ const DEFAULT_STATEMENT_TIMEOUT_MS = 30_000;
17
+ const DEFAULT_SNAPSHOT_DEADLINE_MS = 120_000;
18
+ const CONNECT_TIMEOUT_MS = 10_000;
19
+ const KEY_LOOKUP_CHUNK = 500;
20
+ export class MysqlDriverMissingError extends Error {
21
+ }
22
+ export function mysqlPromiseModule(loaded) {
23
+ const module = loaded;
24
+ if (typeof module?.createConnection === "function")
25
+ return module;
26
+ if (typeof module?.default?.createConnection === "function")
27
+ return module.default;
28
+ throw new Error('"mysql2/promise" was loaded but exposes no createConnection, at its top level or on its default export');
29
+ }
30
+ export async function loadMysqlPromiseModule() {
31
+ const moduleName = "mysql2/promise";
32
+ let loaded;
33
+ try {
34
+ loaded = await import(__rewriteRelativeImportExtension(moduleName));
35
+ }
36
+ catch (error) {
37
+ const code = error?.code;
38
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND")
39
+ throw new MysqlDriverMissingError(MYSQL_ROW_CAPTURE_REFUSAL_REASON);
40
+ throw error;
41
+ }
42
+ return mysqlPromiseModule(loaded);
43
+ }
44
+ export async function defaultClientFactory(connectionString, statementTimeoutMs) {
45
+ const mysql = await loadMysqlPromiseModule();
46
+ const connection = await mysql.createConnection({
47
+ uri: connectionString,
48
+ dateStrings: true,
49
+ supportBigNumbers: true,
50
+ bigNumberStrings: true,
51
+ jsonStrings: true,
52
+ multipleStatements: false,
53
+ connectTimeout: CONNECT_TIMEOUT_MS,
54
+ });
55
+ return {
56
+ async query(sql, params = []) {
57
+ const [rows] = await connection.query({ sql, values: params, timeout: statementTimeoutMs });
58
+ return Array.isArray(rows) ? rows : [];
59
+ },
60
+ end() {
61
+ return connection.end();
62
+ },
63
+ };
64
+ }
65
+ export function describeMysqlTarget(connectionString) {
66
+ try {
67
+ const url = new URL(connectionString);
68
+ const database = url.pathname.replace(/^\//, "");
69
+ return `${url.hostname}${url.port === "" ? "" : `:${url.port}`}${database === "" ? "" : `/${database}`}`;
70
+ }
71
+ catch {
72
+ return "the configured MySQL server";
73
+ }
74
+ }
75
+ function escapedForRegExp(text) {
76
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
77
+ }
78
+ function withoutSecret(message, secret) {
79
+ if (secret === "")
80
+ return message;
81
+ if (secret.length >= 3)
82
+ return message.split(secret).join("[REDACTED]");
83
+ return message.replace(new RegExp(`(?<![A-Za-z0-9])${escapedForRegExp(secret)}(?![A-Za-z0-9])`, "g"), "[REDACTED]");
84
+ }
85
+ export function scrubConnectionSecrets(message, connectionString) {
86
+ let scrubbed = message.split(connectionString).join(describeMysqlTarget(connectionString));
87
+ scrubbed = scrubbed.replace(/(\/\/)[^/\s@]*@/g, "$1[REDACTED]@");
88
+ scrubbed = scrubbed.replace(/(\buser\s+)'[^']*'(?:@'[^']*')?/gi, "$1[REDACTED]");
89
+ let password;
90
+ try {
91
+ password = new URL(connectionString).password;
92
+ }
93
+ catch {
94
+ return scrubbed;
95
+ }
96
+ const variants = new Set([password]);
97
+ try {
98
+ variants.add(decodeURIComponent(password));
99
+ }
100
+ catch {
101
+ variants.add(password);
102
+ }
103
+ for (const secret of variants)
104
+ scrubbed = withoutSecret(scrubbed, secret);
105
+ return scrubbed;
106
+ }
107
+ export function quoteMysqlIdentifier(name) {
108
+ return `\`${name.replace(/`/g, "``")}\``;
109
+ }
110
+ export function normaliseMysqlValue(value) {
111
+ if (value === null || value === undefined)
112
+ return null;
113
+ if (Buffer.isBuffer(value))
114
+ return `\\x${value.toString("hex")}`;
115
+ if (value instanceof Uint8Array)
116
+ return `\\x${Buffer.from(value).toString("hex")}`;
117
+ if (typeof value === "bigint")
118
+ return value.toString();
119
+ if (value instanceof Date)
120
+ return Number.isNaN(value.getTime()) ? String(value) : value.toISOString();
121
+ if (typeof value === "object")
122
+ return JSON.stringify(value);
123
+ return value;
124
+ }
125
+ function normaliseRow(row) {
126
+ const normalised = {};
127
+ for (const [column, value] of Object.entries(row))
128
+ normalised[column] = normaliseMysqlValue(value);
129
+ return normalised;
130
+ }
131
+ function keyOf(row, keyColumns) {
132
+ return JSON.stringify(keyColumns.map((column) => normaliseMysqlValue(row[column])));
133
+ }
134
+ function rowTuple(columns) {
135
+ return columns.length === 1 ? quoteMysqlIdentifier(columns[0] ?? "") : `(${columns.map(quoteMysqlIdentifier).join(", ")})`;
136
+ }
137
+ function placeholderTuple(count) {
138
+ return count === 1 ? "?" : `(${new Array(count).fill("?").join(", ")})`;
139
+ }
140
+ async function readWindow(client, table, rowCap, upTo) {
141
+ const order = table.keyColumns.map(quoteMysqlIdentifier).join(", ");
142
+ const where = upTo === null ? "" : ` WHERE ${rowTuple(table.keyColumns)} <= ${placeholderTuple(table.keyColumns.length)}`;
143
+ const rows = await client.query(`SELECT * FROM ${quoteMysqlIdentifier(table.name)}${where} ORDER BY ${order} LIMIT ?`, [...(upTo ?? []), rowCap + 1]);
144
+ const truncated = rows.length > rowCap;
145
+ const bounded = truncated ? rows.slice(0, rowCap) : rows;
146
+ const rowsByRowid = new Map();
147
+ const rawKeys = new Map();
148
+ let lastKey = null;
149
+ for (const row of bounded) {
150
+ const key = keyOf(row, table.keyColumns);
151
+ lastKey = table.keyColumns.map((column) => row[column]);
152
+ rowsByRowid.set(key, normaliseRow(row));
153
+ rawKeys.set(key, lastKey);
154
+ }
155
+ let approximateBytes = 0;
156
+ for (const normalisedRow of rowsByRowid.values()) {
157
+ for (const cell of Object.values(normalisedRow))
158
+ approximateBytes += approximateCellBytes(cell);
159
+ }
160
+ return { snapshot: { rowsByRowid, truncated, approximateBytes }, rawKeys, lastKey };
161
+ }
162
+ async function readByKeys(client, table, keys) {
163
+ const found = new Map();
164
+ for (let start = 0; start < keys.length; start += KEY_LOOKUP_CHUNK) {
165
+ const chunk = keys.slice(start, start + KEY_LOOKUP_CHUNK);
166
+ const tuples = chunk.map(() => placeholderTuple(table.keyColumns.length)).join(", ");
167
+ const rows = await client.query(`SELECT * FROM ${quoteMysqlIdentifier(table.name)} WHERE ${rowTuple(table.keyColumns)} IN (${tuples})`, chunk.flat());
168
+ for (const row of rows)
169
+ found.set(keyOf(row, table.keyColumns), normaliseRow(row));
170
+ }
171
+ return found;
172
+ }
173
+ export function diffAgainstKnownRows(table, before, currentOfBefore, afterWindow) {
174
+ const restrictedAfter = new Map();
175
+ for (const [key, row] of currentOfBefore)
176
+ restrictedAfter.set(key, row);
177
+ for (const [key, row] of afterWindow.rowsByRowid) {
178
+ if (!before.rowsByRowid.has(key))
179
+ restrictedAfter.set(key, row);
180
+ }
181
+ return diffTableSnapshot(table, before, { rowsByRowid: restrictedAfter, truncated: true });
182
+ }
183
+ async function listKeyedTables(client, policy, schema) {
184
+ const tableRows = await client.query("SELECT TABLE_NAME AS name FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME");
185
+ const listed = tableRows.map((row) => String(row["name"]));
186
+ const present = new Set(listed.map((name) => name.toLowerCase()));
187
+ const missingAllowlisted = (policy.tables ?? []).filter((name) => !present.has(name) && !present.has(name.replace(`${schema.toLowerCase()}.`, "")));
188
+ const wanted = listed.filter((name) => policy.allows(name, schema));
189
+ const indexRows = await client.query("SELECT s.TABLE_NAME AS table_name, s.INDEX_NAME AS index_name, s.COLUMN_NAME AS column_name, s.SUB_PART AS sub_part, " +
190
+ "c.IS_NULLABLE AS nullable FROM information_schema.STATISTICS s " +
191
+ "LEFT JOIN information_schema.COLUMNS c ON c.TABLE_SCHEMA = s.TABLE_SCHEMA AND c.TABLE_NAME = s.TABLE_NAME AND c.COLUMN_NAME = s.COLUMN_NAME " +
192
+ "WHERE s.TABLE_SCHEMA = DATABASE() AND s.NON_UNIQUE = 0 ORDER BY s.TABLE_NAME, s.INDEX_NAME, s.SEQ_IN_INDEX");
193
+ const indexes = new Map();
194
+ for (const row of indexRows) {
195
+ const tableName = String(row["table_name"]);
196
+ const indexName = String(row["index_name"]);
197
+ const byIndex = indexes.get(tableName) ?? new Map();
198
+ const entry = byIndex.get(indexName) ?? { columns: [], usable: true };
199
+ const column = row["column_name"];
200
+ const prefixOnly = row["sub_part"] !== null && row["sub_part"] !== undefined;
201
+ const nullable = String(row["nullable"] ?? "YES").toUpperCase() === "YES";
202
+ if (column === null || column === undefined || prefixOnly || nullable)
203
+ entry.usable = false;
204
+ if (column !== null && column !== undefined)
205
+ entry.columns.push(String(column));
206
+ byIndex.set(indexName, entry);
207
+ indexes.set(tableName, byIndex);
208
+ }
209
+ const keyed = [];
210
+ const unkeyed = [];
211
+ for (const name of wanted) {
212
+ const byIndex = indexes.get(name);
213
+ const primary = byIndex?.get("PRIMARY");
214
+ const fallback = [...(byIndex?.entries() ?? [])]
215
+ .filter(([indexName, entry]) => indexName !== "PRIMARY" && entry.usable && entry.columns.length > 0)
216
+ .sort(([a], [b]) => a.localeCompare(b))[0]?.[1];
217
+ const key = primary !== undefined && primary.usable && primary.columns.length > 0 ? primary : fallback;
218
+ if (key === undefined) {
219
+ unkeyed.push(name);
220
+ }
221
+ else {
222
+ keyed.push({ name, keyColumns: key.columns });
223
+ }
224
+ }
225
+ return { keyed, unkeyed, missingAllowlisted };
226
+ }
22
227
  export function createMysqlRowChangeCollector(options) {
23
228
  const processId = options.processId ?? "mysql-row-changes";
229
+ const rowCap = options.rowCap ?? DEFAULT_ROW_CAP;
230
+ const statementTimeoutMs = options.statementTimeoutMs ?? DEFAULT_STATEMENT_TIMEOUT_MS;
231
+ const snapshotDeadlineMs = options.snapshotDeadlineMs ?? DEFAULT_SNAPSHOT_DEADLINE_MS;
232
+ const clientFactory = options.clientFactory ?? defaultClientFactory;
233
+ const target = describeMysqlTarget(options.connectionString);
234
+ const policyResolution = resolveRowCapturePolicy(options.rowCapture);
235
+ const rowPolicy = policyResolution.ok ? policyResolution.policy : null;
236
+ let client = null;
237
+ let savedContext = null;
238
+ let refusalReason = null;
239
+ let schema = "";
240
+ let tables = [];
241
+ let unkeyedTables = [];
242
+ let unreadableTables = [];
243
+ let outOfTimeTables = [];
244
+ let missingAllowlisted = [];
245
+ let partialInsertTables = new Set();
246
+ let beforeWindows = new Map();
247
+ function describeError(error) {
248
+ const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
249
+ return scrubConnectionSecrets(detail, options.connectionString);
250
+ }
24
251
  function capabilities() {
25
252
  const unrelated = {
26
253
  availability: "unavailable",
27
254
  reason: "MysqlRowChangeCollector observes row-level DATABASE_QUERY (row-change) events only.",
28
255
  };
256
+ const databaseObservation = refusalReason !== null
257
+ ? { availability: "unavailable", reason: refusalReason }
258
+ : {
259
+ availability: "available",
260
+ reason: `row-level INSERT/UPDATE/DELETE on ${target} via a read-only before/after snapshot diff keyed by each table's ` +
261
+ `primary key (or a NOT NULL unique key), capped at ${String(rowCap)} rows per table. A row changed and changed back ` +
262
+ "inside the window is not seen, several updates to one row arrive as one, and a key change arrives as a DELETE " +
263
+ "plus an INSERT. Tables over the cap are diffed for the rows the first snapshot held and disclosed per row as " +
264
+ "truncated: true; rows inserted past that window are not observed." +
265
+ (unkeyedTables.length > 0 ? ` Skipped, no primary or NOT NULL unique key to diff by: ${unkeyedTables.join(", ")}.` : "") +
266
+ (unreadableTables.length > 0 ? ` Skipped, could not be read: ${unreadableTables.join(", ")}.` : "") +
267
+ (outOfTimeTables.length > 0
268
+ ? ` Skipped, the ${String(snapshotDeadlineMs)} ms snapshot deadline or the ${String(MAX_SNAPSHOT_BYTES)} byte snapshot budget ran out before them: ${outOfTimeTables.join(", ")}.`
269
+ : "") +
270
+ (partialInsertTables.size > 0
271
+ ? ` More rows than the cap changed in: ${[...partialInsertTables].join(", ")}; their inserts are partial.`
272
+ : "") +
273
+ ` ${rowPolicy?.describe(missingAllowlisted) ?? ""}`,
274
+ };
29
275
  return {
30
276
  domObservation: unrelated,
31
277
  consoleObservation: unrelated,
@@ -35,17 +281,225 @@ export function createMysqlRowChangeCollector(options) {
35
281
  sourceMapping: unrelated,
36
282
  stackCapture: unrelated,
37
283
  processLifecycle: unrelated,
38
- databaseObservation: { availability: "unavailable", reason: MYSQL_ROW_CAPTURE_REFUSAL_REASON },
284
+ databaseObservation,
39
285
  externalServiceObservation: unrelated,
40
286
  };
41
287
  }
288
+ function emitDiff(context, diff) {
289
+ const before = rowPolicy?.filterRow(diff.before) ?? { row: diff.before, withheld: [], truncated: [] };
290
+ const after = rowPolicy?.filterRow(diff.after) ?? { row: diff.after, withheld: [], truncated: [] };
291
+ const withheldColumns = mergeWithheld(before.withheld, after.withheld);
292
+ const truncatedColumns = mergeTruncated(before.truncated, after.truncated);
293
+ context.emit({
294
+ timestamp: new Date().toISOString(),
295
+ source: "backend-process",
296
+ service: options.service ?? null,
297
+ process: processId,
298
+ eventType: EVENT_TYPE,
299
+ payload: {
300
+ kind: "row-change",
301
+ schema,
302
+ table: diff.table,
303
+ op: diff.op,
304
+ before: before.row,
305
+ after: after.row,
306
+ ...(withheldColumns.length > 0 ? { withheldColumns } : {}),
307
+ ...(truncatedColumns.length > 0 ? { truncatedColumns } : {}),
308
+ beforeCompleteness: "full",
309
+ truncated: diff.truncated,
310
+ },
311
+ traceId: null,
312
+ requestId: null,
313
+ correlationId: null,
314
+ graphNodeId: null,
315
+ sourceLocation: null,
316
+ stackTrace: null,
317
+ confidence: 1,
318
+ redactionStatus: "pending-redaction",
319
+ collectorVersion: COLLECTOR_VERSION,
320
+ });
321
+ }
322
+ function emitCollectorError(context, detail) {
323
+ try {
324
+ context.emit({
325
+ timestamp: new Date().toISOString(),
326
+ source: "backend-process",
327
+ service: options.service ?? null,
328
+ process: processId,
329
+ eventType: "COLLECTOR_ERROR",
330
+ payload: {
331
+ raw: `mysql row-change collector for process "${processId}" failed: ${detail}`,
332
+ collectorId: `mysql-row-collector:${processId}`,
333
+ error: detail,
334
+ },
335
+ traceId: null,
336
+ requestId: null,
337
+ correlationId: null,
338
+ graphNodeId: null,
339
+ sourceLocation: null,
340
+ stackTrace: null,
341
+ confidence: 1,
342
+ redactionStatus: "pending-redaction",
343
+ collectorVersion: COLLECTOR_VERSION,
344
+ });
345
+ }
346
+ catch (emitError) {
347
+ console.error(`[mysql-row-collector:${processId}] failed (${detail}) AND the failure could not be emitted: ${String(emitError)}`);
348
+ }
349
+ }
350
+ async function closeClient() {
351
+ const active = client;
352
+ client = null;
353
+ if (active === null)
354
+ return;
355
+ try {
356
+ await active.end();
357
+ }
358
+ catch (error) {
359
+ if (savedContext !== null)
360
+ emitCollectorError(savedContext, `closing the database connection failed (${describeError(error)})`);
361
+ }
362
+ }
363
+ async function inReadOnlySnapshot(active, body) {
364
+ await active.query("START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY");
365
+ try {
366
+ return await body();
367
+ }
368
+ finally {
369
+ await active.query("COMMIT").catch((error) => {
370
+ if (savedContext !== null)
371
+ emitCollectorError(savedContext, `ending the read-only snapshot transaction failed (${describeError(error)})`);
372
+ });
373
+ }
374
+ }
375
+ async function diffTable(active, table, before) {
376
+ const upTo = before.snapshot.truncated ? before.lastKey : null;
377
+ const after = await readWindow(active, table, rowCap, upTo);
378
+ if (!after.snapshot.truncated) {
379
+ const diffs = diffTableSnapshot(table.name, before.snapshot, after.snapshot);
380
+ return before.snapshot.truncated ? diffs.map((diff) => ({ ...diff, truncated: true })) : diffs;
381
+ }
382
+ partialInsertTables.add(table.name);
383
+ const current = await readByKeys(active, table, [...before.rawKeys.values()]);
384
+ return diffAgainstKnownRows(table.name, before.snapshot, current, after.snapshot);
385
+ }
42
386
  return {
43
387
  collectorId: `mysql-row-collector:${processId}`,
44
- start(_context) {
45
- return Promise.resolve({ available: false, reason: MYSQL_ROW_CAPTURE_REFUSAL_REASON });
388
+ async start(context) {
389
+ savedContext = context;
390
+ refusalReason = null;
391
+ if (!policyResolution.ok || rowPolicy === null) {
392
+ refusalReason = policyResolution.ok ? "row capture policy did not resolve" : policyResolution.reason;
393
+ return { available: false, reason: refusalReason };
394
+ }
395
+ if (!Number.isInteger(rowCap) || rowCap < 1) {
396
+ refusalReason = `rowCap must be a positive integer, got ${String(rowCap)}.`;
397
+ return { available: false, reason: refusalReason };
398
+ }
399
+ try {
400
+ client = await clientFactory(options.connectionString, statementTimeoutMs);
401
+ }
402
+ catch (error) {
403
+ refusalReason =
404
+ error instanceof MysqlDriverMissingError
405
+ ? MYSQL_ROW_CAPTURE_REFUSAL_REASON
406
+ : `could not connect to ${target} for row-level capture (${describeError(error)}); the query-text channel is unaffected.`;
407
+ client = null;
408
+ return { available: false, reason: refusalReason };
409
+ }
410
+ const active = client;
411
+ try {
412
+ const databaseRows = await active.query("SELECT DATABASE() AS name");
413
+ const current = databaseRows[0]?.["name"];
414
+ if (current === null || current === undefined || String(current) === "") {
415
+ refusalReason =
416
+ `the connection string for ${target} names no database, so there is no table set to capture; ` +
417
+ "add the database to the connection string's path.";
418
+ await closeClient();
419
+ return { available: false, reason: refusalReason };
420
+ }
421
+ schema = String(current);
422
+ await active.query("SET SESSION TRANSACTION READ ONLY");
423
+ const listed = await listKeyedTables(active, rowPolicy, schema);
424
+ tables = listed.keyed;
425
+ unkeyedTables = listed.unkeyed;
426
+ missingAllowlisted = listed.missingAllowlisted;
427
+ unreadableTables = [];
428
+ outOfTimeTables = [];
429
+ partialInsertTables = new Set();
430
+ beforeWindows = new Map();
431
+ const deadlineAt = Date.now() + snapshotDeadlineMs;
432
+ let snapshotBytes = 0;
433
+ await inReadOnlySnapshot(active, async () => {
434
+ for (const table of tables) {
435
+ if (Date.now() > deadlineAt || snapshotBytes > MAX_SNAPSHOT_BYTES) {
436
+ outOfTimeTables.push(table.name);
437
+ continue;
438
+ }
439
+ try {
440
+ const window = await readWindow(active, table, rowCap, null);
441
+ snapshotBytes += window.snapshot.approximateBytes ?? 0;
442
+ beforeWindows.set(table.name, window);
443
+ }
444
+ catch (error) {
445
+ unreadableTables.push(`${table.name} (${describeError(error)})`);
446
+ }
447
+ }
448
+ });
449
+ return { available: true };
450
+ }
451
+ catch (error) {
452
+ refusalReason = `could not start row-level capture on ${target}: ${describeError(error)}`;
453
+ await closeClient();
454
+ return { available: false, reason: refusalReason };
455
+ }
46
456
  },
47
- stop() {
48
- return Promise.resolve();
457
+ async stop() {
458
+ const active = client;
459
+ if (active === null)
460
+ return;
461
+ const context = savedContext;
462
+ try {
463
+ const diffs = [];
464
+ const deadlineAt = Date.now() + snapshotDeadlineMs;
465
+ let snapshotBytes = 0;
466
+ await inReadOnlySnapshot(active, async () => {
467
+ for (const table of tables) {
468
+ const before = beforeWindows.get(table.name);
469
+ if (before === undefined)
470
+ continue;
471
+ if (Date.now() > deadlineAt || snapshotBytes > MAX_SNAPSHOT_BYTES) {
472
+ outOfTimeTables.push(table.name);
473
+ if (context !== null)
474
+ emitCollectorError(context, `table "${table.name}" was not compared: the closing snapshot ran out of its ${String(snapshotDeadlineMs)} ms deadline or byte budget`);
475
+ continue;
476
+ }
477
+ try {
478
+ diffs.push(...(await diffTable(active, table, before)));
479
+ snapshotBytes += before.snapshot.approximateBytes ?? 0;
480
+ }
481
+ catch (error) {
482
+ unreadableTables.push(`${table.name} (${describeError(error)})`);
483
+ if (context !== null)
484
+ emitCollectorError(context, `table "${table.name}" could not be read when the run ended, so its row changes were not captured (${describeError(error)})`);
485
+ }
486
+ }
487
+ });
488
+ if (context !== null) {
489
+ for (const diff of diffs)
490
+ emitDiff(context, diff);
491
+ }
492
+ }
493
+ catch (error) {
494
+ const detail = describeError(error);
495
+ refusalReason = `could not read the closing snapshot from ${target}: ${detail}`;
496
+ if (context !== null)
497
+ emitCollectorError(context, detail);
498
+ }
499
+ finally {
500
+ beforeWindows = new Map();
501
+ await closeClient();
502
+ }
49
503
  },
50
504
  capabilities,
51
505
  };
@@ -1 +1 @@
1
- {"version":3,"file":"mysql-row-collector.js","sourceRoot":"","sources":["../src/mysql-row-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAUH,MAAM,CAAC,MAAM,gCAAgC,GAC3C,kHAAkH;IAClH,6EAA6E,CAAC;AAEhF,MAAM,UAAU,6BAA6B,CAAC,OAAuC;IACnF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,mBAAmB,CAAC;IAE3D,SAAS,YAAY;QACnB,MAAM,SAAS,GAAG;YAChB,YAAY,EAAE,aAAsB;YACpC,MAAM,EAAE,qFAAqF;SAC9F,CAAC;QACF,OAAO;YACL,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,SAAS;YAC7B,kBAAkB,EAAE,SAAS;YAC7B,gBAAgB,EAAE,SAAS;YAC3B,gBAAgB,EAAE,SAAS;YAC3B,aAAa,EAAE,SAAS;YACxB,YAAY,EAAE,SAAS;YACvB,gBAAgB,EAAE,SAAS;YAC3B,mBAAmB,EAAE,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,gCAAgC,EAAE;YAC9F,0BAA0B,EAAE,SAAS;SACtC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE,uBAAuB,SAAS,EAAE;QAE/C,KAAK,CAAC,QAA0B;YAC9B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC;QACzF,CAAC;QAED,IAAI;YACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,YAAY;KACb,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mysql-row-collector.js","sourceRoot":"","sources":["../src/mysql-row-collector.ts"],"names":[],"mappings":"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"}
@@ -1,44 +1,30 @@
1
1
  /**
2
2
  * RG-5(b): Postgres needs no preload — its own server-side statement log is
3
3
  * the capture mechanism, the way the plan calls for ("its logging path
4
- * needs no preload"). This reads one line of that log, already stripped of
5
- * whatever `log_line_prefix` a deployment configured (timestamp, pid,
6
- * database name — all deployment-specific and none of them this parser's
7
- * concern), and recognises exactly two shapes `log_statement = 'all'`
8
- * produces:
9
- *
10
- * - `LOG: statement: <sql>` — the simple-query protocol.
11
- * - `LOG: execute <name>: <sql>` — the extended/prepared-statement
12
- * protocol (`<name>` is `<unnamed>` for an unnamed prepared statement, or
13
- * a real name).
4
+ * needs no preload"). This reads that log line by line, whatever
5
+ * `log_line_prefix` a deployment configured (timestamp, pid, database name
6
+ * — all deployment-specific and none of them this parser's concern).
14
7
  *
15
8
  * Verified against PostgreSQL's own documented log format (`log_statement`,
16
9
  * `log_line_prefix`), not guessed, and now also **live-tested against a
17
10
  * real `postgres:16` Docker container** producing real `LOG: statement:`
18
11
  * lines (`postgres-query-collector.ts`'s `test/postgres-live.test.ts`) —
19
12
  * not just doc-verified syntax fed in by hand.
20
- *
21
- * **Disclosed, deliberate scope, same "refuse rather than guess" rule
22
- * `query-line-parser.ts` and `table-extraction.ts` already apply:**
23
- * - A statement split across multiple log lines (a long query Postgres
24
- * wraps) is read as written on its own line only — refused, not
25
- * reassembled, same as this package's other parsers stay bounded readers.
26
- * - `duration` is always `null` here: Postgres logs it on a **separate**
27
- * `LOG: duration: N ms` line, joined to the statement line only via
28
- * `log_duration`/`log_min_duration_statement` and the same backend pid —
29
- * a real correlation this parser does not attempt, so it reports what it
30
- * does not know rather than a fabricated duration.
31
- * - `success` is always `true` here: a failed statement logs as `ERROR:`,
32
- * a different prefix this parser does not recognise — refused (`null`),
33
- * not misread as a successful query.
34
13
  */
14
+ export declare const MAX_STATEMENT_CHARS: number;
35
15
  export interface PostgresLogQuery {
36
16
  readonly sql: string;
37
- readonly method: "statement" | "execute";
38
- readonly durationMs: null;
39
- readonly success: true;
40
- readonly error: null;
17
+ readonly method: "statement" | "execute" | "failed-statement";
18
+ readonly durationMs: number | null;
19
+ readonly success: boolean | null;
20
+ readonly outcomeKnown: boolean;
21
+ readonly error: string | null;
22
+ readonly sqlTruncated: boolean;
23
+ }
24
+ export interface PostgresLogReader {
25
+ push(line: string): readonly PostgresLogQuery[];
26
+ flush(): readonly PostgresLogQuery[];
41
27
  }
42
- /** `null` for anything not one of the two recognised `log_statement = 'all'` shapes — never a guessed reassembly. */
28
+ export declare function createPostgresLogReader(): PostgresLogReader;
43
29
  export declare function parsePostgresLogLine(line: string): PostgresLogQuery | null;
44
30
  //# sourceMappingURL=postgres-log-parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-log-parser.d.ts","sourceRoot":"","sources":["../src/postgres-log-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;CACtB;AAKD,qHAAqH;AACrH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAU1E"}
1
+ {"version":3,"file":"postgres-log-parser.d.ts","sourceRoot":"","sources":["../src/postgres-log-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,mBAAmB,QAAa,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AA0ED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,gBAAgB,EAAE,CAAC;IAChD,KAAK,IAAI,SAAS,gBAAgB,EAAE,CAAC;CACtC;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAyC3D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAG1E"}