(
name: string,
options: Omit<RecordReplayOptions, "directory"> = {},
)
| 91 | }) |
| 92 | |
| 93 | export const recordingLayer = ( |
| 94 | name: string, |
| 95 | options: Omit<RecordReplayOptions, "directory"> = {}, |
| 96 | ): Layer.Layer<HttpClient.HttpClient, never, HttpClient.HttpClient | CassetteService.Service> => |
| 97 | Layer.effect( |
| 98 | HttpClient.HttpClient, |
| 99 | Effect.gen(function* () { |
| 100 | const upstream = yield* HttpClient.HttpClient |
| 101 | const cassetteService = yield* CassetteService.Service |
| 102 | const redactor = options.redactor ?? make() |
| 103 | const match = options.match ?? defaultMatcher |
| 104 | const requested = options.mode ?? "auto" |
| 105 | const mode = requested === "auto" ? yield* resolveAutoMode(cassetteService, name) : requested |
| 106 | |
| 107 | const snapshotRequest = (request: HttpClientRequest.HttpClientRequest) => |
| 108 | Effect.gen(function* () { |
| 109 | const web = yield* HttpClientRequest.toWeb(request).pipe(Effect.orDie) |
| 110 | return redactor.request({ |
| 111 | method: web.method, |
| 112 | url: web.url, |
| 113 | headers: Object.fromEntries(web.headers.entries()), |
| 114 | body: yield* Effect.promise(() => web.text()), |
| 115 | }) |
| 116 | }) |
| 117 | |
| 118 | if (mode === "passthrough") return upstream |
| 119 | |
| 120 | if (mode === "record") { |
| 121 | const initial = yield* Deferred.make<void>() |
| 122 | yield* Deferred.succeed(initial, undefined) |
| 123 | const tail = yield* Ref.make(initial) |
| 124 | return HttpClient.make((request) => |
| 125 | Effect.gen(function* () { |
| 126 | const completed = yield* Deferred.make<void>() |
| 127 | const previous = yield* Ref.modify(tail, (current) => [current, completed]) |
| 128 | return yield* Effect.gen(function* () { |
| 129 | const incoming = yield* snapshotRequest(request) |
| 130 | const response = yield* upstream.execute(request) |
| 131 | const captured = yield* captureResponseBody(response, response.headers["content-type"]) |
| 132 | const responseSnapshot: ResponseSnapshot = { |
| 133 | status: response.status, |
| 134 | headers: response.headers as Record<string, string>, |
| 135 | ...captured, |
| 136 | } |
| 137 | const interaction: HttpInteraction = { |
| 138 | transport: "http", |
| 139 | request: incoming, |
| 140 | response: redactor.response(responseSnapshot), |
| 141 | } |
| 142 | yield* Deferred.await(previous) |
| 143 | yield* cassetteService |
| 144 | .append(name, interaction, options.metadata) |
| 145 | .pipe( |
| 146 | Effect.catchTag("UnsafeCassetteError", (error) => |
| 147 | Effect.fail(transportError(request, error.message)), |
| 148 | ), |
| 149 | ) |
| 150 | return responseFromSnapshot(request, responseSnapshot) |
no test coverage detected