@reproapp/node-sdk 0.0.49 → 0.0.51
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 +44 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +83 -31
- package/dist/ingest/client.d.ts +2 -2
- package/dist/ingest/client.js +33 -7
- package/dist/live-capture-limits.d.ts +19 -0
- package/dist/live-capture-limits.js +207 -0
- package/dist/semantic-serialization.d.ts +1 -0
- package/dist/semantic-serialization.js +33 -1
- package/package.json +7 -2
- package/src/index.ts +103 -31
- package/src/ingest/client.ts +36 -10
- package/src/live-capture-limits.ts +177 -0
- package/src/semantic-serialization.ts +30 -0
- package/test/background-continuous-traffic.testcontainers.test.js +100 -0
- package/test/fixtures/live-capture-limits-server.js +21 -0
- package/test/ingest-throttle-retention.test.js +41 -0
- package/test/live-broker-limits.testcontainers.test.js +86 -0
- package/test/live-capture-limits.test.js +99 -0
- package/test/live-capture-limits.testcontainers.test.js +78 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.limitLiveArguments = exports.collectCaptureOmissions = exports.limitLiveCapture = exports.LIVE_CAPTURE_LIMITS = void 0;
|
|
4
|
+
const http_1 = require("http");
|
|
5
|
+
const semantic_serialization_1 = require("./semantic-serialization");
|
|
6
|
+
exports.LIVE_CAPTURE_LIMITS = Object.freeze({ maxDepth: 10, maxKeys: 100, maxEntries: 100 });
|
|
7
|
+
const marker = (omission) => ({ __kind: 'repro-omitted', complete: false, ...omission });
|
|
8
|
+
const childPath = (path, key) => `${path}[${JSON.stringify(key)}]`;
|
|
9
|
+
function parseStructuredString(value) {
|
|
10
|
+
if (typeof value !== 'string' || !/^[\s]*[\[{]/.test(value))
|
|
11
|
+
return undefined;
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(value);
|
|
14
|
+
return parsed && typeof parsed === 'object' ? parsed : undefined;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Snapshot only data descriptors: capture must never execute application getters. */
|
|
21
|
+
function limitLiveCapture(value, rootPath = '$') {
|
|
22
|
+
const omissions = [];
|
|
23
|
+
const seen = new WeakMap();
|
|
24
|
+
const omit = (detail) => { omissions.push(detail); return marker(detail); };
|
|
25
|
+
const walk = (input, depth, path) => {
|
|
26
|
+
if (input === null || input === undefined)
|
|
27
|
+
return input;
|
|
28
|
+
if (typeof input === 'string') {
|
|
29
|
+
const parsed = parseStructuredString(input);
|
|
30
|
+
if (parsed === undefined)
|
|
31
|
+
return input;
|
|
32
|
+
const before = omissions.length;
|
|
33
|
+
const bounded = walk(parsed, depth, path);
|
|
34
|
+
// Preserve the original string exactly unless its structured data exceeded a limit.
|
|
35
|
+
return omissions.length === before ? input : JSON.stringify(bounded);
|
|
36
|
+
}
|
|
37
|
+
if (typeof input === 'bigint' || typeof input === 'symbol')
|
|
38
|
+
return String(input);
|
|
39
|
+
if (typeof input === 'function')
|
|
40
|
+
return '[Function]';
|
|
41
|
+
if (typeof input !== 'object')
|
|
42
|
+
return input;
|
|
43
|
+
const previous = seen.get(input);
|
|
44
|
+
if (previous && previous.depth <= depth)
|
|
45
|
+
return { __reproCircularRef: previous.path };
|
|
46
|
+
seen.set(input, { path, depth });
|
|
47
|
+
const descriptor = (key) => Object.getOwnPropertyDescriptor(input, key);
|
|
48
|
+
const data = (key) => descriptor(key)?.value;
|
|
49
|
+
if (data('__kind') === 'repro-omitted') {
|
|
50
|
+
const detail = { reason: data('reason'), path: data('path'), limit: data('limit'), originalCount: data('originalCount'), capturedCount: data('capturedCount') };
|
|
51
|
+
omissions.push(detail);
|
|
52
|
+
return marker(detail);
|
|
53
|
+
}
|
|
54
|
+
if (input instanceof Date)
|
|
55
|
+
return Number.isNaN(Date.prototype.getTime.call(input)) ? 'Invalid Date' : Date.prototype.toISOString.call(input);
|
|
56
|
+
if (input instanceof RegExp)
|
|
57
|
+
return RegExp.prototype.toString.call(input);
|
|
58
|
+
if (input instanceof http_1.IncomingMessage) {
|
|
59
|
+
// The business body is its own root, not depth one in a socket graph.
|
|
60
|
+
return { __kind: 'http-request', method: data('method'), url: data('originalUrl') ?? data('url'),
|
|
61
|
+
headers: walk(data('headers') ?? Object.getOwnPropertyDescriptor(http_1.IncomingMessage.prototype, 'headers')?.get?.call(input), 0, childPath(path, 'headers')),
|
|
62
|
+
query: walk(data('query'), 0, childPath(path, 'query')),
|
|
63
|
+
body: walk(data('body'), 0, childPath(path, 'body')),
|
|
64
|
+
params: walk(data('params'), 0, childPath(path, 'params')) };
|
|
65
|
+
}
|
|
66
|
+
if (input instanceof http_1.ServerResponse)
|
|
67
|
+
return { __kind: 'http-response', statusCode: data('statusCode') };
|
|
68
|
+
const projected = (0, semantic_serialization_1.projectSemanticInfrastructureValue)(input);
|
|
69
|
+
if (projected)
|
|
70
|
+
return projected.value;
|
|
71
|
+
// Mongoose stores business fields in _doc; never recurse through $__ state.
|
|
72
|
+
const documentData = (0, semantic_serialization_1.mongooseDocumentData)(input);
|
|
73
|
+
if (documentData)
|
|
74
|
+
return walk(documentData, depth, path);
|
|
75
|
+
if (depth > exports.LIVE_CAPTURE_LIMITS.maxDepth)
|
|
76
|
+
return omit({ reason: 'max-depth', path, limit: exports.LIVE_CAPTURE_LIMITS.maxDepth, capturedCount: 0 });
|
|
77
|
+
if (input instanceof Error) {
|
|
78
|
+
const details = Object.create(null);
|
|
79
|
+
for (const key of ['message', 'stack', 'cause', 'errors', ...Object.keys(input)]) {
|
|
80
|
+
const item = descriptor(key);
|
|
81
|
+
if (item)
|
|
82
|
+
Object.defineProperty(details, key, { ...item, enumerable: true, configurable: true });
|
|
83
|
+
}
|
|
84
|
+
return walk(details, depth, path);
|
|
85
|
+
}
|
|
86
|
+
if (input instanceof ArrayBuffer || (typeof SharedArrayBuffer !== 'undefined' && input instanceof SharedArrayBuffer) || input instanceof DataView) {
|
|
87
|
+
let bytes;
|
|
88
|
+
if (input instanceof DataView) {
|
|
89
|
+
const read = (key) => Object.getOwnPropertyDescriptor(DataView.prototype, key).get.call(input);
|
|
90
|
+
bytes = new Uint8Array(read('buffer'), read('byteOffset'), read('byteLength'));
|
|
91
|
+
}
|
|
92
|
+
else
|
|
93
|
+
bytes = new Uint8Array(input);
|
|
94
|
+
return { __type: input instanceof DataView ? 'DataView' : 'ArrayBuffer', values: walk(bytes, depth, path).values };
|
|
95
|
+
}
|
|
96
|
+
if (input instanceof Map) {
|
|
97
|
+
const entries = [];
|
|
98
|
+
const size = Object.getOwnPropertyDescriptor(Map.prototype, 'size').get.call(input);
|
|
99
|
+
for (const [key, item] of Map.prototype.entries.call(input)) {
|
|
100
|
+
if (entries.length >= exports.LIVE_CAPTURE_LIMITS.maxEntries)
|
|
101
|
+
break;
|
|
102
|
+
const index = entries.length;
|
|
103
|
+
entries.push([walk(key, depth + 1, childPath(path, `key:${index}`)), walk(item, depth + 1, childPath(path, index))]);
|
|
104
|
+
}
|
|
105
|
+
if (size > entries.length)
|
|
106
|
+
entries.push(omit({ reason: 'max-entries', path, limit: 100, originalCount: size, capturedCount: entries.length }));
|
|
107
|
+
return { __type: 'Map', entries };
|
|
108
|
+
}
|
|
109
|
+
if (input instanceof Set) {
|
|
110
|
+
const values = [];
|
|
111
|
+
const size = Object.getOwnPropertyDescriptor(Set.prototype, 'size').get.call(input);
|
|
112
|
+
for (const item of Set.prototype.values.call(input)) {
|
|
113
|
+
if (values.length >= 100)
|
|
114
|
+
break;
|
|
115
|
+
values.push(walk(item, depth + 1, childPath(path, values.length)));
|
|
116
|
+
}
|
|
117
|
+
if (size > values.length)
|
|
118
|
+
values.push(omit({ reason: 'max-entries', path, limit: 100, originalCount: size, capturedCount: values.length }));
|
|
119
|
+
return { __type: 'Set', values };
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(input) || (ArrayBuffer.isView(input) && !(input instanceof DataView))) {
|
|
122
|
+
const length = input.length;
|
|
123
|
+
const previousMarker = Array.isArray(input) && length === 101 ? descriptor('100')?.value : null;
|
|
124
|
+
const prior = previousMarker && Object.getOwnPropertyDescriptors(previousMarker);
|
|
125
|
+
const hasPriorLimit = prior?.__kind?.value === 'repro-omitted' && prior?.reason?.value === 'max-entries';
|
|
126
|
+
const values = [];
|
|
127
|
+
for (let i = 0; i < Math.min(length, 100); i++) {
|
|
128
|
+
const itemDescriptor = descriptor(String(i));
|
|
129
|
+
values.push(itemDescriptor && !('value' in itemDescriptor)
|
|
130
|
+
? omit({ reason: 'accessor', path: childPath(path, i), capturedCount: 0 })
|
|
131
|
+
: walk(itemDescriptor?.value, depth + 1, childPath(path, i)));
|
|
132
|
+
}
|
|
133
|
+
if (length > 100)
|
|
134
|
+
values.push(hasPriorLimit
|
|
135
|
+
? walk(previousMarker, depth + 1, path)
|
|
136
|
+
: omit({ reason: 'max-entries', path, limit: 100, originalCount: length, capturedCount: 100 }));
|
|
137
|
+
return Array.isArray(input) ? values : { __type: 'TypedArray', values };
|
|
138
|
+
}
|
|
139
|
+
const keys = Object.keys(input);
|
|
140
|
+
const previousMetadataKey = keys.find(key => {
|
|
141
|
+
if (!/^__reproCapture\$*$/.test(key))
|
|
142
|
+
return false;
|
|
143
|
+
const candidate = descriptor(key)?.value;
|
|
144
|
+
return candidate && Object.getOwnPropertyDescriptor(candidate, '__kind')?.value === 'repro-omitted'
|
|
145
|
+
&& Object.getOwnPropertyDescriptor(candidate, 'reason')?.value === 'max-keys';
|
|
146
|
+
});
|
|
147
|
+
const businessKeys = keys.filter(key => key !== previousMetadataKey);
|
|
148
|
+
const out = Object.create(null);
|
|
149
|
+
for (const key of businessKeys.slice(0, 100)) {
|
|
150
|
+
const itemDescriptor = descriptor(key);
|
|
151
|
+
out[key] = 'value' in itemDescriptor
|
|
152
|
+
? walk(itemDescriptor.value, depth + 1, childPath(path, key))
|
|
153
|
+
: omit({ reason: 'accessor', path: childPath(path, key), capturedCount: 0 });
|
|
154
|
+
}
|
|
155
|
+
if (businessKeys.length > 100 || previousMetadataKey) {
|
|
156
|
+
const detail = previousMetadataKey
|
|
157
|
+
? walk(descriptor(previousMetadataKey)?.value, depth + 1, path)
|
|
158
|
+
: omit({ reason: 'max-keys', path, limit: 100, originalCount: businessKeys.length, capturedCount: 100 });
|
|
159
|
+
let metadataKey = '__reproCapture';
|
|
160
|
+
while (Object.prototype.hasOwnProperty.call(out, metadataKey))
|
|
161
|
+
metadataKey += '$';
|
|
162
|
+
out[metadataKey] = detail;
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
return { value: walk(value, 0, rootPath), omissions };
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return { value: omit({ reason: 'uninspectable', path: rootPath, capturedCount: 0 }), omissions };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.limitLiveCapture = limitLiveCapture;
|
|
174
|
+
function collectCaptureOmissions(value) {
|
|
175
|
+
const result = [];
|
|
176
|
+
const seen = new WeakSet();
|
|
177
|
+
const pending = [value];
|
|
178
|
+
while (pending.length) {
|
|
179
|
+
const item = pending.pop();
|
|
180
|
+
const node = typeof item === 'string' ? parseStructuredString(item) : item;
|
|
181
|
+
if (!node || typeof node !== 'object' || seen.has(node))
|
|
182
|
+
continue;
|
|
183
|
+
seen.add(node);
|
|
184
|
+
const descriptors = Object.getOwnPropertyDescriptors(node);
|
|
185
|
+
if (descriptors.__kind?.value === 'repro-omitted') {
|
|
186
|
+
result.push({ reason: descriptors.reason?.value, path: descriptors.path?.value, limit: descriptors.limit?.value,
|
|
187
|
+
originalCount: descriptors.originalCount?.value, capturedCount: descriptors.capturedCount?.value });
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
for (const item of Object.values(descriptors))
|
|
191
|
+
if ('value' in item)
|
|
192
|
+
pending.push(item.value);
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
exports.collectCaptureOmissions = collectCaptureOmissions;
|
|
197
|
+
function limitLiveArguments(args) {
|
|
198
|
+
const values = args.slice(0, 100).map((arg, index) => limitLiveCapture(arg, `$[${index}]`).value);
|
|
199
|
+
if (args.length > 100) {
|
|
200
|
+
const prior = Object.getOwnPropertyDescriptor(args, '100')?.value;
|
|
201
|
+
values.push(args.length === 101 && prior && Object.getOwnPropertyDescriptor(prior, '__kind')?.value === 'repro-omitted'
|
|
202
|
+
? limitLiveCapture(prior).value
|
|
203
|
+
: marker({ reason: 'max-entries', path: '$', limit: 100, originalCount: args.length, capturedCount: 100 }));
|
|
204
|
+
}
|
|
205
|
+
return values;
|
|
206
|
+
}
|
|
207
|
+
exports.limitLiveArguments = limitLiveArguments;
|
|
@@ -2,6 +2,7 @@ export type SemanticProjection = {
|
|
|
2
2
|
matched: true;
|
|
3
3
|
value: Record<string, unknown>;
|
|
4
4
|
};
|
|
5
|
+
export declare function mongooseDocumentData(value: object): object | null;
|
|
5
6
|
/**
|
|
6
7
|
* Projects known runtime machinery into stable, non-recursive descriptions.
|
|
7
8
|
* Unknown application values deliberately return null and remain fully captured.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.projectSemanticInfrastructureValue = void 0;
|
|
3
|
+
exports.projectSemanticInfrastructureValue = exports.mongooseDocumentData = void 0;
|
|
4
4
|
function constructorName(value) {
|
|
5
5
|
if (!value || typeof value !== 'object')
|
|
6
6
|
return '';
|
|
@@ -49,6 +49,13 @@ function method(value, key) {
|
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
function mongooseDocumentData(value) {
|
|
53
|
+
const doc = Object.getOwnPropertyDescriptor(value, '_doc')?.value;
|
|
54
|
+
if (!doc || typeof doc !== 'object' || !Object.getOwnPropertyDescriptor(value, '$__')?.value)
|
|
55
|
+
return null;
|
|
56
|
+
return method(value, '$__init') && method(value, '$toObject') ? doc : null;
|
|
57
|
+
}
|
|
58
|
+
exports.mongooseDocumentData = mongooseDocumentData;
|
|
52
59
|
function primitiveStateValue(value) {
|
|
53
60
|
if (value === null)
|
|
54
61
|
return null;
|
|
@@ -82,6 +89,8 @@ function projectConfigurationService(value, className) {
|
|
|
82
89
|
function projectLogger(value, className) {
|
|
83
90
|
if (!/(Logger|LoggerService)$/i.test(className))
|
|
84
91
|
return null;
|
|
92
|
+
if (!method(value, 'log') && !method(value, 'info'))
|
|
93
|
+
return null;
|
|
85
94
|
const descriptors = ownDataDescriptors(value);
|
|
86
95
|
const context = primitiveStateValue(descriptors.context?.value);
|
|
87
96
|
return semanticValue('logger', className, context !== undefined ? { context } : {});
|
|
@@ -90,6 +99,15 @@ function projectNestInfrastructure(value, className) {
|
|
|
90
99
|
if (!/(ModuleRef|ModulesContainer|InstanceWrapper|NestContainer|Injector|DiscoveryService|ExecutionContextHost|ArgumentsHost|HttpAdapterHost)$/i.test(className)) {
|
|
91
100
|
return null;
|
|
92
101
|
}
|
|
102
|
+
const signatures = {
|
|
103
|
+
ModuleRef: ['get', 'resolve'], ModulesContainer: ['get', 'set'],
|
|
104
|
+
InstanceWrapper: ['getInstanceByContextId'], NestContainer: ['getModules'],
|
|
105
|
+
Injector: ['loadInstance'], DiscoveryService: ['getProviders'],
|
|
106
|
+
ExecutionContextHost: ['switchToHttp', 'getArgs'], ArgumentsHost: ['switchToHttp', 'getArgs'],
|
|
107
|
+
HttpAdapterHost: ['listen$'],
|
|
108
|
+
};
|
|
109
|
+
if (!(signatures[className] ?? []).some(key => method(value, key)))
|
|
110
|
+
return null;
|
|
93
111
|
return semanticValue('nestjs-infrastructure', className);
|
|
94
112
|
}
|
|
95
113
|
function projectRedis(value, className) {
|
|
@@ -149,6 +167,19 @@ function projectTypeOrm(value, className) {
|
|
|
149
167
|
}
|
|
150
168
|
return null;
|
|
151
169
|
}
|
|
170
|
+
function projectMongoInfrastructure(value, className) {
|
|
171
|
+
const signatures = {
|
|
172
|
+
MongoClient: ['connect', 'db', 'close'],
|
|
173
|
+
ClientSession: ['startTransaction', 'endSession'],
|
|
174
|
+
ConnectionPool: ['checkOut', 'checkIn'],
|
|
175
|
+
NativeConnection: ['openUri', 'model', 'close'],
|
|
176
|
+
Schema: ['add', 'path', 'plugin'],
|
|
177
|
+
};
|
|
178
|
+
const required = signatures[className];
|
|
179
|
+
return required?.every(key => method(value, key))
|
|
180
|
+
? semanticValue('mongodb-infrastructure', className)
|
|
181
|
+
: null;
|
|
182
|
+
}
|
|
152
183
|
/**
|
|
153
184
|
* Projects known runtime machinery into stable, non-recursive descriptions.
|
|
154
185
|
* Unknown application values deliberately return null and remain fully captured.
|
|
@@ -165,6 +196,7 @@ function projectSemanticInfrastructureValue(value) {
|
|
|
165
196
|
projectRedis(value, className) ||
|
|
166
197
|
projectKafka(value, className) ||
|
|
167
198
|
projectAmqp(value, className) ||
|
|
199
|
+
projectMongoInfrastructure(value, className) ||
|
|
168
200
|
projectPostgres(value, className) ||
|
|
169
201
|
projectTypeOrm(value, className));
|
|
170
202
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reproapp/node-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.51",
|
|
4
4
|
"description": "Repro Nest SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
"node": ">=18"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
+
"test:live-capture": "npm run build && node test/live-capture-limits.test.js && node test/ingest-throttle-retention.test.js && node test/live-capture-limits.testcontainers.test.js",
|
|
13
|
+
"test:live-brokers": "npm run build && node test/live-broker-limits.testcontainers.test.js",
|
|
12
14
|
"build": "tsc -p tsconfig.json",
|
|
13
15
|
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
|
14
16
|
"prepublishOnly": "npm run build",
|
|
15
17
|
"test": "npm run build && node test/semantic-serialization.test.js && node test/semantic-serialization-trace.test.js && node test/content-addressed-trace-values.test.js && node test/trace-observation-snapshots.test.js && node test/session-storage-budget.test.js && node test/trace-source-exclude.test.js && node test/unawaited.test.js && node test/integration-unawaited.js && node test/request-flush-timing.test.js && node test/request-capture-background.test.js && node test/init-auto-http-server.test.js && node test/backend-live-mode.test.js && node test/client-performance-regression.test.js && node test/request-manifest-priority.test.js && node test/runtime-no-double-invoke.test.js && node test/express-trace-http-args.test.js && node test/trace-batch-size.test.js && node test/sdk-background-priority.test.js && node test/sdk-background-timeout-isolation.test.js && node test/runtime-service-registration.test.js && node test/ingest-queue-retention.test.js && node test/ingest-high-priority-retention.test.js && node test/ingest-high-priority-fairness.test.js && node test/ingest-critical-retention.test.js && node test/ingest-critical-retry-retention.test.js && node test/ingest-batching.test.js && node test/ingest-timeout.test.js && node -r ./tracer/register test/promise-map.test.js && node test/disable-subtree.test.js && node test/circular-capture.test.js && node test/wrap-plugin-arrow-args.test.js && node test/wrap-plugin-super-call.test.js && node test/function-arg-identity.test.js && node test/privacy-service-scope.test.js && node test/privacy-policy-index.test.js && node test/policy-capture-attestation.test.js && node test/privacy-runtime-policy.test.js && node test/runtime-privacy-materialization.test.js && node test/kafka-runtime-privacy-policy.test.js && node test/amqplib-integration.test.js && node test/mongodb-integration.test.js && node test/mongodb-esm-import-hook.test.js && node test/mongodb-suppression-cleanup.test.js && node test/postgresql-integration.test.js",
|
|
16
|
-
"test:containers": "npm run build && node test/runtime-no-double-invoke.testcontainers.test.js && node test/wrap-plugin-super-call.testcontainers.test.js && node test/function-arg-identity.testcontainers.test.js && node test/mongodb-mongoose-native-suppression.testcontainers.test.js && node test/content-addressed-mongodb.testcontainers.test.js && node test/policy-session-completion.testcontainers.test.js && node test/postgresql-integrations.testcontainers.test.js"
|
|
18
|
+
"test:containers": "npm run build && node test/background-continuous-traffic.testcontainers.test.js && node test/runtime-no-double-invoke.testcontainers.test.js && node test/wrap-plugin-super-call.testcontainers.test.js && node test/function-arg-identity.testcontainers.test.js && node test/mongodb-mongoose-native-suppression.testcontainers.test.js && node test/content-addressed-mongodb.testcontainers.test.js && node test/policy-session-completion.testcontainers.test.js && node test/postgresql-integrations.testcontainers.test.js"
|
|
17
19
|
},
|
|
18
20
|
"peerDependencies": {
|
|
19
21
|
"express": "^5.1.0",
|
|
@@ -21,8 +23,11 @@
|
|
|
21
23
|
},
|
|
22
24
|
"devDependencies": {
|
|
23
25
|
"@nestjs/typeorm": "^11.0.0",
|
|
26
|
+
"@testcontainers/kafka": "^11.8.1",
|
|
24
27
|
"@types/express": "^5.0.3",
|
|
25
28
|
"@types/pg": "^8.20.0",
|
|
29
|
+
"amqplib": "^0.10.9",
|
|
30
|
+
"kafkajs": "^2.2.4",
|
|
26
31
|
"mongodb": "^6.21.0",
|
|
27
32
|
"pg": "^8.22.0",
|
|
28
33
|
"postgres": "^3.4.9",
|