@replayio-app-building/netlify-recorder 0.1.0 → 0.2.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.
- package/README.md +161 -42
- package/dist/index.d.ts +15 -1
- package/dist/index.js +43 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,136 @@
|
|
|
1
|
-
# @netlify-recorder
|
|
1
|
+
# @replayio-app-building/netlify-recorder
|
|
2
2
|
|
|
3
3
|
Capture and replay Netlify function executions as [Replay](https://replay.io) recordings. This package intercepts outbound network calls and environment variable reads during handler execution, stores the captured data as a blob, and can later reproduce the exact execution as a Replay recording for debugging and analysis.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @netlify-recorder
|
|
8
|
+
npm install @replayio-app-building/netlify-recorder
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Integration Options
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
There are two ways to use this package:
|
|
14
|
+
|
|
15
|
+
- **Option A: Use the Netlify Recorder service (recommended)** — The service handles blob storage, request tracking, and recording creation. Your app just wraps its handlers and calls `remoteCallbacks()`. No database or container infrastructure needed.
|
|
16
|
+
|
|
17
|
+
- **Option B: Self-hosted** — You manage your own blob storage, database tables, and recording containers. Full control, but requires more setup.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Option A: Using the Netlify Recorder Service
|
|
22
|
+
|
|
23
|
+
The Netlify Recorder app (`https://netlify-recorder-bm4wmw.netlify.app`) provides a hosted service that stores captured request data, manages a pool of recording containers, and creates Replay recordings on demand. Your app needs zero database or infrastructure setup.
|
|
24
|
+
|
|
25
|
+
### 1. Wrap your Netlify function
|
|
26
|
+
|
|
27
|
+
Use `startRequest` / `finishRequest` with `remoteCallbacks()` to capture request data and send it to the service:
|
|
14
28
|
|
|
15
29
|
```typescript
|
|
16
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
startRequest,
|
|
32
|
+
finishRequest,
|
|
33
|
+
remoteCallbacks,
|
|
34
|
+
} from "@replayio-app-building/netlify-recorder";
|
|
35
|
+
import type { Handler } from "@netlify/functions";
|
|
36
|
+
|
|
37
|
+
const RECORDER_URL = "https://netlify-recorder-bm4wmw.netlify.app";
|
|
38
|
+
|
|
39
|
+
const handler: Handler = async (event) => {
|
|
40
|
+
const reqContext = startRequest({
|
|
41
|
+
method: event.httpMethod,
|
|
42
|
+
url: event.path,
|
|
43
|
+
headers: event.headers as Record<string, string>,
|
|
44
|
+
body: event.body ?? undefined,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const result = await myBusinessLogic();
|
|
49
|
+
|
|
50
|
+
return await finishRequest(
|
|
51
|
+
reqContext,
|
|
52
|
+
remoteCallbacks(RECORDER_URL),
|
|
53
|
+
{
|
|
54
|
+
statusCode: 200,
|
|
55
|
+
headers: { "Content-Type": "application/json" },
|
|
56
|
+
body: JSON.stringify(result),
|
|
57
|
+
},
|
|
58
|
+
{ handlerPath: "netlify/functions/my-handler" }
|
|
59
|
+
);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
reqContext.cleanup();
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export { handler };
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That's it for capturing. The `remoteCallbacks(url)` helper sends the captured blob data to the Netlify Recorder service, which uploads it to blob storage and stores the request metadata. The response includes an `X-Replay-Request-Id` header with the request ID managed by the service.
|
|
70
|
+
|
|
71
|
+
### 2. Create recordings
|
|
72
|
+
|
|
73
|
+
When you want to turn a captured request into a Replay recording, POST to the service's `create-recording` endpoint with the request ID:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const response = await fetch(
|
|
77
|
+
`${RECORDER_URL}/.netlify/functions/create-recording`,
|
|
78
|
+
{
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: { "Content-Type": "application/json" },
|
|
81
|
+
body: JSON.stringify({ requestId }),
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The service looks up the stored blob data, dispatches the work to a pool container, and creates the recording. You can check the recording status via the service's Requests page, or provide a webhook to be notified on completion.
|
|
87
|
+
|
|
88
|
+
### 3. (Optional) Get notified when recordings complete
|
|
89
|
+
|
|
90
|
+
If you want to be notified when a recording finishes, call the blob endpoint directly with a `webhookUrl`:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
await fetch(
|
|
94
|
+
`${RECORDER_URL}/.netlify/functions/create-recording-from-blob-background`,
|
|
95
|
+
{
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: { "Content-Type": "application/json" },
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
blobUrl: "https://...", // blob URL from the service
|
|
100
|
+
handlerPath: "netlify/functions/my-handler",
|
|
101
|
+
commitSha: "a1b2c3d4...",
|
|
102
|
+
branchName: "main",
|
|
103
|
+
repositoryUrl: "https://github.com/your-org/your-repo",
|
|
104
|
+
webhookUrl: "https://your-app.netlify.app/.netlify/functions/on-recording-complete",
|
|
105
|
+
}),
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Webhook payload (POSTed to `webhookUrl`):**
|
|
111
|
+
|
|
112
|
+
On success:
|
|
113
|
+
```json
|
|
114
|
+
{ "status": "recorded", "recordingId": "a1b2c3d4-..." }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
On failure:
|
|
118
|
+
```json
|
|
119
|
+
{ "status": "failed", "error": "Error message" }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Option B: Self-Hosted
|
|
125
|
+
|
|
126
|
+
If you need full control, you can manage your own blob storage, database, and recording containers. This requires more setup but gives you complete ownership of the data pipeline.
|
|
127
|
+
|
|
128
|
+
### 1. Wrap your Netlify function
|
|
129
|
+
|
|
130
|
+
Use `startRequest` / `finishRequest` with custom callbacks that write to your own storage and database:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { startRequest, finishRequest } from "@replayio-app-building/netlify-recorder";
|
|
17
134
|
import type { Handler } from "@netlify/functions";
|
|
18
135
|
|
|
19
136
|
const handler: Handler = async (event) => {
|
|
@@ -25,8 +142,6 @@ const handler: Handler = async (event) => {
|
|
|
25
142
|
});
|
|
26
143
|
|
|
27
144
|
try {
|
|
28
|
-
// Your handler logic — all fetch() calls and process.env reads
|
|
29
|
-
// are automatically captured while the context is active.
|
|
30
145
|
const result = await myBusinessLogic();
|
|
31
146
|
|
|
32
147
|
return await finishRequest(
|
|
@@ -34,7 +149,6 @@ const handler: Handler = async (event) => {
|
|
|
34
149
|
{
|
|
35
150
|
uploadBlob: async (data) => {
|
|
36
151
|
// Upload the JSON string to your blob storage (S3, R2, etc.)
|
|
37
|
-
// and return the public URL.
|
|
38
152
|
const res = await originalFetch("https://storage.example.com/upload", {
|
|
39
153
|
method: "PUT",
|
|
40
154
|
body: data,
|
|
@@ -43,7 +157,6 @@ const handler: Handler = async (event) => {
|
|
|
43
157
|
return url;
|
|
44
158
|
},
|
|
45
159
|
storeRequestData: async ({ blobUrl, commitSha, branchName, handlerPath }) => {
|
|
46
|
-
// Insert a row into your requests table and return the request ID.
|
|
47
160
|
const [row] = await sql`
|
|
48
161
|
INSERT INTO requests (blob_url, commit_sha, branch_name, handler_path, status)
|
|
49
162
|
VALUES (${blobUrl}, ${commitSha}, ${branchName}, ${handlerPath}, 'captured')
|
|
@@ -59,7 +172,7 @@ const handler: Handler = async (event) => {
|
|
|
59
172
|
}
|
|
60
173
|
);
|
|
61
174
|
} catch (err) {
|
|
62
|
-
reqContext.cleanup();
|
|
175
|
+
reqContext.cleanup();
|
|
63
176
|
throw err;
|
|
64
177
|
}
|
|
65
178
|
};
|
|
@@ -67,12 +180,8 @@ const handler: Handler = async (event) => {
|
|
|
67
180
|
export { handler };
|
|
68
181
|
```
|
|
69
182
|
|
|
70
|
-
The response returned by `finishRequest` includes the `X-Replay-Request-Id` header, which the frontend can read to display the request ID.
|
|
71
|
-
|
|
72
183
|
### 2. Create a requests database table
|
|
73
184
|
|
|
74
|
-
The consuming app must provide a PostgreSQL table to track captured requests:
|
|
75
|
-
|
|
76
185
|
```sql
|
|
77
186
|
CREATE TABLE IF NOT EXISTS requests (
|
|
78
187
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
@@ -87,24 +196,10 @@ CREATE TABLE IF NOT EXISTS requests (
|
|
|
87
196
|
);
|
|
88
197
|
```
|
|
89
198
|
|
|
90
|
-
**Columns:**
|
|
91
|
-
|
|
92
|
-
| Column | Type | Description |
|
|
93
|
-
|---|---|---|
|
|
94
|
-
| `id` | UUID | Unique request ID |
|
|
95
|
-
| `blob_url` | TEXT | URL to the stored captured data blob |
|
|
96
|
-
| `commit_sha` | TEXT | Git commit hash when the request was captured |
|
|
97
|
-
| `branch_name` | TEXT | Git branch name for container cloning |
|
|
98
|
-
| `handler_path` | TEXT | Path to the handler file that was executed |
|
|
99
|
-
| `recording_id` | TEXT | Replay recording ID (null until recording is created) |
|
|
100
|
-
| `status` | TEXT | One of: `captured`, `processing`, `recorded`, `failed` |
|
|
101
|
-
| `created_at` | TIMESTAMPTZ | When the request was captured |
|
|
102
|
-
| `updated_at` | TIMESTAMPTZ | Last status update |
|
|
103
|
-
|
|
104
199
|
### 3. Create a background function to produce recordings
|
|
105
200
|
|
|
106
201
|
```typescript
|
|
107
|
-
import { ensureRequestRecording } from "@netlify-recorder
|
|
202
|
+
import { ensureRequestRecording } from "@replayio-app-building/netlify-recorder";
|
|
108
203
|
import type { Handler } from "@netlify/functions";
|
|
109
204
|
|
|
110
205
|
const handler: Handler = async (event) => {
|
|
@@ -145,13 +240,13 @@ const handler: Handler = async (event) => {
|
|
|
145
240
|
export { handler };
|
|
146
241
|
```
|
|
147
242
|
|
|
148
|
-
### 4. Create a container script
|
|
243
|
+
### 4. Create a container script
|
|
149
244
|
|
|
150
|
-
This script runs inside the container
|
|
245
|
+
This script runs inside the recording container under `replay-node`:
|
|
151
246
|
|
|
152
247
|
```typescript
|
|
153
248
|
// scripts/create-request-recording.ts
|
|
154
|
-
import { createRequestRecording } from "@netlify-recorder
|
|
249
|
+
import { createRequestRecording } from "@replayio-app-building/netlify-recorder";
|
|
155
250
|
|
|
156
251
|
const args = process.argv.slice(2);
|
|
157
252
|
const blobUrl = args[args.indexOf("--blob-url") + 1]!;
|
|
@@ -164,6 +259,23 @@ await createRequestRecording(blobUrl, handlerPath, {
|
|
|
164
259
|
});
|
|
165
260
|
```
|
|
166
261
|
|
|
262
|
+
### Required infrastructure
|
|
263
|
+
|
|
264
|
+
Self-hosted recording requires these environment variables:
|
|
265
|
+
|
|
266
|
+
| Variable | Description |
|
|
267
|
+
|---|---|
|
|
268
|
+
| `INFISICAL_CLIENT_ID` | Infisical service account client ID |
|
|
269
|
+
| `INFISICAL_CLIENT_SECRET` | Infisical service account client secret |
|
|
270
|
+
| `INFISICAL_PROJECT_ID` | Infisical project ID |
|
|
271
|
+
| `INFISICAL_ENVIRONMENT` | Infisical environment (e.g. `production`) |
|
|
272
|
+
| `FLY_API_TOKEN` | Fly.io API token for container management |
|
|
273
|
+
| `FLY_APP_NAME` | Fly.io app name for container deployment |
|
|
274
|
+
| `APP_REPOSITORY_URL` | Git repository URL for container cloning |
|
|
275
|
+
| `RECORD_REPLAY_API_KEY` | Replay API key for recording upload |
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
167
279
|
## API Reference
|
|
168
280
|
|
|
169
281
|
### `startRequest(requestInfo): RequestContext`
|
|
@@ -178,19 +290,26 @@ Begins capturing a Netlify handler execution. Patches `globalThis.fetch` and `pr
|
|
|
178
290
|
|
|
179
291
|
**Returns:** A `RequestContext` object to pass to `finishRequest`.
|
|
180
292
|
|
|
181
|
-
### `finishRequest(requestContext, callbacks, response): Promise<HandlerResponse>`
|
|
293
|
+
### `finishRequest(requestContext, callbacks, response, options?): Promise<HandlerResponse>`
|
|
182
294
|
|
|
183
|
-
Finalizes the request capture. Restores original `fetch` and `process.env`, serializes the captured data, uploads it via the
|
|
295
|
+
Finalizes the request capture. Restores original `fetch` and `process.env`, serializes the captured data, uploads it via the callbacks, and returns the response with `X-Replay-Request-Id` header set.
|
|
184
296
|
|
|
185
297
|
**Parameters:**
|
|
186
298
|
- `requestContext` — The context returned by `startRequest`
|
|
187
|
-
- `callbacks
|
|
188
|
-
- `callbacks.storeRequestData({ blobUrl, commitSha, branchName, handlerPath })` — Stores metadata, returns request ID
|
|
299
|
+
- `callbacks` — Either `remoteCallbacks(serviceUrl)` or custom `{ uploadBlob, storeRequestData }` callbacks
|
|
189
300
|
- `response` — The handler's response object (`{ statusCode, headers?, body? }`)
|
|
301
|
+
- `options.handlerPath` — Path to the handler file (used for recording metadata)
|
|
302
|
+
|
|
303
|
+
### `remoteCallbacks(serviceUrl): FinishRequestCallbacks`
|
|
304
|
+
|
|
305
|
+
Creates callbacks for `finishRequest` that send captured data to the Netlify Recorder service. The service handles blob storage and request tracking — no local database needed.
|
|
306
|
+
|
|
307
|
+
**Parameters:**
|
|
308
|
+
- `serviceUrl` — Base URL of the Netlify Recorder service (e.g. `"https://netlify-recorder-bm4wmw.netlify.app"`)
|
|
190
309
|
|
|
191
310
|
### `ensureRequestRecording(requestId, options): Promise<string>`
|
|
192
311
|
|
|
193
|
-
Spawns a container via `@replayio/app-building` to create a Replay recording from captured request data. Returns the recording ID.
|
|
312
|
+
Spawns a container via `@replayio/app-building` to create a Replay recording from captured request data. Returns the recording ID. Only needed for self-hosted setups (Option B).
|
|
194
313
|
|
|
195
314
|
**Parameters:**
|
|
196
315
|
- `requestId` — The request to create a recording for
|
|
@@ -201,7 +320,7 @@ Spawns a container via `@replayio/app-building` to create a Replay recording fro
|
|
|
201
320
|
|
|
202
321
|
### `createRequestRecording(blobUrl, handlerPath, requestInfo): Promise<void>`
|
|
203
322
|
|
|
204
|
-
Called inside a container running under `replay-node`. Downloads the captured data blob, installs replay-mode interceptors (which return pre-recorded responses instead of making real calls), and executes the original handler so replay-node can record the execution.
|
|
323
|
+
Called inside a container running under `replay-node`. Downloads the captured data blob, installs replay-mode interceptors (which return pre-recorded responses instead of making real calls), and executes the original handler so replay-node can record the execution. Only needed for self-hosted setups (Option B).
|
|
205
324
|
|
|
206
325
|
**Parameters:**
|
|
207
326
|
- `blobUrl` — URL to the captured data blob
|
|
@@ -214,11 +333,11 @@ Called inside a container running under `replay-node`. Downloads the captured da
|
|
|
214
333
|
|---|---|---|
|
|
215
334
|
| `COMMIT_SHA` | No | Git commit hash (defaults to `"HEAD"`) |
|
|
216
335
|
| `BRANCH_NAME` | No | Git branch name for container cloning (defaults to `"main"`) |
|
|
217
|
-
| `RECORD_REPLAY_API_KEY` | For recording | Replay API key for uploading recordings |
|
|
218
|
-
| `APP_REPOSITORY_URL` | For recording | Git repository URL for container cloning |
|
|
336
|
+
| `RECORD_REPLAY_API_KEY` | For self-hosted recording | Replay API key for uploading recordings |
|
|
337
|
+
| `APP_REPOSITORY_URL` | For self-hosted recording | Git repository URL for container cloning |
|
|
219
338
|
|
|
220
339
|
## How It Works
|
|
221
340
|
|
|
222
|
-
1. **Capture phase** (`startRequest` / `finishRequest`): When a Netlify function handles a request, `startRequest` patches `globalThis.fetch` and `process.env` with Proxies that record every outbound network call and environment variable read. When the handler completes, `finishRequest` restores the originals, serializes the captured data to JSON,
|
|
341
|
+
1. **Capture phase** (`startRequest` / `finishRequest`): When a Netlify function handles a request, `startRequest` patches `globalThis.fetch` and `process.env` with Proxies that record every outbound network call and environment variable read. When the handler completes, `finishRequest` restores the originals, serializes the captured data to JSON, and sends it to either the remote service (via `remoteCallbacks`) or your own storage (via custom callbacks).
|
|
223
342
|
|
|
224
|
-
2. **Recording phase
|
|
343
|
+
2. **Recording phase**: The captured blob is sent to a recording container (either via the Netlify Recorder service or self-hosted). Inside the container, `createRequestRecording` downloads the blob, installs replay-mode interceptors that return the pre-recorded responses, and re-executes the handler under `replay-node`. Since replay-node records all execution, this produces a Replay recording of the exact same handler execution.
|
package/dist/index.d.ts
CHANGED
|
@@ -118,6 +118,20 @@ interface FinishRequestOptions {
|
|
|
118
118
|
*/
|
|
119
119
|
declare function finishRequest(requestContext: RequestContext, callbacks: FinishRequestCallbacks, response: HandlerResponse, options?: FinishRequestOptions): Promise<HandlerResponse>;
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Creates `FinishRequestCallbacks` that send captured data to a remote
|
|
123
|
+
* Netlify Recorder service. This removes the need for the consuming app
|
|
124
|
+
* to set up its own blob storage or database tables.
|
|
125
|
+
*
|
|
126
|
+
* The callbacks upload blob data and store request metadata via the
|
|
127
|
+
* service's `store-request` endpoint, which handles UploadThing storage
|
|
128
|
+
* and database insertion.
|
|
129
|
+
*
|
|
130
|
+
* @param serviceUrl - Base URL of the Netlify Recorder service
|
|
131
|
+
* (e.g. "https://netlify-recorder-bm4wmw.netlify.app")
|
|
132
|
+
*/
|
|
133
|
+
declare function remoteCallbacks(serviceUrl: string): FinishRequestCallbacks;
|
|
134
|
+
|
|
121
135
|
/**
|
|
122
136
|
* Redacts sensitive environment variable values from blob data.
|
|
123
137
|
*
|
|
@@ -206,4 +220,4 @@ interface SpawnRecordingContainerOptions {
|
|
|
206
220
|
*/
|
|
207
221
|
declare function spawnRecordingContainer(options: SpawnRecordingContainerOptions): Promise<string>;
|
|
208
222
|
|
|
209
|
-
export { type BlobData, type CapturedData, type ContainerInfraConfig, type EnsureRecordingOptions, type EnvRead, type FinishRequestCallbacks, type NetworkCall, type RequestContext, type RequestInfo, type SpawnRecordingContainerOptions, createRequestRecording, ensureRequestRecording, finishRequest, readInfraConfigFromEnv, redactBlobData, spawnRecordingContainer, startRequest };
|
|
223
|
+
export { type BlobData, type CapturedData, type ContainerInfraConfig, type EnsureRecordingOptions, type EnvRead, type FinishRequestCallbacks, type NetworkCall, type RequestContext, type RequestInfo, type SpawnRecordingContainerOptions, createRequestRecording, ensureRequestRecording, finishRequest, readInfraConfigFromEnv, redactBlobData, remoteCallbacks, spawnRecordingContainer, startRequest };
|
package/dist/index.js
CHANGED
|
@@ -301,6 +301,48 @@ async function finishRequest(requestContext, callbacks, response, options) {
|
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// src/remoteCallbacks.ts
|
|
305
|
+
function remoteCallbacks(serviceUrl) {
|
|
306
|
+
const base = serviceUrl.replace(/\/+$/, "");
|
|
307
|
+
let pendingBlobData;
|
|
308
|
+
return {
|
|
309
|
+
uploadBlob: async (data) => {
|
|
310
|
+
pendingBlobData = data;
|
|
311
|
+
return "__pending__";
|
|
312
|
+
},
|
|
313
|
+
storeRequestData: async (metadata) => {
|
|
314
|
+
const blobData = pendingBlobData;
|
|
315
|
+
pendingBlobData = void 0;
|
|
316
|
+
if (!blobData) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
"remoteCallbacks: uploadBlob must be called before storeRequestData"
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
const res = await fetch(
|
|
322
|
+
`${base}/.netlify/functions/store-request`,
|
|
323
|
+
{
|
|
324
|
+
method: "POST",
|
|
325
|
+
headers: { "Content-Type": "application/json" },
|
|
326
|
+
body: JSON.stringify({
|
|
327
|
+
blobData,
|
|
328
|
+
handlerPath: metadata.handlerPath,
|
|
329
|
+
commitSha: metadata.commitSha,
|
|
330
|
+
branchName: metadata.branchName
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
if (!res.ok) {
|
|
335
|
+
const errBody = await res.text().catch(() => "(unreadable)");
|
|
336
|
+
throw new Error(
|
|
337
|
+
`Netlify Recorder store-request failed: ${res.status} ${errBody}`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
const result = await res.json();
|
|
341
|
+
return result.requestId;
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
304
346
|
// src/spawnRecordingContainer.ts
|
|
305
347
|
async function spawnRecordingContainer(options) {
|
|
306
348
|
const {
|
|
@@ -609,6 +651,7 @@ export {
|
|
|
609
651
|
finishRequest,
|
|
610
652
|
readInfraConfigFromEnv,
|
|
611
653
|
redactBlobData,
|
|
654
|
+
remoteCallbacks,
|
|
612
655
|
spawnRecordingContainer,
|
|
613
656
|
startRequest
|
|
614
657
|
};
|