cassetter 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/binding.d.ts +60 -0
  4. package/dist/binding.d.ts.map +1 -0
  5. package/dist/binding.js +12 -0
  6. package/dist/binding.js.map +1 -0
  7. package/dist/cassette.d.ts +122 -0
  8. package/dist/cassette.d.ts.map +1 -0
  9. package/dist/cassette.js +377 -0
  10. package/dist/cassette.js.map +1 -0
  11. package/dist/context.d.ts +22 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +70 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/index.d.ts +29 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +26 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/intercept/base.d.ts +11 -0
  20. package/dist/intercept/base.d.ts.map +1 -0
  21. package/dist/intercept/base.js +20 -0
  22. package/dist/intercept/base.js.map +1 -0
  23. package/dist/intercept/fetch.d.ts +13 -0
  24. package/dist/intercept/fetch.d.ts.map +1 -0
  25. package/dist/intercept/fetch.js +104 -0
  26. package/dist/intercept/fetch.js.map +1 -0
  27. package/dist/intercept/index.d.ts +4 -0
  28. package/dist/intercept/index.d.ts.map +1 -0
  29. package/dist/intercept/index.js +3 -0
  30. package/dist/intercept/index.js.map +1 -0
  31. package/dist/recording.d.ts +22 -0
  32. package/dist/recording.d.ts.map +1 -0
  33. package/dist/recording.js +51 -0
  34. package/dist/recording.js.map +1 -0
  35. package/dist/types.d.ts +96 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +35 -0
  38. package/dist/types.js.map +1 -0
  39. package/native/cassetter.darwin-arm64.node +0 -0
  40. package/native/cassetter.darwin-x64.node +0 -0
  41. package/native/cassetter.linux-arm64-gnu.node +0 -0
  42. package/native/cassetter.linux-arm64-musl.node +0 -0
  43. package/native/cassetter.linux-x64-gnu.node +0 -0
  44. package/native/cassetter.linux-x64-musl.node +0 -0
  45. package/native/cassetter.win32-arm64-msvc.node +0 -0
  46. package/native/cassetter.win32-x64-msvc.node +0 -0
  47. package/native/index.js +326 -0
  48. package/native/package.json +3 -0
  49. package/package.json +74 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Intercepts the global `fetch` to record and replay HTTP traffic.
