@softprobe/softprobe-js 2.0.4 → 2.0.5
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 +6 -1
- package/dist/cli/diff.d.ts.map +1 -1
- package/dist/cli/diff.js +6 -1
- package/dist/cli/diff.js.map +1 -1
- package/dist/core/runtime/architecture-guard.js +13 -13
- package/dist/core/runtime/architecture-guard.js.map +1 -1
- package/dist/core/runtime/http-body.d.ts +5 -0
- package/dist/core/runtime/http-body.d.ts.map +1 -0
- package/dist/core/runtime/http-body.js +20 -0
- package/dist/core/runtime/http-body.js.map +1 -0
- package/dist/instrumentations/common/http/inbound-capture.d.ts +4 -0
- package/dist/instrumentations/common/http/inbound-capture.d.ts.map +1 -1
- package/dist/instrumentations/common/http/inbound-capture.js +5 -2
- package/dist/instrumentations/common/http/inbound-capture.js.map +1 -1
- package/dist/instrumentations/common/http/inbound-record.d.ts +4 -0
- package/dist/instrumentations/common/http/inbound-record.d.ts.map +1 -1
- package/dist/instrumentations/common/http/inbound-record.js +8 -4
- package/dist/instrumentations/common/http/inbound-record.js.map +1 -1
- package/dist/instrumentations/express/capture.d.ts.map +1 -1
- package/dist/instrumentations/express/capture.js +2 -0
- package/dist/instrumentations/express/capture.js.map +1 -1
- package/package.json +3 -2
- package/dist/bindings/http-span.d.ts +0 -6
- package/dist/bindings/http-span.d.ts.map +0 -1
- package/dist/bindings/http-span.js +0 -11
- package/dist/bindings/http-span.js.map +0 -1
- package/dist/bindings/postgres-span.d.ts +0 -6
- package/dist/bindings/postgres-span.d.ts.map +0 -1
- package/dist/bindings/postgres-span.js +0 -11
- package/dist/bindings/postgres-span.js.map +0 -1
- package/dist/bindings/redis-span.d.ts +0 -6
- package/dist/bindings/redis-span.d.ts.map +0 -1
- package/dist/bindings/redis-span.js +0 -11
- package/dist/bindings/redis-span.js.map +0 -1
- package/dist/bindings/test-span.d.ts +0 -6
- package/dist/bindings/test-span.d.ts.map +0 -1
- package/dist/bindings/test-span.js +0 -9
- package/dist/bindings/test-span.js.map +0 -1
- package/dist/capture/express.d.ts +0 -6
- package/dist/capture/express.d.ts.map +0 -1
- package/dist/capture/express.js +0 -11
- package/dist/capture/express.js.map +0 -1
- package/dist/capture/fastify.d.ts +0 -5
- package/dist/capture/fastify.d.ts.map +0 -1
- package/dist/capture/fastify.js +0 -9
- package/dist/capture/fastify.js.map +0 -1
- package/dist/capture/framework-mutator.d.ts +0 -20
- package/dist/capture/framework-mutator.d.ts.map +0 -1
- package/dist/capture/framework-mutator.js +0 -144
- package/dist/capture/framework-mutator.js.map +0 -1
- package/dist/capture/http-inbound.d.ts +0 -28
- package/dist/capture/http-inbound.d.ts.map +0 -1
- package/dist/capture/http-inbound.js +0 -40
- package/dist/capture/http-inbound.js.map +0 -1
- package/dist/capture/inject.d.ts +0 -17
- package/dist/capture/inject.d.ts.map +0 -1
- package/dist/capture/inject.js +0 -28
- package/dist/capture/inject.js.map +0 -1
- package/dist/capture/mutator.d.ts +0 -17
- package/dist/capture/mutator.d.ts.map +0 -1
- package/dist/capture/mutator.js +0 -51
- package/dist/capture/mutator.js.map +0 -1
- package/dist/capture/postgres.d.ts +0 -6
- package/dist/capture/postgres.d.ts.map +0 -1
- package/dist/capture/postgres.js +0 -11
- package/dist/capture/postgres.js.map +0 -1
- package/dist/capture/redis.d.ts +0 -5
- package/dist/capture/redis.d.ts.map +0 -1
- package/dist/capture/redis.js +0 -10
- package/dist/capture/redis.js.map +0 -1
- package/dist/capture/store-accessor.d.ts +0 -11
- package/dist/capture/store-accessor.d.ts.map +0 -1
- package/dist/capture/store-accessor.js +0 -19
- package/dist/capture/store-accessor.js.map +0 -1
- package/dist/capture/stream-tap.d.ts +0 -5
- package/dist/capture/stream-tap.d.ts.map +0 -1
- package/dist/capture/stream-tap.js +0 -9
- package/dist/capture/stream-tap.js.map +0 -1
- package/dist/identifier.d.ts +0 -5
- package/dist/identifier.d.ts.map +0 -1
- package/dist/identifier.js +0 -11
- package/dist/identifier.js.map +0 -1
- package/dist/replay/express.d.ts +0 -5
- package/dist/replay/express.d.ts.map +0 -1
- package/dist/replay/express.js +0 -9
- package/dist/replay/express.js.map +0 -1
- package/dist/replay/extract-key.d.ts +0 -41
- package/dist/replay/extract-key.d.ts.map +0 -1
- package/dist/replay/extract-key.js +0 -80
- package/dist/replay/extract-key.js.map +0 -1
- package/dist/replay/fastify.d.ts +0 -5
- package/dist/replay/fastify.d.ts.map +0 -1
- package/dist/replay/fastify.js +0 -9
- package/dist/replay/fastify.js.map +0 -1
- package/dist/replay/http.d.ts +0 -5
- package/dist/replay/http.d.ts.map +0 -1
- package/dist/replay/http.js +0 -10
- package/dist/replay/http.js.map +0 -1
- package/dist/replay/matcher.d.ts +0 -25
- package/dist/replay/matcher.d.ts.map +0 -1
- package/dist/replay/matcher.js +0 -83
- package/dist/replay/matcher.js.map +0 -1
- package/dist/replay/postgres.d.ts +0 -5
- package/dist/replay/postgres.d.ts.map +0 -1
- package/dist/replay/postgres.js +0 -10
- package/dist/replay/postgres.js.map +0 -1
- package/dist/replay/redis.d.ts +0 -5
- package/dist/replay/redis.d.ts.map +0 -1
- package/dist/replay/redis.js +0 -10
- package/dist/replay/redis.js.map +0 -1
- package/dist/replay/softprobe-matcher.d.ts +0 -41
- package/dist/replay/softprobe-matcher.d.ts.map +0 -1
- package/dist/replay/softprobe-matcher.js +0 -92
- package/dist/replay/softprobe-matcher.js.map +0 -1
- package/dist/replay/store-accessor.d.ts +0 -14
- package/dist/replay/store-accessor.d.ts.map +0 -1
- package/dist/replay/store-accessor.js +0 -26
- package/dist/replay/store-accessor.js.map +0 -1
- package/dist/replay/topology.d.ts +0 -37
- package/dist/replay/topology.d.ts.map +0 -1
- package/dist/replay/topology.js +0 -72
- package/dist/replay/topology.js.map +0 -1
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Key extraction and candidate filtering for default matcher (design §7.3).
|
|
4
|
-
* Derives { protocol, identifier } from a span; filters outbound records by key.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.CallSeq = void 0;
|
|
8
|
-
exports.extractKeyFromSpan = extractKeyFromSpan;
|
|
9
|
-
exports.filterOutboundCandidates = filterOutboundCandidates;
|
|
10
|
-
exports.createDefaultMatcher = createDefaultMatcher;
|
|
11
|
-
const postgres_span_1 = require("../core/bindings/postgres-span");
|
|
12
|
-
const redis_span_1 = require("../core/bindings/redis-span");
|
|
13
|
-
const http_span_1 = require("../core/bindings/http-span");
|
|
14
|
-
/**
|
|
15
|
-
* Extracts matching key from a span using PostgresSpan, RedisSpan, and HttpSpan.
|
|
16
|
-
* Returns the first non-null fromSpan result as { protocol, identifier }; unknown span yields null.
|
|
17
|
-
*/
|
|
18
|
-
function extractKeyFromSpan(span) {
|
|
19
|
-
const pg = postgres_span_1.PostgresSpan.fromSpan(span);
|
|
20
|
-
if (pg)
|
|
21
|
-
return { protocol: 'postgres', identifier: pg.identifier };
|
|
22
|
-
const redis = redis_span_1.RedisSpan.fromSpan(span);
|
|
23
|
-
if (redis)
|
|
24
|
-
return { protocol: 'redis', identifier: redis.identifier };
|
|
25
|
-
const http = http_span_1.HttpSpan.fromSpan(span);
|
|
26
|
-
if (http)
|
|
27
|
-
return { protocol: 'http', identifier: http.identifier };
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Returns only outbound records whose protocol and identifier match the key.
|
|
32
|
-
*/
|
|
33
|
-
function filterOutboundCandidates(records, key) {
|
|
34
|
-
return records.filter((r) => r.type === 'outbound' &&
|
|
35
|
-
r.protocol === key.protocol &&
|
|
36
|
-
r.identifier === key.identifier);
|
|
37
|
-
}
|
|
38
|
-
function seqKey(key) {
|
|
39
|
-
return `${key.protocol}::${key.identifier}`;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Per-key call sequence for default matcher: tracks the next candidate index
|
|
43
|
-
* per (protocol, identifier). getAndIncrement returns the current index and advances.
|
|
44
|
-
*/
|
|
45
|
-
class CallSeq {
|
|
46
|
-
constructor() {
|
|
47
|
-
this.next = new Map();
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Returns the current index for this key and increments for the next call.
|
|
51
|
-
*/
|
|
52
|
-
getAndIncrement(key) {
|
|
53
|
-
const k = seqKey(key);
|
|
54
|
-
const idx = this.next.get(k) ?? 0;
|
|
55
|
-
this.next.set(k, idx + 1);
|
|
56
|
-
return idx;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.CallSeq = CallSeq;
|
|
60
|
-
/**
|
|
61
|
-
* Returns a MatcherFn that uses extractKeyFromSpan, filterOutboundCandidates,
|
|
62
|
-
* and CallSeq to pick an outbound record and return MOCK with its responsePayload.
|
|
63
|
-
*/
|
|
64
|
-
function createDefaultMatcher() {
|
|
65
|
-
const callSeq = new CallSeq();
|
|
66
|
-
return (span, records) => {
|
|
67
|
-
const key = extractKeyFromSpan(span);
|
|
68
|
-
if (!key)
|
|
69
|
-
return { action: 'CONTINUE' };
|
|
70
|
-
const candidates = filterOutboundCandidates(records, key);
|
|
71
|
-
if (candidates.length === 0)
|
|
72
|
-
return { action: 'CONTINUE' };
|
|
73
|
-
const idx = callSeq.getAndIncrement(key);
|
|
74
|
-
if (idx >= candidates.length)
|
|
75
|
-
return { action: 'CONTINUE' };
|
|
76
|
-
const record = candidates[idx];
|
|
77
|
-
return { action: 'MOCK', payload: record?.responsePayload, traceId: record?.traceId };
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=extract-key.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extract-key.js","sourceRoot":"","sources":["../../src/replay/extract-key.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAwBH,gDAWC;AAKD,4DAUC;AA4BD,oDAYC;AAnFD,kEAA8D;AAC9D,4DAAwD;AACxD,0DAAsD;AAWtD;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,IAAkB;IACnD,MAAM,EAAE,GAAG,4BAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,EAAE;QAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC;IAEnE,MAAM,KAAK,GAAG,sBAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;IAEtE,MAAM,IAAI,GAAG,oBAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,IAAI;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IAEnE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,wBAAwB,CACtC,OAAkC,EAClC,GAAY;IAEZ,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,UAAU;QACrB,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ;QAC3B,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,UAAU,CAClC,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,UAAU,EAAE,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAa,OAAO;IAApB;QACU,SAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAW3C,CAAC;IATC;;OAEG;IACH,eAAe,CAAC,GAAY;QAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QAC1B,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAZD,0BAYC;AAED;;;GAGG;AACH,SAAgB,oBAAoB;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,OAAO,EAAiB,EAAE;QACtC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAoB,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC5D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACxF,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/replay/fastify.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/replay/fastify.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,gCAAgC,EAAE,MAAM,oCAAoC,CAAC"}
|
package/dist/replay/fastify.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.softprobeFastifyReplayPreHandler = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Legacy compatibility re-export for Fastify replay instrumentation.
|
|
6
|
-
*/
|
|
7
|
-
var replay_1 = require("../instrumentations/fastify/replay");
|
|
8
|
-
Object.defineProperty(exports, "softprobeFastifyReplayPreHandler", { enumerable: true, get: function () { return replay_1.softprobeFastifyReplayPreHandler; } });
|
|
9
|
-
//# sourceMappingURL=fastify.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/replay/fastify.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,6DAAsF;AAA7E,0HAAA,gCAAgC,OAAA"}
|
package/dist/replay/http.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/replay/http.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
|
package/dist/replay/http.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupHttpReplayInterceptor = exports.handleHttpReplayRequest = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Legacy compatibility re-export for HTTP/fetch replay instrumentation.
|
|
6
|
-
*/
|
|
7
|
-
var replay_1 = require("../instrumentations/fetch/replay");
|
|
8
|
-
Object.defineProperty(exports, "handleHttpReplayRequest", { enumerable: true, get: function () { return replay_1.handleHttpReplayRequest; } });
|
|
9
|
-
Object.defineProperty(exports, "setupHttpReplayInterceptor", { enumerable: true, get: function () { return replay_1.setupHttpReplayInterceptor; } });
|
|
10
|
-
//# sourceMappingURL=http.js.map
|
package/dist/replay/http.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/replay/http.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,2DAAuG;AAA9F,iHAAA,uBAAuB,OAAA;AAAE,oHAAA,0BAA0B,OAAA"}
|
package/dist/replay/matcher.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
2
|
-
import type { MatchRequest, CustomMatcherFn } from '../types/schema';
|
|
3
|
-
export declare class SemanticMatcher {
|
|
4
|
-
private readonly recordedSpans;
|
|
5
|
-
/** Tracks call count per (protocol, identifier, liveParentName) for sequential N+1 resolution. */
|
|
6
|
-
private readonly callSequenceMap;
|
|
7
|
-
/** User-registered matchers evaluated before the default tree-matching algorithm. */
|
|
8
|
-
private readonly customMatchers;
|
|
9
|
-
constructor(recordedSpans: ReadableSpan[]);
|
|
10
|
-
/**
|
|
11
|
-
* Registers a custom matcher. Custom matchers are run before the default tree-matching logic.
|
|
12
|
-
* - MOCK: return the given payload (no tree matching, no network).
|
|
13
|
-
* - CONTINUE: fall through to tree matching; the call is still replayed from the recording.
|
|
14
|
-
* - PASSTHROUGH: request live network for this call; in strict mode throws (not allowed).
|
|
15
|
-
*/
|
|
16
|
-
addMatcher(fn: CustomMatcherFn): void;
|
|
17
|
-
/**
|
|
18
|
-
* Finds a recorded span that matches the live request by protocol and identifier,
|
|
19
|
-
* and optionally by lineage: the recorded span's parent name matches the current
|
|
20
|
-
* active OpenTelemetry span's name (semantic tree matching).
|
|
21
|
-
* Custom matchers are evaluated first; if any returns MOCK, that payload is returned; if any returns PASSTHROUGH, throws.
|
|
22
|
-
*/
|
|
23
|
-
findMatch(request: MatchRequest): unknown;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=matcher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../../src/replay/matcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAQrE,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiB;IAC/C,kGAAkG;IAClG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAC7D,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,aAAa,EAAE,YAAY,EAAE;IAIzC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI;IAIrC;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;CA0D1C"}
|
package/dist/replay/matcher.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SemanticMatcher = void 0;
|
|
4
|
-
const api_1 = require("@opentelemetry/api");
|
|
5
|
-
const RESPONSE_BODY_KEY = 'softprobe.response.body';
|
|
6
|
-
const PROTOCOL_KEY = 'softprobe.protocol';
|
|
7
|
-
const IDENTIFIER_KEY = 'softprobe.identifier';
|
|
8
|
-
// This is obsolete, we should use the new matcher instead
|
|
9
|
-
// Deprecated: use SoftprobeMatcher instead
|
|
10
|
-
class SemanticMatcher {
|
|
11
|
-
constructor(recordedSpans) {
|
|
12
|
-
/** Tracks call count per (protocol, identifier, liveParentName) for sequential N+1 resolution. */
|
|
13
|
-
this.callSequenceMap = new Map();
|
|
14
|
-
/** User-registered matchers evaluated before the default tree-matching algorithm. */
|
|
15
|
-
this.customMatchers = [];
|
|
16
|
-
this.recordedSpans = recordedSpans;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Registers a custom matcher. Custom matchers are run before the default tree-matching logic.
|
|
20
|
-
* - MOCK: return the given payload (no tree matching, no network).
|
|
21
|
-
* - CONTINUE: fall through to tree matching; the call is still replayed from the recording.
|
|
22
|
-
* - PASSTHROUGH: request live network for this call; in strict mode throws (not allowed).
|
|
23
|
-
*/
|
|
24
|
-
addMatcher(fn) {
|
|
25
|
-
this.customMatchers.push(fn);
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Finds a recorded span that matches the live request by protocol and identifier,
|
|
29
|
-
* and optionally by lineage: the recorded span's parent name matches the current
|
|
30
|
-
* active OpenTelemetry span's name (semantic tree matching).
|
|
31
|
-
* Custom matchers are evaluated first; if any returns MOCK, that payload is returned; if any returns PASSTHROUGH, throws.
|
|
32
|
-
*/
|
|
33
|
-
findMatch(request) {
|
|
34
|
-
for (const matcher of this.customMatchers) {
|
|
35
|
-
const result = matcher(request, this.recordedSpans);
|
|
36
|
-
if (result.action === 'MOCK')
|
|
37
|
-
return result.payload;
|
|
38
|
-
if (result.action === 'PASSTHROUGH') {
|
|
39
|
-
throw new Error('[Softprobe] Network Passthrough not allowed in strict mode');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const candidates = this.recordedSpans.filter((span) => span.attributes[PROTOCOL_KEY] === request.protocol &&
|
|
43
|
-
span.attributes[IDENTIFIER_KEY] === request.identifier);
|
|
44
|
-
if (candidates.length === 0) {
|
|
45
|
-
throw new Error(`[Softprobe] No recorded traces found for ${request.protocol}: ${request.identifier}`);
|
|
46
|
-
}
|
|
47
|
-
const liveSpan = api_1.trace.getActiveSpan();
|
|
48
|
-
const liveParentName = liveSpan && typeof liveSpan.name === 'string'
|
|
49
|
-
? liveSpan.name
|
|
50
|
-
: 'root';
|
|
51
|
-
const lineageMatches = candidates.filter((candidate) => {
|
|
52
|
-
const parentSpanId = candidate.parentSpanId;
|
|
53
|
-
if (parentSpanId == null)
|
|
54
|
-
return liveParentName === 'root';
|
|
55
|
-
const candidateParent = this.recordedSpans.find((s) => s.spanContext().spanId === parentSpanId);
|
|
56
|
-
return candidateParent != null && candidateParent.name === liveParentName;
|
|
57
|
-
});
|
|
58
|
-
let matched;
|
|
59
|
-
if (lineageMatches.length > 0) {
|
|
60
|
-
const sequenceKey = `${request.protocol}-${request.identifier}-${liveParentName}`;
|
|
61
|
-
const currentCount = this.callSequenceMap.get(sequenceKey) ?? 0;
|
|
62
|
-
// Wrap-around: if call count exceeds number of lineage matches, reuse the first match
|
|
63
|
-
matched = lineageMatches[currentCount] ?? lineageMatches[0];
|
|
64
|
-
this.callSequenceMap.set(sequenceKey, currentCount + 1);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
// Flat match: no lineage context, so we do not update callSequenceMap; always return first candidate.
|
|
68
|
-
matched = candidates[0];
|
|
69
|
-
}
|
|
70
|
-
const raw = matched.attributes[RESPONSE_BODY_KEY];
|
|
71
|
-
if (typeof raw !== 'string') {
|
|
72
|
-
throw new Error('[Softprobe] Missing or invalid softprobe.response.body on matched span');
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
return JSON.parse(raw);
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
throw new Error('[Softprobe] Invalid or non-JSON softprobe.response.body on matched span');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
exports.SemanticMatcher = SemanticMatcher;
|
|
83
|
-
//# sourceMappingURL=matcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../src/replay/matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/replay/postgres.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC"}
|
package/dist/replay/postgres.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupPostgresReplay = exports.applyPostgresReplay = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Legacy compatibility re-export for Postgres replay instrumentation.
|
|
6
|
-
*/
|
|
7
|
-
var replay_1 = require("../instrumentations/postgres/replay");
|
|
8
|
-
Object.defineProperty(exports, "applyPostgresReplay", { enumerable: true, get: function () { return replay_1.applyPostgresReplay; } });
|
|
9
|
-
Object.defineProperty(exports, "setupPostgresReplay", { enumerable: true, get: function () { return replay_1.setupPostgresReplay; } });
|
|
10
|
-
//# sourceMappingURL=postgres.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/replay/postgres.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,8DAA+F;AAAtF,6GAAA,mBAAmB,OAAA;AAAE,6GAAA,mBAAmB,OAAA"}
|
package/dist/replay/redis.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/replay/redis.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC"}
|
package/dist/replay/redis.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupRedisReplay = exports.applyRedisReplay = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Legacy compatibility re-export for Redis replay instrumentation.
|
|
6
|
-
*/
|
|
7
|
-
var replay_1 = require("../instrumentations/redis/replay");
|
|
8
|
-
Object.defineProperty(exports, "applyRedisReplay", { enumerable: true, get: function () { return replay_1.applyRedisReplay; } });
|
|
9
|
-
Object.defineProperty(exports, "setupRedisReplay", { enumerable: true, get: function () { return replay_1.setupRedisReplay; } });
|
|
10
|
-
//# sourceMappingURL=redis.js.map
|
package/dist/replay/redis.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/replay/redis.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,2DAAsF;AAA7E,0GAAA,gBAAgB,OAAA;AAAE,0GAAA,gBAAgB,OAAA"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { MatcherAction, MatcherFn, SoftprobeCassetteRecord } from '../types/schema';
|
|
2
|
-
export declare class SoftprobeMatcher {
|
|
3
|
-
/** Matcher functions run in registration order; first non-CONTINUE wins. */
|
|
4
|
-
private fns;
|
|
5
|
-
/** Cassette records for this replay context (one trace). Set by SoftprobeContext.run(REPLAY). */
|
|
6
|
-
private records;
|
|
7
|
-
/** Appends a matcher function. Fns are run in registration order. */
|
|
8
|
-
use(fn: MatcherFn): void;
|
|
9
|
-
/** Removes all registered matcher fns. */
|
|
10
|
-
clear(): void;
|
|
11
|
-
/**
|
|
12
|
-
* Sets the cassette records for this context. Called by SoftprobeContext.run(REPLAY)
|
|
13
|
-
* after loading from storage so each matcher fn receives them in match().
|
|
14
|
-
*/
|
|
15
|
-
_setRecords(records: SoftprobeCassetteRecord[]): void;
|
|
16
|
-
/**
|
|
17
|
-
* Returns the records for this replay context (context-scoped).
|
|
18
|
-
* Used by getRecordsForTrace when the active context has a matcher, so HTTP replay
|
|
19
|
-
* (MSW interceptor) reads from context instead of a global cache.
|
|
20
|
-
*/
|
|
21
|
-
_getRecords(): SoftprobeCassetteRecord[];
|
|
22
|
-
/**
|
|
23
|
-
* Returns the trace id for the current request (from first record).
|
|
24
|
-
* Used when context/span do not propagate to fetch so the interceptor can identify the trace.
|
|
25
|
-
*/
|
|
26
|
-
_getTraceId(): string | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Returns the inbound record's responsePayload.body, with .http extracted when present.
|
|
29
|
-
* Used by HTTP replay (MSW interceptor) so the mock response body matches the recorded inbound and diff passes.
|
|
30
|
-
*/
|
|
31
|
-
_getInboundHttpBody(): unknown;
|
|
32
|
-
/**
|
|
33
|
-
* Runs registered matcher fns in order against the current active span (or spanOverride).
|
|
34
|
-
* Returns the first non-CONTINUE action (MOCK or PASSTHROUGH), or CONTINUE if all fns continue.
|
|
35
|
-
* Each fn receives the span and this context's records (design §7.1).
|
|
36
|
-
*/
|
|
37
|
-
match(spanOverride?: import('@opentelemetry/api').Span | {
|
|
38
|
-
attributes?: Record<string, unknown>;
|
|
39
|
-
}): MatcherAction;
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=softprobe-matcher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"softprobe-matcher.d.ts","sourceRoot":"","sources":["../../src/replay/softprobe-matcher.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEzF,qBAAa,gBAAgB;IAC3B,4EAA4E;IAC5E,OAAO,CAAC,GAAG,CAAmB;IAC9B,iGAAiG;IACjG,OAAO,CAAC,OAAO,CAAiC;IAEhD,qEAAqE;IACrE,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAIxB,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,IAAI;IAIrD;;;;OAIG;IACH,WAAW,IAAI,uBAAuB,EAAE;IAIxC;;;OAGG;IACH,WAAW,IAAI,MAAM,GAAG,SAAS;IAIjC;;;OAGG;IACH,mBAAmB,IAAI,OAAO;IAoB9B;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO,oBAAoB,EAAE,IAAI,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,aAAa;CAQlH"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SoftprobeMatcher = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* SoftprobeMatcher: per-context replay matcher for outbound calls.
|
|
6
|
-
*
|
|
7
|
-
* One instance is created per SoftprobeContext.run(REPLAY) and stored in the OTel context
|
|
8
|
-
* for that request. It holds the cassette records for that trace and runs a list of MatcherFn
|
|
9
|
-
* in order; match() returns the first non-CONTINUE action (MOCK or PASSTHROUGH).
|
|
10
|
-
*
|
|
11
|
-
* Design §7.1: use(fn) appends; matchers do not execute passthrough. Records are context-scoped
|
|
12
|
-
* (loaded from the cassette for this run's traceId).
|
|
13
|
-
*/
|
|
14
|
-
const api_1 = require("@opentelemetry/api");
|
|
15
|
-
class SoftprobeMatcher {
|
|
16
|
-
constructor() {
|
|
17
|
-
/** Matcher functions run in registration order; first non-CONTINUE wins. */
|
|
18
|
-
this.fns = [];
|
|
19
|
-
/** Cassette records for this replay context (one trace). Set by SoftprobeContext.run(REPLAY). */
|
|
20
|
-
this.records = [];
|
|
21
|
-
}
|
|
22
|
-
/** Appends a matcher function. Fns are run in registration order. */
|
|
23
|
-
use(fn) {
|
|
24
|
-
this.fns.push(fn);
|
|
25
|
-
}
|
|
26
|
-
/** Removes all registered matcher fns. */
|
|
27
|
-
clear() {
|
|
28
|
-
this.fns = [];
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Sets the cassette records for this context. Called by SoftprobeContext.run(REPLAY)
|
|
32
|
-
* after loading from storage so each matcher fn receives them in match().
|
|
33
|
-
*/
|
|
34
|
-
_setRecords(records) {
|
|
35
|
-
this.records = records;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Returns the records for this replay context (context-scoped).
|
|
39
|
-
* Used by getRecordsForTrace when the active context has a matcher, so HTTP replay
|
|
40
|
-
* (MSW interceptor) reads from context instead of a global cache.
|
|
41
|
-
*/
|
|
42
|
-
_getRecords() {
|
|
43
|
-
return this.records;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Returns the trace id for the current request (from first record).
|
|
47
|
-
* Used when context/span do not propagate to fetch so the interceptor can identify the trace.
|
|
48
|
-
*/
|
|
49
|
-
_getTraceId() {
|
|
50
|
-
return this.records[0]?.traceId;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Returns the inbound record's responsePayload.body, with .http extracted when present.
|
|
54
|
-
* Used by HTTP replay (MSW interceptor) so the mock response body matches the recorded inbound and diff passes.
|
|
55
|
-
*/
|
|
56
|
-
_getInboundHttpBody() {
|
|
57
|
-
const inbound = this.records.find((r) => r.type === 'inbound');
|
|
58
|
-
const payload = inbound?.responsePayload;
|
|
59
|
-
const body = payload?.body;
|
|
60
|
-
if (body == null)
|
|
61
|
-
return undefined;
|
|
62
|
-
const parsed = typeof body === 'string'
|
|
63
|
-
? (() => {
|
|
64
|
-
try {
|
|
65
|
-
return JSON.parse(body);
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
})()
|
|
71
|
-
: body;
|
|
72
|
-
return parsed && typeof parsed === 'object' && 'http' in parsed
|
|
73
|
-
? parsed.http
|
|
74
|
-
: undefined;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Runs registered matcher fns in order against the current active span (or spanOverride).
|
|
78
|
-
* Returns the first non-CONTINUE action (MOCK or PASSTHROUGH), or CONTINUE if all fns continue.
|
|
79
|
-
* Each fn receives the span and this context's records (design §7.1).
|
|
80
|
-
*/
|
|
81
|
-
match(spanOverride) {
|
|
82
|
-
const span = (api_1.trace.getActiveSpan() ?? spanOverride);
|
|
83
|
-
for (const fn of this.fns) {
|
|
84
|
-
const r = fn(span, this.records);
|
|
85
|
-
if (r.action !== 'CONTINUE')
|
|
86
|
-
return r;
|
|
87
|
-
}
|
|
88
|
-
return { action: 'CONTINUE' };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
exports.SoftprobeMatcher = SoftprobeMatcher;
|
|
92
|
-
//# sourceMappingURL=softprobe-matcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"softprobe-matcher.js","sourceRoot":"","sources":["../../src/replay/softprobe-matcher.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;GASG;AACH,4CAA2C;AAG3C,MAAa,gBAAgB;IAA7B;QACE,4EAA4E;QACpE,QAAG,GAAgB,EAAE,CAAC;QAC9B,iGAAiG;QACzF,YAAO,GAA8B,EAAE,CAAC;IA0ElD,CAAC;IAxEC,qEAAqE;IACrE,GAAG,CAAC,EAAa;QACf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IAED,0CAA0C;IAC1C,KAAK;QACH,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,OAAkC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,mBAAmB;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,OAAO,EAAE,eAAiD,CAAC;QAC3E,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,CAAC;QAC3B,IAAI,IAAI,IAAI,IAAI;YAAE,OAAO,SAAS,CAAC;QACnC,MAAM,MAAM,GACV,OAAO,IAAI,KAAK,QAAQ;YACtB,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,IAAI,CAAC;oBACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,CAAC;gBACnB,CAAC;YACH,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,IAAI,CAAC;QACX,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,IAAI,MAAM;YAC7D,CAAC,CAAE,MAA4B,CAAC,IAAI;YACpC,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAA2F;QAC/F,MAAM,IAAI,GAAG,CAAC,WAAK,CAAC,aAAa,EAAE,IAAI,YAAY,CAAkD,CAAC;QACtG,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,CAAC,IAAyC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACtE,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;gBAAE,OAAO,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;CACF;AA9ED,4CA8EC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Replay-mode record store accessor. Records are context-scoped only: the matcher
|
|
3
|
-
* in the active OTel context holds the loaded records for that request (created by
|
|
4
|
-
* SoftprobeContext.run(REPLAY)). No global cache. Task 15.3.1.
|
|
5
|
-
* Task 13.10: Load via Cassette (getOrCreateCassette) only; no loadNdjson.
|
|
6
|
-
*/
|
|
7
|
-
import type { SoftprobeCassetteRecord } from '../types/schema';
|
|
8
|
-
/**
|
|
9
|
-
* Returns recorded cassette records for the given traceId from the active context only.
|
|
10
|
-
* The matcher is created and seeded by SoftprobeContext.run(REPLAY); only the framework creates matchers.
|
|
11
|
-
* Returns [] when there is no active matcher with records. Compares traceIds in lowercase (W3C traceparent).
|
|
12
|
-
*/
|
|
13
|
-
export declare function getRecordsForTrace(traceId: string): SoftprobeCassetteRecord[];
|
|
14
|
-
//# sourceMappingURL=store-accessor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store-accessor.d.ts","sourceRoot":"","sources":["../../src/replay/store-accessor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAK/D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAS7E"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Replay-mode record store accessor. Records are context-scoped only: the matcher
|
|
4
|
-
* in the active OTel context holds the loaded records for that request (created by
|
|
5
|
-
* SoftprobeContext.run(REPLAY)). No global cache. Task 15.3.1.
|
|
6
|
-
* Task 13.10: Load via Cassette (getOrCreateCassette) only; no loadNdjson.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.getRecordsForTrace = getRecordsForTrace;
|
|
10
|
-
const context_1 = require("../context");
|
|
11
|
-
/**
|
|
12
|
-
* Returns recorded cassette records for the given traceId from the active context only.
|
|
13
|
-
* The matcher is created and seeded by SoftprobeContext.run(REPLAY); only the framework creates matchers.
|
|
14
|
-
* Returns [] when there is no active matcher with records. Compares traceIds in lowercase (W3C traceparent).
|
|
15
|
-
*/
|
|
16
|
-
function getRecordsForTrace(traceId) {
|
|
17
|
-
const normalized = traceId.toLowerCase();
|
|
18
|
-
const matcher = context_1.SoftprobeContext.getMatcher();
|
|
19
|
-
const replayMatcher = matcher;
|
|
20
|
-
if (replayMatcher && typeof replayMatcher._getRecords === 'function') {
|
|
21
|
-
const contextRecords = replayMatcher._getRecords();
|
|
22
|
-
return contextRecords.filter((r) => (r.traceId ?? '').toLowerCase() === normalized);
|
|
23
|
-
}
|
|
24
|
-
return [];
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=store-accessor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store-accessor.js","sourceRoot":"","sources":["../../src/replay/store-accessor.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAaH,gDASC;AAlBD,wCAA8C;AAI9C;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAAe;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,0BAAgB,CAAC,UAAU,EAAE,CAAC;IAC9C,MAAM,aAAa,GAAG,OAAyC,CAAC;IAChE,IAAI,aAAa,IAAI,OAAO,aAAa,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QACrE,MAAM,cAAc,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;QACnD,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Topology-aware matching helpers (design §7.4).
|
|
3
|
-
* Read live parent name; build bySpanId index; filter candidates; createTopologyMatcher.
|
|
4
|
-
*/
|
|
5
|
-
import type { MatcherFn, SoftprobeCassetteRecord } from '../types/schema';
|
|
6
|
-
import { type SpanKey } from './extract-key';
|
|
7
|
-
/** Span-like with optional internal _parentSpanName (test or OTel plumbing). */
|
|
8
|
-
type SpanWithParent = {
|
|
9
|
-
_parentSpanName?: string;
|
|
10
|
-
} | undefined;
|
|
11
|
-
/**
|
|
12
|
-
* Returns the live parent span name for topology matching.
|
|
13
|
-
* If the span has _parentSpanName (set by instrumentation or tests), returns it; otherwise "root".
|
|
14
|
-
*/
|
|
15
|
-
export declare function getLiveParentName(span: SpanWithParent): string;
|
|
16
|
-
/**
|
|
17
|
-
* Builds a map from spanId to record for lineage lookup (design §7.4).
|
|
18
|
-
* Enables looking up a record's parent via bySpanId.get(record.parentSpanId).
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildBySpanIdIndex(records: SoftprobeCassetteRecord[]): Map<string, SoftprobeCassetteRecord>;
|
|
21
|
-
/**
|
|
22
|
-
* Filters records to outbound candidates matching protocol+identifier (design §7.4).
|
|
23
|
-
* Same semantics as flat matcher's filterOutboundCandidates.
|
|
24
|
-
*/
|
|
25
|
-
export declare function filterCandidatesByKey(records: SoftprobeCassetteRecord[], key: SpanKey): SoftprobeCassetteRecord[];
|
|
26
|
-
/**
|
|
27
|
-
* Prefers candidates whose recorded parent spanName matches live parent (design §7.4).
|
|
28
|
-
* Returns lineageMatches when non-empty, otherwise returns all candidates (fallback pool).
|
|
29
|
-
*/
|
|
30
|
-
export declare function selectLineagePool(candidates: SoftprobeCassetteRecord[], bySpanId: Map<string, SoftprobeCassetteRecord>, liveParentName: string): SoftprobeCassetteRecord[];
|
|
31
|
-
/**
|
|
32
|
-
* Returns a MatcherFn that prefers candidates whose recorded parent spanName matches
|
|
33
|
-
* the live parent, with per-(protocol, identifier, liveParentName) call sequencing (design §7.4).
|
|
34
|
-
*/
|
|
35
|
-
export declare function createTopologyMatcher(): MatcherFn;
|
|
36
|
-
export {};
|
|
37
|
-
//# sourceMappingURL=topology.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"topology.d.ts","sourceRoot":"","sources":["../../src/replay/topology.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAiB,SAAS,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAGL,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AAEvB,gFAAgF;AAChF,KAAK,cAAc,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,uBAAuB,EAAE,GACjC,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAEtC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,uBAAuB,EAAE,EAClC,GAAG,EAAE,OAAO,GACX,uBAAuB,EAAE,CAE3B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,uBAAuB,EAAE,EACrC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC9C,cAAc,EAAE,MAAM,GACrB,uBAAuB,EAAE,CAO3B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,SAAS,CAsBjD"}
|
package/dist/replay/topology.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Topology-aware matching helpers (design §7.4).
|
|
4
|
-
* Read live parent name; build bySpanId index; filter candidates; createTopologyMatcher.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.getLiveParentName = getLiveParentName;
|
|
8
|
-
exports.buildBySpanIdIndex = buildBySpanIdIndex;
|
|
9
|
-
exports.filterCandidatesByKey = filterCandidatesByKey;
|
|
10
|
-
exports.selectLineagePool = selectLineagePool;
|
|
11
|
-
exports.createTopologyMatcher = createTopologyMatcher;
|
|
12
|
-
const extract_key_1 = require("./extract-key");
|
|
13
|
-
/**
|
|
14
|
-
* Returns the live parent span name for topology matching.
|
|
15
|
-
* If the span has _parentSpanName (set by instrumentation or tests), returns it; otherwise "root".
|
|
16
|
-
*/
|
|
17
|
-
function getLiveParentName(span) {
|
|
18
|
-
return span?._parentSpanName ?? 'root';
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Builds a map from spanId to record for lineage lookup (design §7.4).
|
|
22
|
-
* Enables looking up a record's parent via bySpanId.get(record.parentSpanId).
|
|
23
|
-
*/
|
|
24
|
-
function buildBySpanIdIndex(records) {
|
|
25
|
-
return new Map(records.map((r) => [r.spanId, r]));
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Filters records to outbound candidates matching protocol+identifier (design §7.4).
|
|
29
|
-
* Same semantics as flat matcher's filterOutboundCandidates.
|
|
30
|
-
*/
|
|
31
|
-
function filterCandidatesByKey(records, key) {
|
|
32
|
-
return (0, extract_key_1.filterOutboundCandidates)(records, key);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Prefers candidates whose recorded parent spanName matches live parent (design §7.4).
|
|
36
|
-
* Returns lineageMatches when non-empty, otherwise returns all candidates (fallback pool).
|
|
37
|
-
*/
|
|
38
|
-
function selectLineagePool(candidates, bySpanId, liveParentName) {
|
|
39
|
-
const lineageMatches = candidates.filter((c) => {
|
|
40
|
-
if (!c.parentSpanId)
|
|
41
|
-
return liveParentName === 'root';
|
|
42
|
-
const parent = bySpanId.get(c.parentSpanId);
|
|
43
|
-
return (parent?.spanName ?? 'root') === liveParentName;
|
|
44
|
-
});
|
|
45
|
-
return lineageMatches.length > 0 ? lineageMatches : candidates;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Returns a MatcherFn that prefers candidates whose recorded parent spanName matches
|
|
49
|
-
* the live parent, with per-(protocol, identifier, liveParentName) call sequencing (design §7.4).
|
|
50
|
-
*/
|
|
51
|
-
function createTopologyMatcher() {
|
|
52
|
-
const callSeq = new Map();
|
|
53
|
-
return (span, records) => {
|
|
54
|
-
const key = (0, extract_key_1.extractKeyFromSpan)(span);
|
|
55
|
-
if (!key)
|
|
56
|
-
return { action: 'CONTINUE' };
|
|
57
|
-
const liveParentName = getLiveParentName(span);
|
|
58
|
-
const candidates = filterCandidatesByKey(records, key);
|
|
59
|
-
if (candidates.length === 0)
|
|
60
|
-
return { action: 'CONTINUE' };
|
|
61
|
-
const bySpanId = buildBySpanIdIndex(records);
|
|
62
|
-
const pool = selectLineagePool(candidates, bySpanId, liveParentName);
|
|
63
|
-
const seqKey = `${key.protocol}::${key.identifier}::${liveParentName}`;
|
|
64
|
-
const n = callSeq.get(seqKey) ?? 0;
|
|
65
|
-
const picked = pool[n];
|
|
66
|
-
callSeq.set(seqKey, n + 1);
|
|
67
|
-
if (!picked)
|
|
68
|
-
return { action: 'CONTINUE' };
|
|
69
|
-
return { action: 'MOCK', payload: picked.responsePayload };
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
//# sourceMappingURL=topology.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"topology.js","sourceRoot":"","sources":["../../src/replay/topology.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAgBH,8CAEC;AAMD,gDAIC;AAMD,sDAKC;AAMD,8CAWC;AAMD,sDAsBC;AAjFD,+CAIuB;AAKvB;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,IAAoB;IACpD,OAAQ,IAAY,EAAE,eAAe,IAAI,MAAM,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAChC,OAAkC;IAElC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,OAAkC,EAClC,GAAY;IAEZ,OAAO,IAAA,sCAAwB,EAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAC/B,UAAqC,EACrC,QAA8C,EAC9C,cAAsB;IAEtB,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7C,IAAI,CAAC,CAAC,CAAC,YAAY;YAAE,OAAO,cAAc,KAAK,MAAM,CAAC;QACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAC5C,OAAO,CAAC,MAAM,EAAE,QAAQ,IAAI,MAAM,CAAC,KAAK,cAAc,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,OAAO,CAAC,IAAI,EAAE,OAAO,EAAiB,EAAE;QACtC,MAAM,GAAG,GAAG,IAAA,gCAAkB,EAAC,IAAgD,CAAC,CAAC;QACjF,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAExC,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAsB,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,qBAAqB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACvD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAE3D,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,iBAAiB,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAErE,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,UAAU,KAAK,cAAc,EAAE,CAAC;QACvE,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC;IAC7D,CAAC,CAAC;AACJ,CAAC"}
|