@reproapp/node-sdk 0.0.39 → 0.0.42
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 +4 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +592 -2
- package/dist/ingest/client.d.ts +1 -1
- package/dist/ingest/client.js +156 -8
- package/dist/ingest/mapper.js +2 -0
- package/dist/ingest/types.d.ts +1 -0
- package/package.json +10 -4
- package/src/index.ts +651 -1
- package/src/ingest/client.ts +187 -10
- package/src/ingest/mapper.ts +1 -0
- package/src/ingest/types.ts +1 -0
- package/test/backend-live-mode.test.js +20 -2
- package/test/client-performance-regression.test.js +5 -0
- package/test/ingest-batching.test.js +67 -0
- package/test/postgresql-integration.test.js +302 -0
- package/test/postgresql-integrations.testcontainers.test.js +261 -0
- package/test/request-capture-background.test.js +6 -1
- package/test/request-manifest-priority.test.js +6 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchMongoDb = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
|
|
3
|
+
exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchMongoDb = exports.patchPostgreSql = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
|
|
4
4
|
const mongoose = require("mongoose");
|
|
5
5
|
const async_hooks_1 = require("async_hooks");
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
@@ -822,6 +822,27 @@ function buildRequestCaptureManifestPayload(scope, traceBatchTotal, closedAtMs)
|
|
|
822
822
|
closedAt,
|
|
823
823
|
};
|
|
824
824
|
}
|
|
825
|
+
function emitRequestCaptureStart(cfg, sessionId, actionId, scope, openedAtMs) {
|
|
826
|
+
if (!sessionId) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const openedAt = typeof openedAtMs === 'number' && Number.isFinite(openedAtMs)
|
|
830
|
+
? openedAtMs
|
|
831
|
+
: alignedNow();
|
|
832
|
+
post(cfg, sessionId, {
|
|
833
|
+
entries: [{
|
|
834
|
+
actionId: actionId ?? null,
|
|
835
|
+
requestRid: scope.requestRid,
|
|
836
|
+
requestCaptureStart: {
|
|
837
|
+
scopeId: `req:${scope.requestRid}`,
|
|
838
|
+
requestRid: scope.requestRid,
|
|
839
|
+
transport: scope.transport,
|
|
840
|
+
openedAt,
|
|
841
|
+
},
|
|
842
|
+
t: openedAt,
|
|
843
|
+
}],
|
|
844
|
+
}, { priority: 'critical' });
|
|
845
|
+
}
|
|
825
846
|
const als = new async_hooks_1.AsyncLocalStorage();
|
|
826
847
|
const getCtx = () => als.getStore() || {};
|
|
827
848
|
function normalizeNativeMongoSuppressionOp(op) {
|
|
@@ -964,7 +985,7 @@ const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
|
964
985
|
const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
|
|
965
986
|
const raw = String(process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS ?? '').trim().toLowerCase();
|
|
966
987
|
if (!raw) {
|
|
967
|
-
return
|
|
988
|
+
return 30000;
|
|
968
989
|
}
|
|
969
990
|
if (raw === 'off' || raw === 'never' || raw === 'infinite' || raw === 'infinity' || raw === '-1') {
|
|
970
991
|
return Number.POSITIVE_INFINITY;
|
|
@@ -4598,6 +4619,7 @@ function reproMiddleware(cfg) {
|
|
|
4598
4619
|
const clockSkewMs = headerTs !== null ? headerTs - requestStartRaw : 0;
|
|
4599
4620
|
const rid = nextRequestId(requestEpochMs);
|
|
4600
4621
|
const captureScope = createRequestCaptureScope(rid, 'http');
|
|
4622
|
+
emitRequestCaptureStart(captureCfg, sid, aid, captureScope, requestEpochMs);
|
|
4601
4623
|
const t0 = requestStartRaw;
|
|
4602
4624
|
const url = req.originalUrl || req.url || '/';
|
|
4603
4625
|
const urlPathOnly = (url || '/').split('?')[0] || '/';
|
|
@@ -6515,6 +6537,7 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
6515
6537
|
const span = captureSpanContextFromTracer();
|
|
6516
6538
|
const publishRid = nextRequestId(alignedNow());
|
|
6517
6539
|
const captureScope = createRequestCaptureScope(publishRid, 'kafka');
|
|
6540
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
6518
6541
|
const payloadObj = payload && typeof payload === 'object' ? payload : {};
|
|
6519
6542
|
const topic = sanitizeKafkaTopic(payloadObj.topic);
|
|
6520
6543
|
const rawMessages = Array.isArray(payloadObj.messages) ? payloadObj.messages : [];
|
|
@@ -6623,6 +6646,7 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
6623
6646
|
const span = captureSpanContextFromTracer();
|
|
6624
6647
|
const publishRid = nextRequestId(alignedNow());
|
|
6625
6648
|
const captureScope = createRequestCaptureScope(publishRid, 'kafka');
|
|
6649
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
6626
6650
|
const payloadObj = payload && typeof payload === 'object' ? payload : {};
|
|
6627
6651
|
const topicMessages = Array.isArray(payloadObj.topicMessages)
|
|
6628
6652
|
? payloadObj.topicMessages
|
|
@@ -6764,6 +6788,7 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
|
|
|
6764
6788
|
const consumeRid = nextRequestId(`${topic}-${message?.offset ?? alignedNow()}`);
|
|
6765
6789
|
const traceId = consumeRid;
|
|
6766
6790
|
const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
|
|
6791
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
6767
6792
|
const rawTraceEvents = [];
|
|
6768
6793
|
const maskReq = {
|
|
6769
6794
|
method: 'KAFKA_CONSUME',
|
|
@@ -6878,6 +6903,7 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
|
|
|
6878
6903
|
const consumeRid = nextRequestId(`${topic}-batch-${alignedNow()}`);
|
|
6879
6904
|
const traceId = consumeRid;
|
|
6880
6905
|
const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
|
|
6906
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
6881
6907
|
const rawTraceEvents = [];
|
|
6882
6908
|
const maskReq = {
|
|
6883
6909
|
method: 'KAFKA_CONSUME_BATCH',
|
|
@@ -7506,6 +7532,7 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
|
|
|
7506
7532
|
const key = `${method} ${methodName === 'publish' ? `${exchange || 'default'}/${routingKey}` : queue}`;
|
|
7507
7533
|
const content = methodName === 'publish' ? args[2] : args[1];
|
|
7508
7534
|
const captureScope = createRequestCaptureScope(publishRid, 'amqp');
|
|
7535
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
7509
7536
|
const t0 = Date.now();
|
|
7510
7537
|
let finished = false;
|
|
7511
7538
|
const finish = (status, error, result) => {
|
|
@@ -7592,6 +7619,7 @@ function wrapAmqplibConsumeHandler(onMessage, cfg, queue) {
|
|
|
7592
7619
|
const consumeRid = nextRequestId(`${queueName}-${deliveryTag}`);
|
|
7593
7620
|
const traceId = consumeRid;
|
|
7594
7621
|
const captureScope = createRequestCaptureScope(consumeRid, 'amqp');
|
|
7622
|
+
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
7595
7623
|
const rawTraceEvents = [];
|
|
7596
7624
|
const maskReq = {
|
|
7597
7625
|
method: 'AMQP_CONSUME',
|
|
@@ -8154,6 +8182,564 @@ function patchRedis(cfg) {
|
|
|
8154
8182
|
}
|
|
8155
8183
|
}
|
|
8156
8184
|
exports.patchRedis = patchRedis;
|
|
8185
|
+
const postgresSqlPatchConfigs = [];
|
|
8186
|
+
const postgresSqlSourceAls = new async_hooks_1.AsyncLocalStorage();
|
|
8187
|
+
const pgPoolQueryAls = new async_hooks_1.AsyncLocalStorage();
|
|
8188
|
+
let pgRequireHookInstalled = false;
|
|
8189
|
+
let postgresJsRequireHookInstalled = false;
|
|
8190
|
+
let typeOrmRequireHookInstalled = false;
|
|
8191
|
+
const PG_CLIENT_PATCHED = Symbol.for('@reproapp/node-sdk/pg-client-patched');
|
|
8192
|
+
const PG_POOL_PATCHED = Symbol.for('@reproapp/node-sdk/pg-pool-patched');
|
|
8193
|
+
const POSTGRES_JS_QUERY_PATCHED = Symbol.for('@reproapp/node-sdk/postgres-js-query-patched');
|
|
8194
|
+
const TYPEORM_DATASOURCE_PATCHED = Symbol.for('@reproapp/node-sdk/typeorm-datasource-patched');
|
|
8195
|
+
const TYPEORM_QUERY_RUNNER_PATCHED = Symbol.for('@reproapp/node-sdk/typeorm-query-runner-patched');
|
|
8196
|
+
function registerPostgreSqlPatchConfig(cfg) {
|
|
8197
|
+
if (!postgresSqlPatchConfigs.includes(cfg)) {
|
|
8198
|
+
postgresSqlPatchConfigs.push(cfg);
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
function resolvePostgreSqlCaptureContext(defaultSource, source) {
|
|
8202
|
+
const ctx = getCtx();
|
|
8203
|
+
const contextualSource = postgresSqlSourceAls.getStore();
|
|
8204
|
+
for (let i = postgresSqlPatchConfigs.length - 1; i >= 0; i -= 1) {
|
|
8205
|
+
const cfg = postgresSqlPatchConfigs[i];
|
|
8206
|
+
if (!cfg)
|
|
8207
|
+
continue;
|
|
8208
|
+
const fallback = cfg.resolveContext?.() ?? {};
|
|
8209
|
+
const sid = ctx.sid ?? fallback.sid ?? null;
|
|
8210
|
+
if (!sid)
|
|
8211
|
+
continue;
|
|
8212
|
+
return {
|
|
8213
|
+
cfg,
|
|
8214
|
+
sid,
|
|
8215
|
+
aid: ctx.aid ?? fallback.aid ?? null,
|
|
8216
|
+
spanContext: captureSpanContextFromTracer(source),
|
|
8217
|
+
source: contextualSource ?? defaultSource,
|
|
8218
|
+
};
|
|
8219
|
+
}
|
|
8220
|
+
return null;
|
|
8221
|
+
}
|
|
8222
|
+
function stripSqlComments(sql) {
|
|
8223
|
+
let remaining = sql.trimStart();
|
|
8224
|
+
while (remaining.length) {
|
|
8225
|
+
if (remaining.startsWith('--')) {
|
|
8226
|
+
const newline = remaining.indexOf('\n');
|
|
8227
|
+
remaining = newline < 0 ? '' : remaining.slice(newline + 1).trimStart();
|
|
8228
|
+
continue;
|
|
8229
|
+
}
|
|
8230
|
+
if (remaining.startsWith('/*')) {
|
|
8231
|
+
const end = remaining.indexOf('*/', 2);
|
|
8232
|
+
remaining = end < 0 ? '' : remaining.slice(end + 2).trimStart();
|
|
8233
|
+
continue;
|
|
8234
|
+
}
|
|
8235
|
+
break;
|
|
8236
|
+
}
|
|
8237
|
+
return remaining;
|
|
8238
|
+
}
|
|
8239
|
+
function normalizeSqlOperation(sql) {
|
|
8240
|
+
const normalized = stripSqlComments(sql);
|
|
8241
|
+
const first = normalized.match(/^([a-z]+)/i)?.[1]?.toLowerCase() ?? 'query';
|
|
8242
|
+
if (first !== 'with')
|
|
8243
|
+
return first;
|
|
8244
|
+
// CTEs can wrap any DML statement. The last top-level DML keyword is the
|
|
8245
|
+
// operation users care about, while nested SELECTs only build the CTE.
|
|
8246
|
+
const matches = Array.from(normalized.matchAll(/\b(select|insert|update|delete|merge)\b/gi));
|
|
8247
|
+
return matches.length ? String(matches[matches.length - 1][1]).toLowerCase() : 'query';
|
|
8248
|
+
}
|
|
8249
|
+
function cleanSqlIdentifier(value) {
|
|
8250
|
+
if (!value)
|
|
8251
|
+
return undefined;
|
|
8252
|
+
const cleaned = value
|
|
8253
|
+
.trim()
|
|
8254
|
+
.replace(/[;,]$/, '')
|
|
8255
|
+
.split('.')
|
|
8256
|
+
.map((part) => part.replace(/^['"`]|['"`]$/g, ''))
|
|
8257
|
+
.join('.');
|
|
8258
|
+
return cleaned || undefined;
|
|
8259
|
+
}
|
|
8260
|
+
function resolveSqlTable(sql, op) {
|
|
8261
|
+
const normalized = stripSqlComments(sql);
|
|
8262
|
+
let match = null;
|
|
8263
|
+
if (op === 'insert')
|
|
8264
|
+
match = normalized.match(/\binsert\s+into\s+([^\s(]+)/i);
|
|
8265
|
+
else if (op === 'update')
|
|
8266
|
+
match = normalized.match(/\bupdate\s+([^\s(]+)/i);
|
|
8267
|
+
else if (op === 'delete')
|
|
8268
|
+
match = normalized.match(/\bdelete\s+from\s+([^\s(]+)/i);
|
|
8269
|
+
else if (op === 'merge')
|
|
8270
|
+
match = normalized.match(/\bmerge\s+into\s+([^\s(]+)/i);
|
|
8271
|
+
else
|
|
8272
|
+
match = normalized.match(/\bfrom\s+([^\s(]+)/i);
|
|
8273
|
+
return cleanSqlIdentifier(match?.[1]) ?? 'unknown';
|
|
8274
|
+
}
|
|
8275
|
+
function buildPostgresQueryPayload(sql, parameters, source, extra) {
|
|
8276
|
+
return {
|
|
8277
|
+
sql,
|
|
8278
|
+
parameters,
|
|
8279
|
+
library: source.library,
|
|
8280
|
+
driver: source.driver,
|
|
8281
|
+
...(extra ?? {}),
|
|
8282
|
+
};
|
|
8283
|
+
}
|
|
8284
|
+
function summarizePostgresError(error) {
|
|
8285
|
+
return {
|
|
8286
|
+
name: error?.name ?? 'Error',
|
|
8287
|
+
message: error?.message ?? String(error),
|
|
8288
|
+
code: error?.code,
|
|
8289
|
+
severity: error?.severity,
|
|
8290
|
+
detail: error?.detail,
|
|
8291
|
+
hint: error?.hint,
|
|
8292
|
+
position: error?.position,
|
|
8293
|
+
internalPosition: error?.internalPosition,
|
|
8294
|
+
internalQuery: error?.internalQuery,
|
|
8295
|
+
where: error?.where,
|
|
8296
|
+
schema: error?.schema,
|
|
8297
|
+
table: error?.table,
|
|
8298
|
+
column: error?.column,
|
|
8299
|
+
dataType: error?.dataType,
|
|
8300
|
+
constraint: error?.constraint,
|
|
8301
|
+
file: error?.file,
|
|
8302
|
+
line: error?.line,
|
|
8303
|
+
routine: error?.routine,
|
|
8304
|
+
};
|
|
8305
|
+
}
|
|
8306
|
+
function normalizePgQueryInput(config, values) {
|
|
8307
|
+
if (typeof config === 'string') {
|
|
8308
|
+
return { sql: config, parameters: Array.isArray(values) ? values : [] };
|
|
8309
|
+
}
|
|
8310
|
+
const sql = typeof config?.text === 'string' ? config.text : '';
|
|
8311
|
+
const parameters = Array.isArray(config?.values)
|
|
8312
|
+
? config.values
|
|
8313
|
+
: Array.isArray(values)
|
|
8314
|
+
? values
|
|
8315
|
+
: [];
|
|
8316
|
+
return {
|
|
8317
|
+
sql,
|
|
8318
|
+
parameters,
|
|
8319
|
+
extra: {
|
|
8320
|
+
name: typeof config?.name === 'string' ? config.name : undefined,
|
|
8321
|
+
rowMode: config?.rowMode,
|
|
8322
|
+
binary: config?.binary,
|
|
8323
|
+
},
|
|
8324
|
+
};
|
|
8325
|
+
}
|
|
8326
|
+
function normalizePgResult(result) {
|
|
8327
|
+
if (Array.isArray(result))
|
|
8328
|
+
return result.map(normalizePgResult);
|
|
8329
|
+
if (!result || typeof result !== 'object')
|
|
8330
|
+
return result;
|
|
8331
|
+
return {
|
|
8332
|
+
command: result.command,
|
|
8333
|
+
rowCount: result.rowCount,
|
|
8334
|
+
oid: result.oid,
|
|
8335
|
+
fields: Array.isArray(result.fields)
|
|
8336
|
+
? result.fields.map((field) => ({
|
|
8337
|
+
name: field?.name,
|
|
8338
|
+
tableID: field?.tableID,
|
|
8339
|
+
columnID: field?.columnID,
|
|
8340
|
+
dataTypeID: field?.dataTypeID,
|
|
8341
|
+
dataTypeSize: field?.dataTypeSize,
|
|
8342
|
+
dataTypeModifier: field?.dataTypeModifier,
|
|
8343
|
+
format: field?.format,
|
|
8344
|
+
}))
|
|
8345
|
+
: undefined,
|
|
8346
|
+
rows: result.rows,
|
|
8347
|
+
};
|
|
8348
|
+
}
|
|
8349
|
+
function emitPostgreSqlResult(capture, sql, parameters, startedAt, result, error, extra) {
|
|
8350
|
+
const op = normalizeSqlOperation(sql);
|
|
8351
|
+
emitDbQuery(capture.cfg, capture.sid, capture.aid ?? undefined, {
|
|
8352
|
+
type: 'postgresql',
|
|
8353
|
+
collection: resolveSqlTable(sql, op),
|
|
8354
|
+
op,
|
|
8355
|
+
queryRaw: buildPostgresQueryPayload(sql, parameters, capture.source, extra),
|
|
8356
|
+
resultMetaRaw: error ? undefined : result,
|
|
8357
|
+
error: error ? summarizePostgresError(error) : undefined,
|
|
8358
|
+
durMs: Date.now() - startedAt,
|
|
8359
|
+
t: alignedNow(),
|
|
8360
|
+
spanContext: capture.spanContext,
|
|
8361
|
+
});
|
|
8362
|
+
}
|
|
8363
|
+
function findPgCallbackIndex(args) {
|
|
8364
|
+
for (let i = args.length - 1; i >= 1; i -= 1) {
|
|
8365
|
+
if (typeof args[i] === 'function')
|
|
8366
|
+
return i;
|
|
8367
|
+
}
|
|
8368
|
+
return -1;
|
|
8369
|
+
}
|
|
8370
|
+
function patchPgClientPrototype(proto) {
|
|
8371
|
+
if (!proto || proto[PG_CLIENT_PATCHED])
|
|
8372
|
+
return;
|
|
8373
|
+
const original = proto.query;
|
|
8374
|
+
if (typeof original !== 'function')
|
|
8375
|
+
return;
|
|
8376
|
+
try {
|
|
8377
|
+
Object.defineProperty(proto, PG_CLIENT_PATCHED, { value: true, configurable: true });
|
|
8378
|
+
}
|
|
8379
|
+
catch {
|
|
8380
|
+
return;
|
|
8381
|
+
}
|
|
8382
|
+
proto.query = function reproPatchedPgQuery(...args) {
|
|
8383
|
+
if (pgPoolQueryAls.getStore())
|
|
8384
|
+
return original.apply(this, args);
|
|
8385
|
+
const capture = resolvePostgreSqlCaptureContext({ library: 'pg', driver: 'pg' }, this);
|
|
8386
|
+
if (!capture)
|
|
8387
|
+
return original.apply(this, args);
|
|
8388
|
+
const input = normalizePgQueryInput(args[0], args[1]);
|
|
8389
|
+
const startedAt = Date.now();
|
|
8390
|
+
const callbackIndex = findPgCallbackIndex(args);
|
|
8391
|
+
const actualArgs = callbackIndex >= 0 ? [...args] : args;
|
|
8392
|
+
let emitted = false;
|
|
8393
|
+
const emitSuccess = (result) => {
|
|
8394
|
+
if (emitted)
|
|
8395
|
+
return;
|
|
8396
|
+
emitted = true;
|
|
8397
|
+
emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, normalizePgResult(result), undefined, input.extra);
|
|
8398
|
+
};
|
|
8399
|
+
const emitFailure = (error) => {
|
|
8400
|
+
if (emitted)
|
|
8401
|
+
return;
|
|
8402
|
+
emitted = true;
|
|
8403
|
+
emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, undefined, error, input.extra);
|
|
8404
|
+
};
|
|
8405
|
+
if (callbackIndex >= 0) {
|
|
8406
|
+
const callback = args[callbackIndex];
|
|
8407
|
+
actualArgs[callbackIndex] = function reproPgQueryCallback(error, result, ...rest) {
|
|
8408
|
+
if (error)
|
|
8409
|
+
emitFailure(error);
|
|
8410
|
+
else
|
|
8411
|
+
emitSuccess(result);
|
|
8412
|
+
return callback.call(this, error, result, ...rest);
|
|
8413
|
+
};
|
|
8414
|
+
}
|
|
8415
|
+
try {
|
|
8416
|
+
const returned = original.apply(this, actualArgs);
|
|
8417
|
+
if (returned && typeof returned.then === 'function') {
|
|
8418
|
+
return returned.then((result) => {
|
|
8419
|
+
emitSuccess(result);
|
|
8420
|
+
return result;
|
|
8421
|
+
}, (error) => {
|
|
8422
|
+
emitFailure(error);
|
|
8423
|
+
throw error;
|
|
8424
|
+
});
|
|
8425
|
+
}
|
|
8426
|
+
if (returned && callbackIndex < 0 && typeof returned.once === 'function') {
|
|
8427
|
+
returned.once('end', emitSuccess);
|
|
8428
|
+
returned.once('error', emitFailure);
|
|
8429
|
+
}
|
|
8430
|
+
return returned;
|
|
8431
|
+
}
|
|
8432
|
+
catch (error) {
|
|
8433
|
+
emitFailure(error);
|
|
8434
|
+
throw error;
|
|
8435
|
+
}
|
|
8436
|
+
};
|
|
8437
|
+
}
|
|
8438
|
+
function patchPgPoolPrototype(proto) {
|
|
8439
|
+
if (!proto || proto[PG_POOL_PATCHED])
|
|
8440
|
+
return;
|
|
8441
|
+
const original = proto.query;
|
|
8442
|
+
if (typeof original !== 'function')
|
|
8443
|
+
return;
|
|
8444
|
+
try {
|
|
8445
|
+
Object.defineProperty(proto, PG_POOL_PATCHED, { value: true, configurable: true });
|
|
8446
|
+
}
|
|
8447
|
+
catch {
|
|
8448
|
+
return;
|
|
8449
|
+
}
|
|
8450
|
+
proto.query = function reproPatchedPgPoolQuery(...args) {
|
|
8451
|
+
const capture = resolvePostgreSqlCaptureContext({ library: 'pg', driver: 'pg' }, this);
|
|
8452
|
+
if (!capture)
|
|
8453
|
+
return original.apply(this, args);
|
|
8454
|
+
const input = normalizePgQueryInput(args[0], args[1]);
|
|
8455
|
+
const startedAt = Date.now();
|
|
8456
|
+
const callbackIndex = findPgCallbackIndex(args);
|
|
8457
|
+
const actualArgs = callbackIndex >= 0 ? [...args] : args;
|
|
8458
|
+
let emitted = false;
|
|
8459
|
+
const emitSuccess = (result) => {
|
|
8460
|
+
if (emitted)
|
|
8461
|
+
return;
|
|
8462
|
+
emitted = true;
|
|
8463
|
+
emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, normalizePgResult(result), undefined, input.extra);
|
|
8464
|
+
};
|
|
8465
|
+
const emitFailure = (error) => {
|
|
8466
|
+
if (emitted)
|
|
8467
|
+
return;
|
|
8468
|
+
emitted = true;
|
|
8469
|
+
emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, undefined, error, input.extra);
|
|
8470
|
+
};
|
|
8471
|
+
if (callbackIndex >= 0) {
|
|
8472
|
+
const callback = args[callbackIndex];
|
|
8473
|
+
actualArgs[callbackIndex] = function reproPgPoolQueryCallback(error, result, ...rest) {
|
|
8474
|
+
if (error)
|
|
8475
|
+
emitFailure(error);
|
|
8476
|
+
else
|
|
8477
|
+
emitSuccess(result);
|
|
8478
|
+
return callback.call(this, error, result, ...rest);
|
|
8479
|
+
};
|
|
8480
|
+
}
|
|
8481
|
+
try {
|
|
8482
|
+
const returned = pgPoolQueryAls.run(true, () => original.apply(this, actualArgs));
|
|
8483
|
+
if (returned && typeof returned.then === 'function') {
|
|
8484
|
+
return returned.then((result) => {
|
|
8485
|
+
emitSuccess(result);
|
|
8486
|
+
return result;
|
|
8487
|
+
}, (error) => {
|
|
8488
|
+
emitFailure(error);
|
|
8489
|
+
throw error;
|
|
8490
|
+
});
|
|
8491
|
+
}
|
|
8492
|
+
return returned;
|
|
8493
|
+
}
|
|
8494
|
+
catch (error) {
|
|
8495
|
+
emitFailure(error);
|
|
8496
|
+
throw error;
|
|
8497
|
+
}
|
|
8498
|
+
};
|
|
8499
|
+
}
|
|
8500
|
+
function patchPgFromModuleExports(pgModule) {
|
|
8501
|
+
if (!pgModule)
|
|
8502
|
+
return;
|
|
8503
|
+
const candidates = [pgModule, pgModule.default];
|
|
8504
|
+
for (const candidate of candidates) {
|
|
8505
|
+
patchPgClientPrototype(candidate?.Client?.prototype);
|
|
8506
|
+
patchPgClientPrototype(candidate?.native?.Client?.prototype);
|
|
8507
|
+
patchPgPoolPrototype(candidate?.Pool?.prototype);
|
|
8508
|
+
patchPgPoolPrototype(candidate?.native?.Pool?.prototype);
|
|
8509
|
+
}
|
|
8510
|
+
}
|
|
8511
|
+
function installPgRequireHook() {
|
|
8512
|
+
if (pgRequireHookInstalled)
|
|
8513
|
+
return;
|
|
8514
|
+
pgRequireHookInstalled = true;
|
|
8515
|
+
try {
|
|
8516
|
+
const rim = requireOptionalHostModule('require-in-the-middle');
|
|
8517
|
+
const Hook = rim?.Hook ?? rim;
|
|
8518
|
+
if (typeof Hook !== 'function')
|
|
8519
|
+
return;
|
|
8520
|
+
// eslint-disable-next-line no-new
|
|
8521
|
+
new Hook(['pg'], (exports) => {
|
|
8522
|
+
patchPgFromModuleExports(exports);
|
|
8523
|
+
return exports;
|
|
8524
|
+
});
|
|
8525
|
+
}
|
|
8526
|
+
catch { }
|
|
8527
|
+
}
|
|
8528
|
+
function normalizePostgresJsInput(query) {
|
|
8529
|
+
if (typeof query?.statement?.string === 'string') {
|
|
8530
|
+
return {
|
|
8531
|
+
sql: query.statement.string,
|
|
8532
|
+
parameters: Array.isArray(query?.parameters) ? query.parameters : [],
|
|
8533
|
+
extra: {
|
|
8534
|
+
tagged: query?.tagged === true,
|
|
8535
|
+
parameterTypes: Array.isArray(query?.statement?.types) ? query.statement.types : undefined,
|
|
8536
|
+
},
|
|
8537
|
+
};
|
|
8538
|
+
}
|
|
8539
|
+
const strings = Array.isArray(query?.strings) ? query.strings : [];
|
|
8540
|
+
const parameters = Array.isArray(query?.args) ? query.args : [];
|
|
8541
|
+
if (query?.tagged) {
|
|
8542
|
+
return {
|
|
8543
|
+
sql: strings.map((part, index) => `${String(part)}${index < parameters.length ? `$${index + 1}` : ''}`).join(''),
|
|
8544
|
+
parameters,
|
|
8545
|
+
extra: { tagged: true },
|
|
8546
|
+
};
|
|
8547
|
+
}
|
|
8548
|
+
return {
|
|
8549
|
+
sql: typeof strings[0] === 'string' ? strings[0] : '',
|
|
8550
|
+
parameters,
|
|
8551
|
+
extra: { tagged: false },
|
|
8552
|
+
};
|
|
8553
|
+
}
|
|
8554
|
+
function normalizePostgresJsResult(result) {
|
|
8555
|
+
if (!Array.isArray(result))
|
|
8556
|
+
return result;
|
|
8557
|
+
const metadata = result;
|
|
8558
|
+
return {
|
|
8559
|
+
command: metadata.command,
|
|
8560
|
+
count: metadata.count,
|
|
8561
|
+
columns: Array.isArray(metadata.columns)
|
|
8562
|
+
? metadata.columns.map((column) => ({
|
|
8563
|
+
name: column?.name,
|
|
8564
|
+
type: column?.type,
|
|
8565
|
+
table: column?.table,
|
|
8566
|
+
number: column?.number,
|
|
8567
|
+
}))
|
|
8568
|
+
: undefined,
|
|
8569
|
+
rows: Array.from(result),
|
|
8570
|
+
};
|
|
8571
|
+
}
|
|
8572
|
+
function patchPostgresJsQueryPrototype(proto) {
|
|
8573
|
+
if (!proto || proto[POSTGRES_JS_QUERY_PATCHED])
|
|
8574
|
+
return;
|
|
8575
|
+
const originalHandle = proto.handle;
|
|
8576
|
+
if (typeof originalHandle !== 'function')
|
|
8577
|
+
return;
|
|
8578
|
+
try {
|
|
8579
|
+
Object.defineProperty(proto, POSTGRES_JS_QUERY_PATCHED, { value: true, configurable: true });
|
|
8580
|
+
}
|
|
8581
|
+
catch {
|
|
8582
|
+
return;
|
|
8583
|
+
}
|
|
8584
|
+
proto.handle = function reproPatchedPostgresJsHandle(...args) {
|
|
8585
|
+
if (!this.__repro_postgres_capture_attached) {
|
|
8586
|
+
const capture = resolvePostgreSqlCaptureContext({ library: 'postgres', driver: 'postgres' }, this);
|
|
8587
|
+
if (capture) {
|
|
8588
|
+
try {
|
|
8589
|
+
Object.defineProperty(this, '__repro_postgres_capture_attached', { value: true, configurable: true });
|
|
8590
|
+
}
|
|
8591
|
+
catch {
|
|
8592
|
+
this.__repro_postgres_capture_attached = true;
|
|
8593
|
+
}
|
|
8594
|
+
const input = normalizePostgresJsInput(this);
|
|
8595
|
+
const startedAt = Date.now();
|
|
8596
|
+
Promise.prototype.then.call(this, (result) => {
|
|
8597
|
+
const executedInput = normalizePostgresJsInput(this);
|
|
8598
|
+
emitPostgreSqlResult(capture, executedInput.sql || input.sql, executedInput.parameters, startedAt, normalizePostgresJsResult(result), undefined, executedInput.extra);
|
|
8599
|
+
return result;
|
|
8600
|
+
}, (error) => {
|
|
8601
|
+
const executedInput = normalizePostgresJsInput(this);
|
|
8602
|
+
emitPostgreSqlResult(capture, executedInput.sql || input.sql, executedInput.parameters.length ? executedInput.parameters : input.parameters, startedAt, undefined, error, executedInput.extra);
|
|
8603
|
+
});
|
|
8604
|
+
}
|
|
8605
|
+
}
|
|
8606
|
+
return originalHandle.apply(this, args);
|
|
8607
|
+
};
|
|
8608
|
+
}
|
|
8609
|
+
function patchPostgresJsFromModuleExports(postgresModule) {
|
|
8610
|
+
const factories = new Set();
|
|
8611
|
+
const addFactory = (candidate) => {
|
|
8612
|
+
if (typeof candidate !== 'function')
|
|
8613
|
+
return;
|
|
8614
|
+
// getLoadedModuleExportsByPackage also returns internal postgres.js
|
|
8615
|
+
// helpers. Only the public factory carries these static exports.
|
|
8616
|
+
if (!candidate.PostgresError && !candidate.BigInt && !candidate.__repro_postgres_factory)
|
|
8617
|
+
return;
|
|
8618
|
+
factories.add(candidate);
|
|
8619
|
+
};
|
|
8620
|
+
addFactory(postgresModule);
|
|
8621
|
+
addFactory(postgresModule?.default);
|
|
8622
|
+
for (const factory of factories) {
|
|
8623
|
+
let sql;
|
|
8624
|
+
try {
|
|
8625
|
+
sql = factory({ max: 1, idle_timeout: 1, connect_timeout: 1 });
|
|
8626
|
+
const query = sql.unsafe('select 1');
|
|
8627
|
+
patchPostgresJsQueryPrototype(Object.getPrototypeOf(query));
|
|
8628
|
+
}
|
|
8629
|
+
catch { }
|
|
8630
|
+
try {
|
|
8631
|
+
const ended = sql?.end?.({ timeout: 0 });
|
|
8632
|
+
if (ended && typeof ended.catch === 'function')
|
|
8633
|
+
ended.catch(() => undefined);
|
|
8634
|
+
}
|
|
8635
|
+
catch { }
|
|
8636
|
+
}
|
|
8637
|
+
}
|
|
8638
|
+
function installPostgresJsRequireHook() {
|
|
8639
|
+
if (postgresJsRequireHookInstalled)
|
|
8640
|
+
return;
|
|
8641
|
+
postgresJsRequireHookInstalled = true;
|
|
8642
|
+
try {
|
|
8643
|
+
const rim = requireOptionalHostModule('require-in-the-middle');
|
|
8644
|
+
const Hook = rim?.Hook ?? rim;
|
|
8645
|
+
if (typeof Hook !== 'function')
|
|
8646
|
+
return;
|
|
8647
|
+
// eslint-disable-next-line no-new
|
|
8648
|
+
new Hook(['postgres'], (exports) => {
|
|
8649
|
+
patchPostgresJsFromModuleExports(exports);
|
|
8650
|
+
return exports;
|
|
8651
|
+
});
|
|
8652
|
+
}
|
|
8653
|
+
catch { }
|
|
8654
|
+
}
|
|
8655
|
+
function patchTypeOrmQueryRunner(queryRunner) {
|
|
8656
|
+
if (!queryRunner || queryRunner[TYPEORM_QUERY_RUNNER_PATCHED])
|
|
8657
|
+
return queryRunner;
|
|
8658
|
+
const original = queryRunner.query;
|
|
8659
|
+
if (typeof original !== 'function')
|
|
8660
|
+
return queryRunner;
|
|
8661
|
+
try {
|
|
8662
|
+
Object.defineProperty(queryRunner, TYPEORM_QUERY_RUNNER_PATCHED, { value: true, configurable: true });
|
|
8663
|
+
}
|
|
8664
|
+
catch {
|
|
8665
|
+
return queryRunner;
|
|
8666
|
+
}
|
|
8667
|
+
queryRunner.query = function reproPatchedTypeOrmQuery(...args) {
|
|
8668
|
+
return postgresSqlSourceAls.run({ library: 'typeorm', driver: 'pg' }, () => original.apply(this, args));
|
|
8669
|
+
};
|
|
8670
|
+
return queryRunner;
|
|
8671
|
+
}
|
|
8672
|
+
function patchTypeOrmDataSourcePrototype(proto) {
|
|
8673
|
+
if (!proto || proto[TYPEORM_DATASOURCE_PATCHED])
|
|
8674
|
+
return;
|
|
8675
|
+
const original = proto.createQueryRunner;
|
|
8676
|
+
if (typeof original !== 'function')
|
|
8677
|
+
return;
|
|
8678
|
+
try {
|
|
8679
|
+
Object.defineProperty(proto, TYPEORM_DATASOURCE_PATCHED, { value: true, configurable: true });
|
|
8680
|
+
}
|
|
8681
|
+
catch {
|
|
8682
|
+
return;
|
|
8683
|
+
}
|
|
8684
|
+
proto.createQueryRunner = function reproPatchedCreateQueryRunner(...args) {
|
|
8685
|
+
return patchTypeOrmQueryRunner(original.apply(this, args));
|
|
8686
|
+
};
|
|
8687
|
+
}
|
|
8688
|
+
function patchTypeOrmFromModuleExports(typeOrmModule) {
|
|
8689
|
+
if (!typeOrmModule)
|
|
8690
|
+
return;
|
|
8691
|
+
patchTypeOrmDataSourcePrototype(typeOrmModule?.DataSource?.prototype);
|
|
8692
|
+
patchTypeOrmDataSourcePrototype(typeOrmModule?.Connection?.prototype);
|
|
8693
|
+
patchTypeOrmDataSourcePrototype(typeOrmModule?.default?.DataSource?.prototype);
|
|
8694
|
+
}
|
|
8695
|
+
function installTypeOrmRequireHook() {
|
|
8696
|
+
if (typeOrmRequireHookInstalled)
|
|
8697
|
+
return;
|
|
8698
|
+
typeOrmRequireHookInstalled = true;
|
|
8699
|
+
try {
|
|
8700
|
+
const rim = requireOptionalHostModule('require-in-the-middle');
|
|
8701
|
+
const Hook = rim?.Hook ?? rim;
|
|
8702
|
+
if (typeof Hook !== 'function')
|
|
8703
|
+
return;
|
|
8704
|
+
// eslint-disable-next-line no-new
|
|
8705
|
+
new Hook(['typeorm'], (exports) => {
|
|
8706
|
+
patchTypeOrmFromModuleExports(exports);
|
|
8707
|
+
return exports;
|
|
8708
|
+
});
|
|
8709
|
+
}
|
|
8710
|
+
catch { }
|
|
8711
|
+
}
|
|
8712
|
+
function patchPostgreSql(cfg) {
|
|
8713
|
+
registerPostgreSqlPatchConfig(cfg);
|
|
8714
|
+
installPgRequireHook();
|
|
8715
|
+
installPostgresJsRequireHook();
|
|
8716
|
+
installTypeOrmRequireHook();
|
|
8717
|
+
const pgModules = new Set();
|
|
8718
|
+
const pg = requireOptionalHostModule('pg');
|
|
8719
|
+
if (pg)
|
|
8720
|
+
pgModules.add(pg);
|
|
8721
|
+
for (const loaded of getLoadedModuleExportsByPackage('pg'))
|
|
8722
|
+
pgModules.add(loaded);
|
|
8723
|
+
for (const loaded of pgModules)
|
|
8724
|
+
patchPgFromModuleExports(loaded);
|
|
8725
|
+
const postgresModules = new Set();
|
|
8726
|
+
const postgres = requireOptionalHostModule('postgres');
|
|
8727
|
+
if (postgres)
|
|
8728
|
+
postgresModules.add(postgres);
|
|
8729
|
+
for (const loaded of getLoadedModuleExportsByPackage('postgres'))
|
|
8730
|
+
postgresModules.add(loaded);
|
|
8731
|
+
for (const loaded of postgresModules)
|
|
8732
|
+
patchPostgresJsFromModuleExports(loaded);
|
|
8733
|
+
const typeOrmModules = new Set();
|
|
8734
|
+
const typeOrm = requireOptionalHostModule('typeorm');
|
|
8735
|
+
if (typeOrm)
|
|
8736
|
+
typeOrmModules.add(typeOrm);
|
|
8737
|
+
for (const loaded of getLoadedModuleExportsByPackage('typeorm'))
|
|
8738
|
+
typeOrmModules.add(loaded);
|
|
8739
|
+
for (const loaded of typeOrmModules)
|
|
8740
|
+
patchTypeOrmFromModuleExports(loaded);
|
|
8741
|
+
}
|
|
8742
|
+
exports.patchPostgreSql = patchPostgreSql;
|
|
8157
8743
|
const mongoDbPatchConfigs = [];
|
|
8158
8744
|
let mongoDbRequireHookInstalled = false;
|
|
8159
8745
|
let mongoDbImportHookInstalled = false;
|
|
@@ -9244,6 +9830,7 @@ async function initRepro(cfg) {
|
|
|
9244
9830
|
patchKafkaJs(integrationCfg);
|
|
9245
9831
|
patchAmqplib(integrationCfg);
|
|
9246
9832
|
patchRedis(integrationCfg);
|
|
9833
|
+
patchPostgreSql(integrationCfg);
|
|
9247
9834
|
patchMongoDb(integrationCfg);
|
|
9248
9835
|
await installMongoDbImportHook();
|
|
9249
9836
|
patchSendgridMail(integrationCfg);
|
|
@@ -9306,6 +9893,9 @@ exports.__reproTestHooks = {
|
|
|
9306
9893
|
patchAmqplibConnectionForTest: patchAmqplibConnection,
|
|
9307
9894
|
patchAmqplibChannelForTest: patchAmqplibChannel,
|
|
9308
9895
|
wrapAmqplibConsumeHandlerForTest: wrapAmqplibConsumeHandler,
|
|
9896
|
+
patchPgModuleForTest: patchPgFromModuleExports,
|
|
9897
|
+
patchPostgresJsModuleForTest: patchPostgresJsFromModuleExports,
|
|
9898
|
+
patchTypeOrmModuleForTest: patchTypeOrmFromModuleExports,
|
|
9309
9899
|
patchMongoDbModuleForTest: patchMongoDbFromModuleExports,
|
|
9310
9900
|
patchMongoCollectionPrototypeForTest: patchMongoCollectionPrototype,
|
|
9311
9901
|
chunkTraceEventsForTransportForTest: chunkTraceEventsForTransport,
|
package/dist/ingest/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IngestClientConfig, LegacyEntry } from './types';
|
|
2
2
|
export type EnqueueIngestOptions = {
|
|
3
|
-
priority?: 'normal' | 'high';
|
|
3
|
+
priority?: 'normal' | 'high' | 'critical';
|
|
4
4
|
};
|
|
5
5
|
export declare const configureIngestQueueDrain: (options: {
|
|
6
6
|
shouldDefer?: (() => boolean) | null;
|