3
+ */
4
+ import { NoMatchError } from "../cassette.js";
5
+ import { bodyToBuffer } from "../types.js";
6
+ import { isLocalhost } from "./base.js";
7
+ const FETCH_PATCHES = new WeakMap();
8
+ function activeFetch(candidate) {
9
+ let current = candidate;
10
+ let patch = FETCH_PATCHES.get(current);
11
+ while (patch && !patch.active) {
12
+ current = patch.previous;
13
+ patch = FETCH_PATCHES.get(current);
14
+ }
15
+ return current;
16
+ }
17
+ export class FetchInterceptor {
18
+ _patched = null;
19
+ /** Replace the global `fetch` with one backed by `cassette`. */
20
+ install(cassette) {
21
+ const patch = {
22
+ active: true,
23
+ previous: globalThis.fetch,
24
+ };
25
+ const patched = async (input, init) => {
26
+ if (!patch.active) {
27
+ return activeFetch(patch.previous)(input, init);
28
+ }
29
+ const request = new Request(input, init);
30
+ const { method, url: uri } = request;
31
+ if (cassette.ignoreLocalhost && isLocalhost(uri)) {
32
+ return patch.previous(input, init);
33
+ }
34
+ const headers = extractHeaders(request.headers);
35
+ const requestBody = method === "GET" || method === "HEAD"
36
+ ? null
37
+ : Buffer.from(await request.clone().arrayBuffer());
38
+ try {
39
+ return buildResponse(cassette.play(method, uri, headers, requestBody));
40
+ }
41
+ catch (e) {
42
+ if (!(e instanceof NoMatchError) || !cassette.canRecord)
43
+ throw e;
44
+ }
45
+ // Claim the slot before going out: under concurrency the responses come
46
+ // back in whatever order they finish, and recording in that order would
47
+ // write a different cassette on every run.
48
+ const order = cassette.reserveRecordOrder();
49
+ const real = await patch.previous(request.clone());
50
+ const responseBody = Buffer.from(await real.clone().arrayBuffer());
51
+ cassette.record(method, uri, headers, requestBody, real.status,
52
+ // `arrayBuffer()` hands back decoded bytes while the upstream encoding
53
+ // and length headers describe the compressed representation.
54
+ extractDecodedResponseHeaders(real.headers), responseBody, order);
55
+ return real;
56
+ };
57
+ FETCH_PATCHES.set(patched, patch);
58
+ this._patched = patched;
59
+ globalThis.fetch = patched;
60
+ }
61
+ /** Put the previous active `fetch` back if this interceptor owns the global. */
62
+ uninstall() {
63
+ if (!this._patched)
64
+ return;
65
+ const patch = FETCH_PATCHES.get(this._patched);
66
+ if (patch) {
67
+ patch.active = false;
68
+ if (globalThis.fetch === this._patched) {
69
+ globalThis.fetch = activeFetch(patch.previous);
70
+ }
71
+ }
72
+ this._patched = null;
73
+ }
74
+ }
75
+ function extractDecodedResponseHeaders(headers) {
76
+ const out = extractHeaders(headers);
77
+ delete out["content-encoding"];
78
+ delete out["content-length"];
79
+ return out;
80
+ }
81
+ /** Collect a `Headers` into name-to-values, lowercasing names. */
82
+ function extractHeaders(headers) {
83
+ const out = {};
84
+ headers.forEach((value, key) => {
85
+ const lower = key.toLowerCase();
86
+ (out[lower] ??= []).push(value);
87
+ });
88
+ return out;
89
+ }
90
+ /** Turn a recorded response back into a `Response`. */
91
+ function buildResponse(response) {
92
+ const headers = [];
93
+ for (const [key, values] of Object.entries(response.headers)) {
94
+ for (const value of values) {
95
+ headers.push([key, value]);
96
+ }
97
+ }
98
+ // 204/304 must not carry a body.
99
+ const body = response.status === 204 || response.status === 304
100
+ ? null
101
+ : bodyToBuffer(response.body);
102
+ return new Response(body, { status: response.status, headers });
103
+ }
104
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/intercept/fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { FetchInterceptor } from "./fetch.js";
2
+ export type { Interceptor } from "./base.js";
3
+ export { isLocalhost } from "./base.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intercept/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { FetchInterceptor } from "./fetch.js";
2
+ export { isLocalhost } from "./base.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/intercept/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Record modes and duration parsing.
3
+ */
4
+ export declare enum RecordMode {
5
+ /** Replay only. Throws if no match is found. */
6
+ NONE = "none",
7
+ /** Record if the cassette doesn't exist; replay if it does. */
8
+ ONCE = "once",
9
+ /** Replay existing interactions, record new ones. */
10
+ NEW_EPISODES = "new_episodes",
11
+ /** Record everything, overwriting the cassette. */
12
+ ALL = "all",
13
+ /** Delete the cassette, then record everything. */
14
+ REWRITE = "rewrite"
15
+ }
16
+ /** Modes that discard whatever the cassette already held. */
17
+ export declare const DISCARDING_MODES: readonly RecordMode[];
18
+ /** Parse a record mode name, accepting hyphens for underscores. */
19
+ export declare function parseRecordMode(value: string): RecordMode;
20
+ /** Parse a duration like `30d`, `24h`, or `4w` into milliseconds. */
21
+ export declare function parseDuration(s: string): number;
22
+ //# sourceMappingURL=recording.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording.d.ts","sourceRoot":"","sources":["../src/recording.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oBAAY,UAAU;IACpB,gDAAgD;IAChD,IAAI,SAAS;IACb,+DAA+D;IAC/D,IAAI,SAAS;IACb,qDAAqD;IACrD,YAAY,iBAAiB;IAC7B,mDAAmD;IACnD,GAAG,QAAQ;IACX,mDAAmD;IACnD,OAAO,YAAY;CACpB;AAUD,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,EAAE,SAAS,UAAU,EAGjD,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAQzD;AASD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/C"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Record modes and duration parsing.
3
+ */
4
+ export var RecordMode;
5
+ (function (RecordMode) {
6
+ /** Replay only. Throws if no match is found. */
7
+ RecordMode["NONE"] = "none";
8
+ /** Record if the cassette doesn't exist; replay if it does. */
9
+ RecordMode["ONCE"] = "once";
10
+ /** Replay existing interactions, record new ones. */
11
+ RecordMode["NEW_EPISODES"] = "new_episodes";
12
+ /** Record everything, overwriting the cassette. */
13
+ RecordMode["ALL"] = "all";
14
+ /** Delete the cassette, then record everything. */
15
+ RecordMode["REWRITE"] = "rewrite";
16
+ })(RecordMode || (RecordMode = {}));
17
+ const RECORD_MODES = {
18
+ none: RecordMode.NONE,
19
+ once: RecordMode.ONCE,
20
+ new_episodes: RecordMode.NEW_EPISODES,
21
+ all: RecordMode.ALL,
22
+ rewrite: RecordMode.REWRITE,
23
+ };
24
+ /** Modes that discard whatever the cassette already held. */
25
+ export const DISCARDING_MODES = [
26
+ RecordMode.ALL,
27
+ RecordMode.REWRITE,
28
+ ];
29
+ /** Parse a record mode name, accepting hyphens for underscores. */
30
+ export function parseRecordMode(value) {
31
+ const mode = RECORD_MODES[value.toLowerCase().replace(/-/g, "_")];
32
+ if (mode === undefined) {
33
+ throw new Error(`unknown record mode: '${value}', expected one of ${Object.keys(RECORD_MODES).join(", ")}`);
34
+ }
35
+ return mode;
36
+ }
37
+ const DURATION_RE = /^(\d+)([dhw])$/;
38
+ const UNIT_MS = {
39
+ h: 60 * 60 * 1000,
40
+ d: 24 * 60 * 60 * 1000,
41
+ w: 7 * 24 * 60 * 60 * 1000,
42
+ };
43
+ /** Parse a duration like `30d`, `24h`, or `4w` into milliseconds. */
44
+ export function parseDuration(s) {
45
+ const m = DURATION_RE.exec(s);
46
+ if (!m) {
47
+ throw new Error(`invalid duration string: '${s}' (expected <number><d|h|w>)`);
48
+ }
49
+ return parseInt(m[1], 10) * UNIT_MS[m[2]];
50
+ }
51
+ //# sourceMappingURL=recording.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording.js","sourceRoot":"","sources":["../src/recording.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAN,IAAY,UAWX;AAXD,WAAY,UAAU;IACpB,gDAAgD;IAChD,2BAAa,CAAA;IACb,+DAA+D;IAC/D,2BAAa,CAAA;IACb,qDAAqD;IACrD,2CAA6B,CAAA;IAC7B,mDAAmD;IACnD,yBAAW,CAAA;IACX,mDAAmD;IACnD,iCAAmB,CAAA;AACrB,CAAC,EAXW,UAAU,KAAV,UAAU,QAWrB;AAED,MAAM,YAAY,GAA+B;IAC/C,IAAI,EAAE,UAAU,CAAC,IAAI;IACrB,IAAI,EAAE,UAAU,CAAC,IAAI;IACrB,YAAY,EAAE,UAAU,CAAC,YAAY;IACrC,GAAG,EAAE,UAAU,CAAC,GAAG;IACnB,OAAO,EAAE,UAAU,CAAC,OAAO;CAC5B,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,UAAU,CAAC,GAAG;IACd,UAAU,CAAC,OAAO;CACnB,CAAC;AAEF,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IAClE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,yBAAyB,KAAK,sBAAsB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,WAAW,GAAG,gBAAgB,CAAC;AACrC,MAAM,OAAO,GAA2B;IACtC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;CAC3B,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,8BAA8B,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Data shapes exchanged with the native core.
3
+ *
4
+ * These mirror the cassette file format one-to-one, so what you see here is
5
+ * what is written to disk and what the Python binding produces. Binary bodies
6
+ * are hex strings (as in the file); use `bodyToBuffer` / `binaryBody` to move
7
+ * between hex and `Buffer`.
8
+ */
9
+ export type BodyType = "json" | "text" | "binary" | "none";
10
+ /** The matchers a `MatchConfig` may name. */
11
+ export type Matcher = "method" | "uri" | "headers" | "body" | "json_body";
12
+ export interface Body {
13
+ type: BodyType;
14
+ /** Parsed JSON for `json`, the string for `text`, hex for `binary`. */
15
+ content?: unknown;
16
+ }
17
+ export type HeaderMap = Record<string, string[]>;
18
+ export interface HttpRequest {
19
+ method: string;
20
+ uri: string;
21
+ headers: HeaderMap;
22
+ body: Body;
23
+ }
24
+ export interface HttpResponse {
25
+ status: number;
26
+ headers: HeaderMap;
27
+ body: Body;
28
+ }
29
+ export interface HttpInteraction {
30
+ request: HttpRequest;
31
+ response: HttpResponse;
32
+ recordedAt: string;
33
+ }
34
+ export interface GrpcRequest {
35
+ method: string;
36
+ metadata: HeaderMap;
37
+ body: Body;
38
+ }
39
+ export interface GrpcResponse {
40
+ statusCode: number;
41
+ statusMessage: string;
42
+ metadata: HeaderMap;
43
+ body: Body;
44
+ }
45
+ export interface GrpcInteraction {
46
+ request: GrpcRequest;
47
+ response: GrpcResponse;
48
+ recordedAt: string;
49
+ jsonDebug?: unknown;
50
+ }
51
+ export interface WsFrame {
52
+ direction: "send" | "recv";
53
+ frameType: "text" | "binary" | "close";
54
+ body: Body;
55
+ offsetMs: number;
56
+ }
57
+ export interface WsInteraction {
58
+ uri: string;
59
+ headers: HeaderMap;
60
+ frames: WsFrame[];
61
+ recordedAt: string;
62
+ }
63
+ /** Fields to match a request on. Defaults to `["method", "uri"]`. */
64
+ export interface MatchConfig {
65
+ matchOn?: Matcher[];
66
+ ignoreJsonPaths?: string[];
67
+ }
68
+ /**
69
+ * Security filtering.
70
+ *
71
+ * Each list **adds to** the built-in defaults rather than standing in for
72
+ * them, so naming one more header to scrub never starts recording the ones
73
+ * already covered. Read the built-ins with `defaultFilterHeaders()` and
74
+ * friends.
75
+ */
76
+ export interface SecurityConfig {
77
+ filterHeaders?: string[];
78
+ filterQueryParameters?: string[];
79
+ bodyScrubPatterns?: string[];
80
+ replacement?: string;
81
+ }
82
+ export interface CassetteConfig extends MatchConfig, SecurityConfig {
83
+ recordMode?: string;
84
+ intercept?: string[];
85
+ maxAge?: string;
86
+ onExpiry?: "warn" | "fail" | "rerecord";
87
+ ignoreLocalhost?: boolean;
88
+ }
89
+ export declare const NONE_BODY: Body;
90
+ /** Decode a body into raw bytes, whatever its type. */
91
+ export declare function bodyToBuffer(body: Body): Buffer;
92
+ /** Build a binary body from raw bytes (stored as hex, as in the cassette). */
93
+ export declare function binaryBody(buf: Buffer): Body;
94
+ /** Read a binary body's bytes. Throws if the body is not binary. */
95
+ export declare function binaryBodyBytes(body: Body): Buffer;
96
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Data shapes exchanged with the native core.
3
+ *
4
+ * These mirror the cassette file format one-to-one, so what you see here is
5
+ * what is written to disk and what the Python binding produces. Binary bodies
6
+ * are hex strings (as in the file); use `bodyToBuffer` / `binaryBody` to move
7
+ * between hex and `Buffer`.
8
+ */
9
+ // --- Body helpers ---
10
+ export const NONE_BODY = { type: "none" };
11
+ /** Decode a body into raw bytes, whatever its type. */
12
+ export function bodyToBuffer(body) {
13
+ switch (body.type) {
14
+ case "json":
15
+ return Buffer.from(JSON.stringify(body.content ?? null));
16
+ case "text":
17
+ return Buffer.from(String(body.content ?? ""));
18
+ case "binary":
19
+ return Buffer.from(String(body.content ?? ""), "hex");
20
+ default:
21
+ return Buffer.alloc(0);
22
+ }
23
+ }
24
+ /** Build a binary body from raw bytes (stored as hex, as in the cassette). */
25
+ export function binaryBody(buf) {
26
+ return { type: "binary", content: buf.toString("hex") };
27
+ }
28
+ /** Read a binary body's bytes. Throws if the body is not binary. */
29
+ export function binaryBodyBytes(body) {
30
+ if (body.type !== "binary") {
31
+ throw new TypeError(`expected a binary body, got '${body.type}'`);
32
+ }
33
+ return Buffer.from(String(body.content ?? ""), "hex");
34
+ }
35
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiGH,uBAAuB;AAEvB,MAAM,CAAC,MAAM,SAAS,GAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAEhD,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC;QAC3D,KAAK,MAAM;YACT,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QACjD,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACxD;YACE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,IAAI,SAAS,CAAC,gCAAgC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC"}
Binary file