@useairfoil/effect-vcr 0.4.6 → 0.4.7
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 +31 -229
- package/dist/{cassette-store-BMtcjh5h.d.ts → cassette-store.d.mts} +13 -17
- package/dist/{cassette-store-BF9e0rz3.js → cassette-store.mjs} +6 -7
- package/dist/cassette-store.mjs.map +1 -0
- package/dist/file-system-cassette-store.d.mts +17 -0
- package/dist/{file-system-cassette-store-CyOsu3z5.js → file-system-cassette-store.mjs} +7 -8
- package/dist/file-system-cassette-store.mjs.map +1 -0
- package/dist/{index.d.ts → index.d.mts} +4 -4
- package/dist/index.mjs +5 -0
- package/dist/{chunk-Bp6m_JJh.js → rolldown-runtime-D7D4PA-g.mjs} +4 -4
- package/dist/{types-XZehMu_v.d.ts → types-v6cSTgDp.d.mts} +3 -3
- package/dist/{types.d.ts → types.d.mts} +1 -1
- package/dist/{types-DMuz_JGd.js → types.mjs} +3 -4
- package/dist/types.mjs.map +1 -0
- package/dist/{vcr-http-client-Ba0WYPV9.js → vcr-http-client-5K20k6US.mjs} +67 -45
- package/dist/vcr-http-client-5K20k6US.mjs.map +1 -0
- package/dist/vcr-http-client.d.mts +21 -0
- package/dist/vcr-http-client.mjs +3 -0
- package/dist/{vitest-state-CiW5dzXZ.js → vitest-state-rX5XIlH6.mjs} +2 -2
- package/dist/vitest-state-rX5XIlH6.mjs.map +1 -0
- package/package.json +25 -25
- package/src/sanitize.ts +21 -2
- package/src/types.ts +2 -0
- package/src/vcr-http-client.ts +81 -33
- package/dist/cassette-store-BF9e0rz3.js.map +0 -1
- package/dist/cassette-store.d.ts +0 -3
- package/dist/cassette-store.js +0 -4
- package/dist/file-system-cassette-store-ClYAuH7U.d.ts +0 -19
- package/dist/file-system-cassette-store-CyOsu3z5.js.map +0 -1
- package/dist/file-system-cassette-store.d.ts +0 -4
- package/dist/file-system-cassette-store.js +0 -6
- package/dist/index.js +0 -7
- package/dist/types-DMuz_JGd.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/vcr-http-client-Ba0WYPV9.js.map +0 -1
- package/dist/vcr-http-client-BveeoOoW.d.ts +0 -26
- package/dist/vcr-http-client.d.ts +0 -4
- package/dist/vcr-http-client.js +0 -6
- package/dist/vitest-state-CiW5dzXZ.js.map +0 -1
package/src/vcr-http-client.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Array as Arr, Config, Data, Effect, Option, Path } from "effect";
|
|
1
|
+
import { Array as Arr, Config, Data, Effect, Option, Path, Result, Semaphore } from "effect";
|
|
2
2
|
import {
|
|
3
3
|
HttpClient,
|
|
4
4
|
HttpClientError,
|
|
5
5
|
type HttpClientRequest,
|
|
6
6
|
HttpClientResponse,
|
|
7
|
-
|
|
7
|
+
Url,
|
|
8
|
+
} from "effect/http";
|
|
8
9
|
|
|
9
10
|
import type { Cassette, CassetteFile, VcrConfig, VcrEntry, VcrRequest, VcrResponse } from "./types";
|
|
10
11
|
|
|
@@ -90,7 +91,7 @@ const normalizeConfig = (config: VcrConfig): VcrConfig => {
|
|
|
90
91
|
};
|
|
91
92
|
};
|
|
92
93
|
|
|
93
|
-
const AckDisableVcrConfig = Config.option(Config.
|
|
94
|
+
const AckDisableVcrConfig = Config.option(Config.String("ACK_DISABLE_VCR")).pipe(
|
|
94
95
|
Config.map((value) =>
|
|
95
96
|
Option.match(value, {
|
|
96
97
|
onNone: () => new Set<string>(),
|
|
@@ -165,12 +166,22 @@ const toVcrRequest = (request: HttpClientRequest.HttpClientRequest): VcrRequest
|
|
|
165
166
|
|
|
166
167
|
return {
|
|
167
168
|
method: request.method,
|
|
168
|
-
url: request
|
|
169
|
+
url: requestUrl(request),
|
|
169
170
|
headers,
|
|
170
171
|
body,
|
|
171
172
|
};
|
|
172
173
|
};
|
|
173
174
|
|
|
175
|
+
/**
|
|
176
|
+
* The URL with its query params, built like `HttpClient` builds it.
|
|
177
|
+
* `request.url` alone leaves out params set with `setUrlParams`.
|
|
178
|
+
*/
|
|
179
|
+
const requestUrl = (request: HttpClientRequest.HttpClientRequest): string =>
|
|
180
|
+
Result.match(Url.make(request.url, request.urlParams, Option.getOrUndefined(request.hash)), {
|
|
181
|
+
onFailure: () => request.url,
|
|
182
|
+
onSuccess: (url) => url.toString(),
|
|
183
|
+
});
|
|
184
|
+
|
|
174
185
|
/**
|
|
175
186
|
* Serialize an Effect HttpClientResponse into a cassette response shape.
|
|
176
187
|
*/
|
|
@@ -243,6 +254,7 @@ const findEntry = (
|
|
|
243
254
|
}
|
|
244
255
|
return buildRequestKey(request, {
|
|
245
256
|
ignoreHeaders: config.matchIgnore?.requestHeaders,
|
|
257
|
+
ignoreQueryParams: config.redact?.requestQueryParams,
|
|
246
258
|
ignoreBodyKeys: config.matchIgnore?.requestBodyKeys,
|
|
247
259
|
}).pipe(Effect.map((key) => cassette.entries[key]));
|
|
248
260
|
};
|
|
@@ -278,7 +290,7 @@ const replay = (
|
|
|
278
290
|
new HttpClientError.HttpClientError({
|
|
279
291
|
reason: new HttpClientError.TransportError({
|
|
280
292
|
request,
|
|
281
|
-
description: `VCR replay missing entry for ${request.method} ${request
|
|
293
|
+
description: `VCR replay missing entry for ${request.method} ${requestUrl(request)}`,
|
|
282
294
|
}),
|
|
283
295
|
}),
|
|
284
296
|
);
|
|
@@ -294,6 +306,7 @@ const replay = (
|
|
|
294
306
|
* Record a live response into the cassette and return the original response.
|
|
295
307
|
*/
|
|
296
308
|
const record = Effect.fnUntraced(function* (
|
|
309
|
+
writeLock: Semaphore.Semaphore,
|
|
297
310
|
store: CassetteStoreService,
|
|
298
311
|
request: HttpClientRequest.HttpClientRequest,
|
|
299
312
|
vcrRequest: VcrRequest,
|
|
@@ -308,6 +321,7 @@ const record = Effect.fnUntraced(function* (
|
|
|
308
321
|
|
|
309
322
|
const sanitizedRequest = config.redact
|
|
310
323
|
? redactRequest(vcrRequest, {
|
|
324
|
+
redactQueryParams: config.redact.requestQueryParams,
|
|
311
325
|
redactHeaders: config.redact.requestHeaders,
|
|
312
326
|
redactBodyKeys: config.redact.requestBodyKeys,
|
|
313
327
|
bodyReplacements: config.redact.requestBodyReplacements,
|
|
@@ -321,30 +335,36 @@ const record = Effect.fnUntraced(function* (
|
|
|
321
335
|
})
|
|
322
336
|
: vcrResponse;
|
|
323
337
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
338
|
+
// Concurrent requests record into the same file, so writes take turns.
|
|
339
|
+
yield* writeLock.withPermits(1)(
|
|
340
|
+
Effect.gen(function* () {
|
|
341
|
+
const file = yield* loadOrInitCassetteFile(store, name, request);
|
|
342
|
+
const cassette = file.exports[exportKey] ?? (yield* createEmptyCassette());
|
|
343
|
+
const key = yield* buildRequestKey(vcrRequest, {
|
|
344
|
+
ignoreHeaders: config.matchIgnore?.requestHeaders,
|
|
345
|
+
ignoreQueryParams: config.redact?.requestQueryParams,
|
|
346
|
+
ignoreBodyKeys: config.matchIgnore?.requestBodyKeys,
|
|
347
|
+
});
|
|
348
|
+
const next: Cassette = {
|
|
349
|
+
...cassette,
|
|
350
|
+
entries: {
|
|
351
|
+
...cassette.entries,
|
|
352
|
+
[key]: {
|
|
353
|
+
request: sanitizedRequest,
|
|
354
|
+
response: sanitizedResponse,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
const nextFile: CassetteFile = {
|
|
359
|
+
...file,
|
|
360
|
+
exports: {
|
|
361
|
+
...file.exports,
|
|
362
|
+
[exportKey]: next,
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
yield* saveCassetteFile(store, name, nextFile, request);
|
|
366
|
+
}),
|
|
367
|
+
);
|
|
348
368
|
return response;
|
|
349
369
|
});
|
|
350
370
|
|
|
@@ -355,7 +375,7 @@ const makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {
|
|
|
355
375
|
const live = yield* HttpClient.HttpClient;
|
|
356
376
|
const normalized = normalizeConfig(config);
|
|
357
377
|
|
|
358
|
-
const isCi = yield* Config.
|
|
378
|
+
const isCi = yield* Config.Boolean("CI").pipe(Config.withDefault(false));
|
|
359
379
|
|
|
360
380
|
const disabledVcrs = yield* AckDisableVcrConfig;
|
|
361
381
|
if (shouldDisableVcr(normalized.vcrName, disabledVcrs)) {
|
|
@@ -363,6 +383,7 @@ const makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {
|
|
|
363
383
|
}
|
|
364
384
|
|
|
365
385
|
const store = yield* CassetteStore;
|
|
386
|
+
const writeLock = yield* Semaphore.make(1);
|
|
366
387
|
|
|
367
388
|
const { name, exportKey } = yield* resolveCassetteLocation(normalized);
|
|
368
389
|
|
|
@@ -375,7 +396,16 @@ const makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {
|
|
|
375
396
|
}
|
|
376
397
|
|
|
377
398
|
if (normalized.mode === "record") {
|
|
378
|
-
return yield* record(
|
|
399
|
+
return yield* record(
|
|
400
|
+
writeLock,
|
|
401
|
+
store,
|
|
402
|
+
request,
|
|
403
|
+
vcrRequest,
|
|
404
|
+
effect,
|
|
405
|
+
normalized,
|
|
406
|
+
name,
|
|
407
|
+
exportKey,
|
|
408
|
+
);
|
|
379
409
|
}
|
|
380
410
|
|
|
381
411
|
const available = yield* store
|
|
@@ -394,7 +424,16 @@ const makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {
|
|
|
394
424
|
);
|
|
395
425
|
}
|
|
396
426
|
|
|
397
|
-
return yield* record(
|
|
427
|
+
return yield* record(
|
|
428
|
+
writeLock,
|
|
429
|
+
store,
|
|
430
|
+
request,
|
|
431
|
+
vcrRequest,
|
|
432
|
+
effect,
|
|
433
|
+
normalized,
|
|
434
|
+
name,
|
|
435
|
+
exportKey,
|
|
436
|
+
);
|
|
398
437
|
}
|
|
399
438
|
|
|
400
439
|
const cassette = yield* readCassetteExport(store, name, exportKey, request);
|
|
@@ -404,7 +443,16 @@ const makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {
|
|
|
404
443
|
return replayResponse(request, entry);
|
|
405
444
|
}
|
|
406
445
|
|
|
407
|
-
return yield* record(
|
|
446
|
+
return yield* record(
|
|
447
|
+
writeLock,
|
|
448
|
+
store,
|
|
449
|
+
request,
|
|
450
|
+
vcrRequest,
|
|
451
|
+
effect,
|
|
452
|
+
normalized,
|
|
453
|
+
name,
|
|
454
|
+
exportKey,
|
|
455
|
+
);
|
|
408
456
|
}),
|
|
409
457
|
),
|
|
410
458
|
);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cassette-store-BF9e0rz3.js","names":[],"sources":["../src/cassette-store.ts"],"sourcesContent":["import { Context, Data, DateTime, Effect, Schema } from \"effect\";\n\nimport { CassetteFileSchema, type Cassette, type CassetteFile } from \"./types\";\n\nexport type CassetteStoreOperation = \"exists\" | \"load\" | \"save\" | \"loadOrInit\" | \"resolveRoot\";\n\n/**\n * Storage contract for VCR cassettes.\n *\n */\nexport interface CassetteStoreService {\n /** Returns true if a cassette with the given name exists. */\n readonly exists: (name: string) => Effect.Effect<boolean, CassetteStoreError>;\n\n /** Loads a cassette by name, returning a `CassetteFile` if found. */\n readonly load: (name: string) => Effect.Effect<CassetteFile, CassetteStoreError>;\n\n /** Saves a cassette by name, overwriting any existing cassette with the same name. */\n readonly save: (name: string, content: CassetteFile) => Effect.Effect<void, CassetteStoreError>;\n\n /** Loads a cassette by name, initializing a new empty cassette if not found. */\n readonly loadOrInit: (name: string) => Effect.Effect<CassetteFile, CassetteStoreError>;\n}\n\n/**\n * Effect service tag for the cassette store.\n */\nexport class CassetteStore extends Context.Service<CassetteStore, CassetteStoreService>()(\n \"@useairfoil/effect-vcr/CassetteStore\",\n) {}\n\n/**\n * Creates a new empty cassette with a timestamp and format version.\n */\nexport const createEmptyCassette = Effect.fnUntraced(function* (): Effect.fn.Return<Cassette> {\n const now = yield* DateTime.now;\n return {\n meta: {\n createdAt: DateTime.formatIso(now),\n version: \"1\",\n },\n entries: {},\n };\n});\n\nexport const createEmptyCassetteFile = (): Effect.Effect<CassetteFile> =>\n Effect.map(createEmptyCassette(), (cassette) => ({\n exports: { default: cassette },\n }));\n\n/**\n * Structured error for cassette persistence operations.\n *\n * `operation` indicates which store function failed.\n * `path` is the file or directory path that was targeted.\n */\nexport class CassetteStoreError extends Data.TaggedError(\"CassetteStoreError\")<{\n readonly operation: CassetteStoreOperation;\n readonly path: string;\n readonly message?: string;\n readonly cause?: unknown;\n}> {}\n\nexport const toStoreError = (\n operation: CassetteStoreOperation,\n path: string,\n cause?: unknown,\n message?: string,\n) =>\n new CassetteStoreError({\n operation,\n path,\n cause,\n message,\n });\n\n/**\n * Parses cassette JSON and maps invalid JSON or an invalid cassette shape to a store error.\n */\nexport const parseCassette = (\n content: string,\n path: string,\n): Effect.Effect<CassetteFile, CassetteStoreError> =>\n Effect.try({\n try: () => JSON.parse(content) as unknown,\n catch: (error) => toStoreError(\"load\", path, error, \"Invalid JSON\"),\n }).pipe(\n Effect.flatMap((parsed) =>\n Schema.decodeUnknownEffect(CassetteFileSchema)(parsed).pipe(\n Effect.mapError((error) =>\n toStoreError(\"load\", path, error, \"Invalid cassette file format\"),\n ),\n ),\n ),\n );\n\n/** Creates a `CassetteStore` implementation that uses the given `impl` object. */\nexport const make = (impl: CassetteStoreService): CassetteStoreService =>\n CassetteStore.of({ ...impl });\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,IAAa,gBAAb,cAAmC,QAAQ,SAA8C,CACvF,uCACD,CAAC;;;;AAKF,MAAa,sBAAsB,OAAO,WAAW,aAAyC;CAC5F,MAAM,MAAM,OAAO,SAAS;AAC5B,QAAO;EACL,MAAM;GACJ,WAAW,SAAS,UAAU,IAAI;GAClC,SAAS;GACV;EACD,SAAS,EAAE;EACZ;EACD;AAEF,MAAa,gCACX,OAAO,IAAI,qBAAqB,GAAG,cAAc,EAC/C,SAAS,EAAE,SAAS,UAAU,EAC/B,EAAE;;;;;;;AAQL,IAAa,qBAAb,cAAwC,KAAK,YAAY,qBAAqB,CAK3E;AAEH,MAAa,gBACX,WACA,MACA,OACA,YAEA,IAAI,mBAAmB;CACrB;CACA;CACA;CACA;CACD,CAAC;;;;AAKJ,MAAa,iBACX,SACA,SAEA,OAAO,IAAI;CACT,WAAW,KAAK,MAAM,QAAQ;CAC9B,QAAQ,UAAU,aAAa,QAAQ,MAAM,OAAO,eAAe;CACpE,CAAC,CAAC,KACD,OAAO,SAAS,WACd,OAAO,oBAAoB,mBAAmB,CAAC,OAAO,CAAC,KACrD,OAAO,UAAU,UACf,aAAa,QAAQ,MAAM,OAAO,+BAA+B,CAClE,CACF,CACF,CACF;;AAGH,MAAa,QAAQ,SACnB,cAAc,GAAG,EAAE,GAAG,MAAM,CAAC"}
|
package/dist/cassette-store.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import "./types-XZehMu_v.js";
|
|
2
|
-
import { c as make, i as CassetteStoreService, l as parseCassette, n as CassetteStoreError, o as createEmptyCassette, r as CassetteStoreOperation, s as createEmptyCassetteFile, t as CassetteStore, u as toStoreError } from "./cassette-store-BMtcjh5h.js";
|
|
3
|
-
export { CassetteStore, CassetteStoreError, CassetteStoreOperation, CassetteStoreService, createEmptyCassette, createEmptyCassetteFile, make, parseCassette, toStoreError };
|
package/dist/cassette-store.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import "./types-DMuz_JGd.js";
|
|
2
|
-
import { a as createEmptyCassetteFile, c as toStoreError, i as createEmptyCassette, n as CassetteStoreError, o as make, s as parseCassette, t as CassetteStore } from "./cassette-store-BF9e0rz3.js";
|
|
3
|
-
|
|
4
|
-
export { CassetteStore, CassetteStoreError, createEmptyCassette, createEmptyCassetteFile, make, parseCassette, toStoreError };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { n as CassetteStoreError, t as CassetteStore } from "./cassette-store-BMtcjh5h.js";
|
|
2
|
-
import { FileSystem, Layer, Path } from "effect";
|
|
3
|
-
|
|
4
|
-
//#region src/file-system-cassette-store.d.ts
|
|
5
|
-
declare namespace file_system_cassette_store_d_exports {
|
|
6
|
-
export { FileSystemCassetteStoreConfig, layer };
|
|
7
|
-
}
|
|
8
|
-
type FileSystemCassetteStoreConfig = {
|
|
9
|
-
readonly cassetteDir?: string;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* FileSystem-backed cassette store.
|
|
13
|
-
*
|
|
14
|
-
* Requires a platform FileSystem layer (Node/Bun) to be provided by the user.
|
|
15
|
-
*/
|
|
16
|
-
declare const layer: (config?: FileSystemCassetteStoreConfig) => Layer.Layer<CassetteStore, CassetteStoreError, FileSystem.FileSystem | Path.Path>;
|
|
17
|
-
//#endregion
|
|
18
|
-
export { file_system_cassette_store_d_exports as n, layer as r, FileSystemCassetteStoreConfig as t };
|
|
19
|
-
//# sourceMappingURL=file-system-cassette-store-ClYAuH7U.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"file-system-cassette-store-CyOsu3z5.js","names":["CassetteStore.CassetteStore","rootDir: string","CassetteStore.toStoreError","CassetteStore.parseCassette","CassetteStore.createEmptyCassetteFile","CassetteStore.make"],"sources":["../src/file-system-cassette-store.ts"],"sourcesContent":["import { Effect, Layer, FileSystem, Path } from \"effect\";\n\nimport type { CassetteFile } from \"./types\";\n\nimport * as CassetteStore from \"./cassette-store\";\nimport { getVitestState } from \"./vitest-state\";\n\nexport type FileSystemCassetteStoreConfig = {\n readonly cassetteDir?: string;\n};\n\n/**\n * FileSystem-backed cassette store.\n *\n * Requires a platform FileSystem layer (Node/Bun) to be provided by the user.\n */\nexport const layer = (config: FileSystemCassetteStoreConfig = {}) =>\n Layer.effect(CassetteStore.CassetteStore)(\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n let rootDir: string;\n if (config.cassetteDir) {\n rootDir = config.cassetteDir;\n } else {\n const { testPath } = getVitestState();\n if (!testPath) {\n return yield* Effect.fail(\n CassetteStore.toStoreError(\n \"resolveRoot\",\n \"__cassettes__\",\n undefined,\n \"VCR cassette directory could not be inferred. Provide cassetteDir when not running in Vitest.\",\n ),\n );\n }\n const testFolder = path.dirname(testPath);\n rootDir = path.join(testFolder, \"__cassettes__\");\n }\n\n const fullPath = (name: string) => path.join(rootDir, name);\n\n const load = (name: string) =>\n fs.readFileString(fullPath(name)).pipe(\n Effect.mapError((error) => CassetteStore.toStoreError(\"load\", name, error)),\n Effect.flatMap((content) => CassetteStore.parseCassette(content, name)),\n );\n\n const save = (name: string, cassette: CassetteFile) => {\n const filePath = fullPath(name);\n const dir = path.dirname(filePath);\n const ensureDir =\n dir === \"\"\n ? Effect.void\n : fs\n .makeDirectory(dir, { recursive: true })\n .pipe(Effect.mapError((error) => CassetteStore.toStoreError(\"save\", dir, error)));\n return ensureDir.pipe(\n Effect.andThen(\n fs\n .writeFileString(filePath, JSON.stringify(cassette, null, 2))\n .pipe(Effect.mapError((error) => CassetteStore.toStoreError(\"save\", name, error))),\n ),\n );\n };\n\n const loadOrInit = (name: string) =>\n fs.exists(fullPath(name)).pipe(\n Effect.mapError((error) => CassetteStore.toStoreError(\"loadOrInit\", name, error)),\n Effect.flatMap((exists) =>\n exists\n ? load(name)\n : CassetteStore.createEmptyCassetteFile().pipe(\n Effect.tap((cassette) => save(name, cassette)),\n ),\n ),\n );\n\n return CassetteStore.make({\n exists: (name: string) =>\n fs\n .exists(fullPath(name))\n .pipe(Effect.mapError((error) => CassetteStore.toStoreError(\"exists\", name, error))),\n load,\n save,\n loadOrInit,\n });\n }),\n );\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAa,SAAS,SAAwC,EAAE,KAC9D,MAAM,OAAOA,cAA4B,CACvC,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,IAAIC;AACJ,KAAI,OAAO,YACT,WAAU,OAAO;MACZ;EACL,MAAM,EAAE,aAAa,gBAAgB;AACrC,MAAI,CAAC,SACH,QAAO,OAAO,OAAO,KACnBC,aACE,eACA,iBACA,QACA,gGACD,CACF;EAEH,MAAM,aAAa,KAAK,QAAQ,SAAS;AACzC,YAAU,KAAK,KAAK,YAAY,gBAAgB;;CAGlD,MAAM,YAAY,SAAiB,KAAK,KAAK,SAAS,KAAK;CAE3D,MAAM,QAAQ,SACZ,GAAG,eAAe,SAAS,KAAK,CAAC,CAAC,KAChC,OAAO,UAAU,UAAUA,aAA2B,QAAQ,MAAM,MAAM,CAAC,EAC3E,OAAO,SAAS,YAAYC,cAA4B,SAAS,KAAK,CAAC,CACxE;CAEH,MAAM,QAAQ,MAAc,aAA2B;EACrD,MAAM,WAAW,SAAS,KAAK;EAC/B,MAAM,MAAM,KAAK,QAAQ,SAAS;AAOlC,UALE,QAAQ,KACJ,OAAO,OACP,GACG,cAAc,KAAK,EAAE,WAAW,MAAM,CAAC,CACvC,KAAK,OAAO,UAAU,UAAUD,aAA2B,QAAQ,KAAK,MAAM,CAAC,CAAC,EACxE,KACf,OAAO,QACL,GACG,gBAAgB,UAAU,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC,CAC5D,KAAK,OAAO,UAAU,UAAUA,aAA2B,QAAQ,MAAM,MAAM,CAAC,CAAC,CACrF,CACF;;CAGH,MAAM,cAAc,SAClB,GAAG,OAAO,SAAS,KAAK,CAAC,CAAC,KACxB,OAAO,UAAU,UAAUA,aAA2B,cAAc,MAAM,MAAM,CAAC,EACjF,OAAO,SAAS,WACd,SACI,KAAK,KAAK,GACVE,yBAAuC,CAAC,KACtC,OAAO,KAAK,aAAa,KAAK,MAAM,SAAS,CAAC,CAC/C,CACN,CACF;AAEH,QAAOC,KAAmB;EACxB,SAAS,SACP,GACG,OAAO,SAAS,KAAK,CAAC,CACtB,KAAK,OAAO,UAAU,UAAUH,aAA2B,UAAU,MAAM,MAAM,CAAC,CAAC;EACxF;EACA;EACA;EACD,CAAC;EACF,CACH"}
|
package/dist/index.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { a as VcrResponseSchema, i as VcrRequestSchema, n as CassetteSchema, r as VcrEntrySchema, t as CassetteFileSchema } from "./types-DMuz_JGd.js";
|
|
2
|
-
import { r as cassette_store_exports } from "./cassette-store-BF9e0rz3.js";
|
|
3
|
-
import "./vitest-state-CiW5dzXZ.js";
|
|
4
|
-
import { t as file_system_cassette_store_exports } from "./file-system-cassette-store-CyOsu3z5.js";
|
|
5
|
-
import { r as vcr_http_client_exports } from "./vcr-http-client-Ba0WYPV9.js";
|
|
6
|
-
|
|
7
|
-
export { CassetteFileSchema, CassetteSchema, cassette_store_exports as CassetteStore, file_system_cassette_store_exports as FileSystemCassetteStore, VcrEntrySchema, vcr_http_client_exports as VcrHttpClient, VcrRequestSchema, VcrResponseSchema };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-DMuz_JGd.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\n/**\n * VCR operating mode.\n * - record: always call the live client and persist.\n * - replay: serve only from cassette, fail if missing.\n * - auto: replay if cassette exists, otherwise record (fail in CI).\n */\nexport type VcrMode = \"record\" | \"replay\" | \"auto\";\n\n/**\n * Safe scalar value written in place of a sensitive body field.\n */\nexport type VcrRedactedValue = string | number | boolean | null;\n\n/**\n * Serialized request shape stored in a cassette.\n */\nexport const VcrRequestSchema = Schema.Struct({\n method: Schema.String,\n url: Schema.String,\n headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),\n body: Schema.optional(Schema.String),\n});\nexport type VcrRequest = Schema.Schema.Type<typeof VcrRequestSchema>;\n\n/**\n * Serialized response shape stored in a cassette.\n */\nexport const VcrResponseSchema = Schema.Struct({\n status: Schema.Number,\n body: Schema.String,\n headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),\n});\nexport type VcrResponse = Schema.Schema.Type<typeof VcrResponseSchema>;\n\n/**\n * A single request/response pair keyed in the cassette.\n */\nexport const VcrEntrySchema = Schema.Struct({\n request: VcrRequestSchema,\n response: VcrResponseSchema,\n});\nexport type VcrEntry = Schema.Schema.Type<typeof VcrEntrySchema>;\n\n/**\n * Cassette file format.\n */\nexport const CassetteSchema = Schema.Struct({\n meta: Schema.Struct({\n createdAt: Schema.String,\n version: Schema.String,\n }),\n entries: Schema.Record(Schema.String, VcrEntrySchema),\n});\nexport type Cassette = Schema.Schema.Type<typeof CassetteSchema>;\n\n/**\n * Cassette file format with multiple exports.\n */\nexport const CassetteFileSchema = Schema.Struct({\n exports: Schema.Record(Schema.String, CassetteSchema),\n});\nexport type CassetteFile = Schema.Schema.Type<typeof CassetteFileSchema>;\n\n/**\n * VCR configuration.\n */\nexport type VcrConfig = {\n readonly vcrName?: string;\n /**\n * Cassette file name or basename.\n *\n * `users` resolves to `users.cassette`.\n * `users.cassette` is preserved as-is.\n */\n readonly cassetteName?: string;\n readonly mode?: VcrMode;\n /**\n * Remove or replace sensitive data before writing to disk.\n */\n readonly redact?: {\n readonly requestHeaders?: ReadonlyArray<string>;\n readonly responseHeaders?: ReadonlyArray<string>;\n readonly requestBodyKeys?: ReadonlyArray<string>;\n readonly responseBodyKeys?: ReadonlyArray<string>;\n readonly requestBodyReplacements?: Readonly<Record<string, VcrRedactedValue>>;\n readonly responseBodyReplacements?: Readonly<Record<string, VcrRedactedValue>>;\n };\n /**\n * Ignore fields when computing the request key for replay matching.\n */\n readonly matchIgnore?: {\n readonly requestHeaders?: ReadonlyArray<string>;\n readonly requestBodyKeys?: ReadonlyArray<string>;\n };\n /**\n * Custom matcher to override key-based lookup.\n */\n readonly match?: (request: VcrRequest, entry: VcrEntry) => boolean;\n};\n"],"mappings":";;;;;;AAkBA,MAAa,mBAAmB,OAAO,OAAO;CAC5C,QAAQ,OAAO;CACf,KAAK,OAAO;CACZ,SAAS,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;CACrE,MAAM,OAAO,SAAS,OAAO,OAAO;CACrC,CAAC;;;;AAMF,MAAa,oBAAoB,OAAO,OAAO;CAC7C,QAAQ,OAAO;CACf,MAAM,OAAO;CACb,SAAS,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;CACtE,CAAC;;;;AAMF,MAAa,iBAAiB,OAAO,OAAO;CAC1C,SAAS;CACT,UAAU;CACX,CAAC;;;;AAMF,MAAa,iBAAiB,OAAO,OAAO;CAC1C,MAAM,OAAO,OAAO;EAClB,WAAW,OAAO;EAClB,SAAS,OAAO;EACjB,CAAC;CACF,SAAS,OAAO,OAAO,OAAO,QAAQ,eAAe;CACtD,CAAC;;;;AAMF,MAAa,qBAAqB,OAAO,OAAO,EAC9C,SAAS,OAAO,OAAO,OAAO,QAAQ,eAAe,EACtD,CAAC"}
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vcr-http-client-Ba0WYPV9.js","names":["record","next: Record<string, unknown>","Arr","headers: Record<string, string>","next: Cassette"],"sources":["../src/sanitize.ts","../src/vcr-http-client.ts"],"sourcesContent":["import { Effect, Option, Record } from \"effect\";\nimport { UrlParams } from \"effect/unstable/http\";\nimport stableStringify from \"json-stable-stringify\";\n\nimport type { VcrRedactedValue, VcrRequest, VcrResponse } from \"./types\";\n\n/**\n * Normalize header names to match HttpClient's lowercase behavior.\n */\nconst normalizeHeaderKey = (key: string) => key.toLowerCase();\n\n/**\n * Canonicalize headers: lowercase keys and stable ordering.\n */\nconst toHeaderRecord = (headers?: Record<string, string>) => {\n if (!headers) return undefined;\n const lowered = Record.mapKeys(headers, normalizeHeaderKey);\n return Record.fromEntries(Record.toEntries(lowered).sort(([a], [b]) => a.localeCompare(b)));\n};\n\n/**\n * Remove specified header names (case-insensitive).\n */\nconst omitHeaderKeys = (\n headers: Record<string, string> | undefined,\n ignore: ReadonlyArray<string> | undefined,\n): Option.Option<Record<string, string>> => {\n if (!headers) return Option.none();\n if (!ignore || ignore.length === 0) return Option.some(headers);\n const ignoreSet = new Set(ignore.map(normalizeHeaderKey));\n return Option.some(Record.filter(headers, (_, key) => !ignoreSet.has(normalizeHeaderKey(key))));\n};\n\n/**\n * Best-effort JSON parse; returns undefined for non-JSON bodies.\n */\nconst tryParseJson = Option.liftThrowable((input: string) => JSON.parse(input));\n\ntype BodyOptions = {\n readonly omit?: ReadonlyArray<string>;\n readonly replacements?: Readonly<Record<string, VcrRedactedValue>>;\n};\n\ntype BodyTransformation<A> = {\n readonly value: A;\n readonly redacted: boolean;\n};\n\n/**\n * Recursively remove or replace keys in JSON values.\n */\nconst transformJsonKeys = (\n value: unknown,\n omit: ReadonlySet<string>,\n replacements: Readonly<Record<string, VcrRedactedValue>>,\n): BodyTransformation<unknown> => {\n if (Array.isArray(value)) {\n let redacted = false;\n const values = value.map((item) => {\n const transformed = transformJsonKeys(item, omit, replacements);\n redacted ||= transformed.redacted;\n return transformed.value;\n });\n return { value: values, redacted };\n }\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const next: Record<string, unknown> = {};\n let redacted = false;\n for (const [key, entry] of Object.entries(record)) {\n if (omit.has(key)) {\n redacted = true;\n continue;\n }\n if (Record.has(replacements, key)) {\n next[key] = replacements[key];\n redacted = true;\n continue;\n }\n const transformed = transformJsonKeys(entry, omit, replacements);\n next[key] = transformed.value;\n redacted ||= transformed.redacted;\n }\n return { value: next, redacted };\n }\n return { value, redacted: false };\n};\n\nconst headerValue = (\n headers: Readonly<Record<string, string>> | undefined,\n name: string,\n): string | undefined => {\n if (!headers) return undefined;\n const normalizedName = normalizeHeaderKey(name);\n return Object.entries(headers).find(([key]) => normalizeHeaderKey(key) === normalizedName)?.[1];\n};\n\nconst isUrlEncoded = (headers: Readonly<Record<string, string>> | undefined): boolean =>\n headerValue(headers, \"content-type\")?.split(\";\", 1)[0]?.trim().toLowerCase() ===\n \"application/x-www-form-urlencoded\";\n\nconst transformUrlParams = (\n body: string,\n omit: ReadonlySet<string>,\n replacements: Readonly<Record<string, VcrRedactedValue>>,\n): BodyTransformation<string> => {\n let redacted = false;\n const value = UrlParams.fromInput(new URLSearchParams(body)).pipe(\n UrlParams.transform((params) =>\n params.flatMap(([key, value]) => {\n if (omit.has(key)) {\n redacted = true;\n return [];\n }\n if (Record.has(replacements, key)) {\n redacted = true;\n return [[key, String(replacements[key])] as const];\n }\n return [[key, value] as const];\n }),\n ),\n UrlParams.toString,\n );\n return { value, redacted };\n};\n\n/**\n * Remove or replace JSON and URL-encoded body fields when possible.\n */\nconst transformBody = (\n body: string | undefined,\n headers: Readonly<Record<string, string>> | undefined,\n options: BodyOptions,\n): Option.Option<BodyTransformation<string>> => {\n if (!body) return Option.none();\n const omit = new Set(options.omit);\n const replacements = options.replacements ?? {};\n if (isUrlEncoded(headers)) {\n const hasMatch = Array.from(new URLSearchParams(body).keys()).some(\n (key) => omit.has(key) || Record.has(replacements, key),\n );\n if (!hasMatch) {\n return Option.some({ value: body, redacted: false });\n }\n return Option.some(transformUrlParams(body, omit, replacements));\n }\n return Option.some(\n tryParseJson(body).pipe(\n Option.match({\n onNone: () => ({ value: body, redacted: false }),\n onSome: (parsed) => {\n const transformed = transformJsonKeys(parsed, omit, replacements);\n return {\n // stableStringify's return type is `string | undefined` for cyclic input;\n // parsed JSON is never cyclic, but the fallback keeps the types honest.\n value: stableStringify(transformed.value) ?? body,\n redacted: transformed.redacted,\n };\n },\n }),\n ),\n );\n};\n\n/**\n * Normalize request for matching: header canonicalization and structured body filtering.\n */\nexport const sanitizeRequest = (\n request: VcrRequest,\n options: {\n readonly ignoreHeaders?: ReadonlyArray<string>;\n readonly ignoreBodyKeys?: ReadonlyArray<string>;\n },\n): VcrRequest => {\n const transformedBody = transformBody(request.body, request.headers, {\n omit: options.ignoreBodyKeys,\n });\n const body = Option.getOrUndefined(\n transformedBody.pipe(Option.map((transformed) => transformed.value)),\n );\n const filteredHeaders = omitHeaderKeys(\n request.headers,\n transformedBody.pipe(Option.exists((transformed) => transformed.redacted))\n ? [...(options.ignoreHeaders ?? []), \"content-length\"]\n : options.ignoreHeaders,\n );\n return {\n ...request,\n headers: toHeaderRecord(Option.getOrUndefined(filteredHeaders)),\n body,\n };\n};\n\n/**\n * Compute the stable request key used for cassette lookups.\n */\nexport const buildRequestKey = (\n request: VcrRequest,\n options: {\n readonly ignoreHeaders?: ReadonlyArray<string>;\n readonly ignoreBodyKeys?: ReadonlyArray<string>;\n },\n): Effect.Effect<string> =>\n Effect.sync(() => {\n const sanitized = sanitizeRequest(request, {\n ignoreHeaders: options.ignoreHeaders,\n ignoreBodyKeys: options.ignoreBodyKeys,\n });\n // stableStringify only returns undefined for cyclic input; this literal never is,\n // but its declared type is `string | undefined`, so keep the fallback for TS.\n return (\n stableStringify({\n method: sanitized.method.toUpperCase(),\n url: sanitized.url,\n headers: sanitized.headers ?? {},\n body: sanitized.body ?? \"\",\n }) ??\n JSON.stringify({\n method: sanitized.method.toUpperCase(),\n url: sanitized.url,\n headers: sanitized.headers ?? {},\n body: sanitized.body ?? \"\",\n })\n );\n });\n\n/**\n * Remove sensitive request data before persisting to a cassette.\n */\nexport const redactRequest = (\n request: VcrRequest,\n options: {\n readonly redactHeaders?: ReadonlyArray<string>;\n readonly redactBodyKeys?: ReadonlyArray<string>;\n readonly bodyReplacements?: Readonly<Record<string, VcrRedactedValue>>;\n },\n): VcrRequest => {\n const transformedBody = transformBody(request.body, request.headers, {\n omit: options.redactBodyKeys,\n replacements: options.bodyReplacements,\n });\n const body = Option.getOrUndefined(\n transformedBody.pipe(Option.map((transformed) => transformed.value)),\n );\n return {\n ...request,\n headers: Option.getOrUndefined(\n omitHeaderKeys(\n request.headers,\n transformedBody.pipe(Option.exists((transformed) => transformed.redacted))\n ? [...(options.redactHeaders ?? []), \"content-length\"]\n : options.redactHeaders,\n ),\n ),\n body,\n };\n};\n\n/**\n * Remove sensitive response data before persisting to a cassette.\n */\nexport const redactResponse = (\n response: VcrResponse,\n options: {\n readonly redactHeaders?: ReadonlyArray<string>;\n readonly redactBodyKeys?: ReadonlyArray<string>;\n readonly bodyReplacements?: Readonly<Record<string, VcrRedactedValue>>;\n },\n): VcrResponse => {\n const transformedBody = transformBody(response.body, response.headers, {\n omit: options.redactBodyKeys,\n replacements: options.bodyReplacements,\n });\n const body = Option.getOrElse(\n transformedBody.pipe(Option.map((transformed) => transformed.value)),\n () => response.body,\n );\n return {\n ...response,\n headers: Option.getOrUndefined(\n omitHeaderKeys(\n response.headers,\n transformedBody.pipe(Option.exists((transformed) => transformed.redacted))\n ? [...(options.redactHeaders ?? []), \"content-length\"]\n : options.redactHeaders,\n ),\n ),\n body,\n };\n};\n","import { Array as Arr, Config, Data, Effect, Option, Path } from \"effect\";\nimport {\n HttpClient,\n HttpClientError,\n type HttpClientRequest,\n HttpClientResponse,\n} from \"effect/unstable/http\";\n\nimport type { Cassette, CassetteFile, VcrConfig, VcrEntry, VcrRequest, VcrResponse } from \"./types\";\n\nimport { CassetteStore, type CassetteStoreService, createEmptyCassette } from \"./cassette-store\";\nimport { buildRequestKey, redactRequest, redactResponse } from \"./sanitize\";\nimport { getVitestState } from \"./vitest-state\";\n\n/**\n * Decoder for Uint8Array request bodies when building cassette keys.\n */\nconst decoder = new TextDecoder();\n\nexport class VcrHttpClientError extends Data.TaggedError(\"VcrHttpClientError\")<{\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n\nconst toCassetteFileName = (name: string): string =>\n name.endsWith(\".cassette\") ? name : `${name}.cassette`;\n\n/**\n * Resolve the cassette file name and export key.\n *\n * If explicit cassetteName are provided, use them and default to\n * the \"default\" export. Otherwise infer from Vitest state:\n * - <file-name>.cassette file name\n * - export key = current test name (describe > test)\n */\nconst resolveCassetteLocation = Effect.fnUntraced(function* (config: VcrConfig) {\n const path = yield* Path.Path;\n if (config.cassetteName) {\n return {\n name: toCassetteFileName(config.cassetteName),\n exportKey: \"default\",\n };\n }\n\n const { testPath, currentTestName } = getVitestState();\n if (!testPath || !currentTestName) {\n return yield* Effect.fail(\n new VcrHttpClientError({\n message:\n \"VCR cassette path could not be inferred. Provide cassetteName when not running in Vitest.\",\n }),\n );\n }\n\n const fileName = path.basename(testPath, \".ts\");\n const cassetteName = `${fileName}.cassette`;\n\n return {\n name: cassetteName,\n exportKey: currentTestName,\n };\n});\n\n/**\n * Apply defaults for common VCR behavior while preserving explicit overrides.\n */\nconst normalizeConfig = (config: VcrConfig): VcrConfig => {\n const redactedRequestBodyKeys = Arr.union(\n config.redact?.requestBodyKeys ?? [],\n Object.keys(config.redact?.requestBodyReplacements ?? {}),\n );\n const redactedRequestHeaders = Arr.union([\"authorization\"], config.redact?.requestHeaders ?? []);\n\n return {\n vcrName: config.vcrName,\n cassetteName: config.cassetteName,\n mode: config.mode ?? \"auto\",\n matchIgnore: {\n requestHeaders: Arr.union(redactedRequestHeaders, config.matchIgnore?.requestHeaders ?? []),\n requestBodyKeys: Arr.union(\n redactedRequestBodyKeys,\n config.matchIgnore?.requestBodyKeys ?? [],\n ),\n },\n redact: {\n ...config.redact,\n requestHeaders: redactedRequestHeaders,\n },\n match: config.match,\n };\n};\n\nconst AckDisableVcrConfig = Config.option(Config.string(\"ACK_DISABLE_VCR\")).pipe(\n Config.map((value) =>\n Option.match(value, {\n onNone: () => new Set<string>(),\n onSome: (raw) =>\n raw === \"*\"\n ? \"*\"\n : new Set(\n raw\n .split(\",\")\n .map((segment) => segment.trim().toLowerCase())\n .filter((segment) => segment.length > 0),\n ),\n }),\n ),\n);\n\nconst shouldDisableVcr = (name: string | undefined, disabled: \"*\" | Set<string>): boolean => {\n if (disabled === \"*\") return true;\n if (!name) return false;\n const normalized = name.trim().toLowerCase();\n return disabled.has(normalized);\n};\n\n/**\n * Convert store or replay failures into HttpClient transport errors.\n */\nconst toRequestError = (\n request: HttpClientRequest.HttpClientRequest,\n cause: unknown,\n description?: string,\n) =>\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n cause,\n description,\n }),\n });\n\n/**\n * Best-effort JSON serialization for opaque raw bodies.\n */\nconst tryStringify = Option.liftThrowable((value: unknown) => JSON.stringify(value));\n\n/**\n * Serialize an Effect HttpClientRequest into a cassette request shape.\n *\n * Note: some body variants (Stream, FormData) are not safely serializable\n * without consuming the body, so we store placeholders to avoid breaking\n * live requests.\n */\nconst toVcrRequest = (request: HttpClientRequest.HttpClientRequest): VcrRequest => {\n const headers: Record<string, string> = { ...request.headers };\n const body = (() => {\n switch (request.body._tag) {\n case \"Empty\":\n return \"\";\n case \"Uint8Array\":\n return decoder.decode(request.body.body);\n case \"Raw\": {\n const raw = request.body.body as unknown;\n if (typeof raw === \"string\") return raw;\n if (raw instanceof Uint8Array) return decoder.decode(raw);\n return tryStringify(raw).pipe(Option.getOrElse(() => \"[raw]\"));\n }\n case \"FormData\":\n return \"[form-data]\";\n case \"Stream\":\n return \"[stream]\";\n }\n })();\n\n return {\n method: request.method,\n url: request.url,\n headers,\n body,\n };\n};\n\n/**\n * Serialize an Effect HttpClientResponse into a cassette response shape.\n */\nconst toVcrResponse = (\n response: HttpClientResponse.HttpClientResponse,\n body: string,\n): VcrResponse => ({\n status: response.status,\n body,\n headers: { ...response.headers },\n});\n\n/**\n * Load a cassette and map store errors into HttpClient errors.\n */\nconst readCassetteFile = (\n store: CassetteStoreService,\n name: string,\n request: HttpClientRequest.HttpClientRequest,\n) => store.load(name).pipe(Effect.mapError((error) => toRequestError(request, error)));\n\n/**\n * Load a cassette or initialize a new one if missing.\n */\nconst loadOrInitCassetteFile = (\n store: CassetteStoreService,\n name: string,\n request: HttpClientRequest.HttpClientRequest,\n) => store.loadOrInit(name).pipe(Effect.mapError((error) => toRequestError(request, error)));\n\n/**\n * Persist the updated cassette.\n */\nconst saveCassetteFile = (\n store: CassetteStoreService,\n name: string,\n cassette: CassetteFile,\n request: HttpClientRequest.HttpClientRequest,\n) => store.save(name, cassette).pipe(Effect.mapError((error) => toRequestError(request, error)));\n\n/**\n * Load a named cassette export from the file, or return a fresh empty cassette.\n */\nconst readCassetteExport = (\n store: CassetteStoreService,\n name: string,\n exportKey: string,\n request: HttpClientRequest.HttpClientRequest,\n) =>\n readCassetteFile(store, name, request).pipe(\n Effect.flatMap((file) => {\n const found = file.exports[exportKey];\n if (found) return Effect.succeed(found);\n return createEmptyCassette();\n }),\n );\n\n/**\n * Locate a cassette entry by custom matcher or stable request key.\n */\nconst findEntry = (\n request: VcrRequest,\n cassette: Cassette,\n config: VcrConfig,\n): Effect.Effect<VcrEntry | undefined> => {\n if (config.match) {\n return Effect.succeed(\n Object.values(cassette.entries).find((entry) => config.match?.(request, entry)),\n );\n }\n return buildRequestKey(request, {\n ignoreHeaders: config.matchIgnore?.requestHeaders,\n ignoreBodyKeys: config.matchIgnore?.requestBodyKeys,\n }).pipe(Effect.map((key) => cassette.entries[key]));\n};\n\nconst replayResponse = (\n request: HttpClientRequest.HttpClientRequest,\n entry: VcrEntry,\n): HttpClientResponse.HttpClientResponse => {\n const web = new Response(entry.response.body, {\n status: entry.response.status,\n headers: entry.response.headers,\n });\n return HttpClientResponse.fromWeb(request, web);\n};\n\n/**\n * Replay a response from cassette data using HttpClientResponse.fromWeb.\n */\nconst replay = (\n store: CassetteStoreService,\n request: HttpClientRequest.HttpClientRequest,\n vcrRequest: VcrRequest,\n config: VcrConfig,\n name: string,\n exportKey: string,\n) =>\n readCassetteExport(store, name, exportKey, request).pipe(\n Effect.flatMap((cassette) =>\n findEntry(vcrRequest, cassette, config).pipe(\n Effect.flatMap((entry) => {\n if (!entry) {\n return Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n description: `VCR replay missing entry for ${request.method} ${request.url}`,\n }),\n }),\n );\n }\n\n return Effect.succeed(replayResponse(request, entry));\n }),\n ),\n ),\n );\n\n/**\n * Record a live response into the cassette and return the original response.\n */\nconst record = Effect.fnUntraced(function* (\n store: CassetteStoreService,\n request: HttpClientRequest.HttpClientRequest,\n vcrRequest: VcrRequest,\n effect: Effect.Effect<HttpClientResponse.HttpClientResponse, HttpClientError.HttpClientError>,\n config: VcrConfig,\n name: string,\n exportKey: string,\n): Effect.fn.Return<HttpClientResponse.HttpClientResponse, HttpClientError.HttpClientError> {\n const response = yield* effect;\n const body = yield* response.text;\n const vcrResponse = toVcrResponse(response, body);\n\n const sanitizedRequest = config.redact\n ? redactRequest(vcrRequest, {\n redactHeaders: config.redact.requestHeaders,\n redactBodyKeys: config.redact.requestBodyKeys,\n bodyReplacements: config.redact.requestBodyReplacements,\n })\n : vcrRequest;\n const sanitizedResponse = config.redact\n ? redactResponse(vcrResponse, {\n redactHeaders: config.redact.responseHeaders,\n redactBodyKeys: config.redact.responseBodyKeys,\n bodyReplacements: config.redact.responseBodyReplacements,\n })\n : vcrResponse;\n\n const file = yield* loadOrInitCassetteFile(store, name, request);\n const cassette = file.exports[exportKey] ?? (yield* createEmptyCassette());\n const key = yield* buildRequestKey(vcrRequest, {\n ignoreHeaders: config.matchIgnore?.requestHeaders,\n ignoreBodyKeys: config.matchIgnore?.requestBodyKeys,\n });\n const next: Cassette = {\n ...cassette,\n entries: {\n ...cassette.entries,\n [key]: {\n request: sanitizedRequest,\n response: sanitizedResponse,\n },\n },\n };\n const nextFile: CassetteFile = {\n ...file,\n exports: {\n ...file.exports,\n [exportKey]: next,\n },\n };\n yield* saveCassetteFile(store, name, nextFile, request);\n return response;\n});\n\n/**\n * Build a VCR-aware HttpClient that replays or records per config.\n */\nconst makeVcrHttpClient = Effect.fnUntraced(function* (config: VcrConfig = {}) {\n const live = yield* HttpClient.HttpClient;\n const normalized = normalizeConfig(config);\n\n const isCi = yield* Config.boolean(\"CI\").pipe(Config.withDefault(false));\n\n const disabledVcrs = yield* AckDisableVcrConfig;\n if (shouldDisableVcr(normalized.vcrName, disabledVcrs)) {\n return live;\n }\n\n const store = yield* CassetteStore;\n\n const { name, exportKey } = yield* resolveCassetteLocation(normalized);\n\n return live.pipe(\n HttpClient.transform(\n Effect.fnUntraced(function* (effect, request) {\n const vcrRequest = toVcrRequest(request);\n if (normalized.mode === \"replay\") {\n return yield* replay(store, request, vcrRequest, normalized, name, exportKey);\n }\n\n if (normalized.mode === \"record\") {\n return yield* record(store, request, vcrRequest, effect, normalized, name, exportKey);\n }\n\n const available = yield* store\n .exists(name)\n .pipe(Effect.mapError((error) => toRequestError(request, error)));\n\n if (!available) {\n if (isCi) {\n return yield* Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n description: \"VCR cassette missing in CI for auto mode\",\n }),\n }),\n );\n }\n\n return yield* record(store, request, vcrRequest, effect, normalized, name, exportKey);\n }\n\n const cassette = yield* readCassetteExport(store, name, exportKey, request);\n const entry = yield* findEntry(vcrRequest, cassette, normalized);\n\n if (entry) {\n return replayResponse(request, entry);\n }\n\n return yield* record(store, request, vcrRequest, effect, normalized, name, exportKey);\n }),\n ),\n );\n});\n\n/**\n * Layer that provides a VCR-wrapped HttpClient.\n */\nexport const layer = (config: VcrConfig = {}) =>\n HttpClient.layerMergedContext(makeVcrHttpClient(config));\n"],"mappings":"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"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { a as VcrConfig } from "./types-XZehMu_v.js";
|
|
2
|
-
import { t as CassetteStore } from "./cassette-store-BMtcjh5h.js";
|
|
3
|
-
import { Config, Path } from "effect";
|
|
4
|
-
import { HttpClient } from "effect/unstable/http";
|
|
5
|
-
import * as effect_Types0 from "effect/Types";
|
|
6
|
-
import * as effect_Cause0 from "effect/Cause";
|
|
7
|
-
import * as effect_Layer0 from "effect/Layer";
|
|
8
|
-
|
|
9
|
-
//#region src/vcr-http-client.d.ts
|
|
10
|
-
declare namespace vcr_http_client_d_exports {
|
|
11
|
-
export { VcrHttpClientError, layer };
|
|
12
|
-
}
|
|
13
|
-
declare const VcrHttpClientError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => effect_Cause0.YieldableError & {
|
|
14
|
-
readonly _tag: "VcrHttpClientError";
|
|
15
|
-
} & Readonly<A>;
|
|
16
|
-
declare class VcrHttpClientError extends VcrHttpClientError_base<{
|
|
17
|
-
readonly message: string;
|
|
18
|
-
readonly cause?: unknown;
|
|
19
|
-
}> {}
|
|
20
|
-
/**
|
|
21
|
-
* Layer that provides a VCR-wrapped HttpClient.
|
|
22
|
-
*/
|
|
23
|
-
declare const layer: (config?: VcrConfig) => effect_Layer0.Layer<HttpClient.HttpClient, VcrHttpClientError | Config.ConfigError, CassetteStore | Path.Path | HttpClient.HttpClient>;
|
|
24
|
-
//#endregion
|
|
25
|
-
export { layer as n, vcr_http_client_d_exports as r, VcrHttpClientError as t };
|
|
26
|
-
//# sourceMappingURL=vcr-http-client-BveeoOoW.d.ts.map
|
package/dist/vcr-http-client.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vitest-state-CiW5dzXZ.js","names":[],"sources":["../src/vitest-state.ts"],"sourcesContent":["export type VitestState = {\n readonly testPath?: string;\n readonly currentTestName?: string;\n};\n\nexport const getVitestState = (): VitestState => {\n const expectGlobal =\n // biome-ignore lint/suspicious/noExplicitAny: --\n (globalThis as { expect?: { getState?: () => any } }).expect;\n const symbolExpect =\n // biome-ignore lint/suspicious/noExplicitAny: --\n (globalThis as { [key: symbol]: { getState?: () => any } })[Symbol.for(\"expect-global\")];\n const state = expectGlobal?.getState?.() ?? symbolExpect?.getState?.();\n return {\n testPath: state?.testPath as string | undefined,\n currentTestName: state?.currentTestName as string | undefined,\n };\n};\n"],"mappings":";AAKA,MAAa,uBAAoC;CAC/C,MAAM,eAEH,WAAqD;CACxD,MAAM,eAEH,WAA2D,OAAO,IAAI,gBAAgB;CACzF,MAAM,QAAQ,cAAc,YAAY,IAAI,cAAc,YAAY;AACtE,QAAO;EACL,UAAU,OAAO;EACjB,iBAAiB,OAAO;EACzB"}
|