@replayio-app-building/netlify-recorder 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +127 -15
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,19 +1,21 @@
1
- # @netlify-recorder/core
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/core
8
+ npm install @replayio-app-building/netlify-recorder
9
9
  ```
10
10
 
11
- ## Quick Start
11
+ ## Capturing Requests
12
12
 
13
- ### 1. Wrap your Netlify function with startRequest / finishRequest
13
+ Every integration starts by wrapping your Netlify functions with `startRequest` / `finishRequest` to capture execution data. This is the same regardless of how you create recordings afterwards.
14
+
15
+ ### 1. Wrap your Netlify function
14
16
 
15
17
  ```typescript
16
- import { startRequest, finishRequest } from "@netlify-recorder/core";
18
+ import { startRequest, finishRequest } from "@replayio-app-building/netlify-recorder";
17
19
  import type { Handler } from "@netlify/functions";
18
20
 
19
21
  const handler: Handler = async (event) => {
@@ -101,10 +103,105 @@ CREATE TABLE IF NOT EXISTS requests (
101
103
  | `created_at` | TIMESTAMPTZ | When the request was captured |
102
104
  | `updated_at` | TIMESTAMPTZ | Last status update |
103
105
 
104
- ### 3. Create a background function to produce recordings
106
+ ## Creating Recordings
107
+
108
+ Once you are capturing requests, you need a way to turn captured data into Replay recordings. There are two options:
109
+
110
+ ### Option A: Use the Netlify Recorder service (recommended)
111
+
112
+ The Netlify Recorder app (`https://netlify-recorder-bm4wmw.netlify.app`) hosts a recording service with a pool of warm containers. Your app sends the captured blob URL and the service handles all container orchestration, recording creation, and upload. No container infrastructure is needed in your app.
113
+
114
+ #### How it works
115
+
116
+ 1. Your Netlify function captures request data via `startRequest`/`finishRequest` (see above).
117
+ 2. When a recording is needed, your app POSTs to the Netlify Recorder's background function.
118
+ 3. The service dispatches the work to a pool container (or queues it if none are idle).
119
+ 4. When the recording is ready, the service POSTs the result to your webhook URL.
120
+
121
+ #### Call the recording endpoint
105
122
 
106
123
  ```typescript
107
- import { ensureRequestRecording } from "@netlify-recorder/core";
124
+ // In a Netlify background function or server-side code:
125
+ const response = await fetch(
126
+ "https://netlify-recorder-bm4wmw.netlify.app/.netlify/functions/create-recording-from-blob-background",
127
+ {
128
+ method: "POST",
129
+ headers: { "Content-Type": "application/json" },
130
+ body: JSON.stringify({
131
+ blobUrl: "https://your-storage.com/blob/abc123.json",
132
+ handlerPath: "netlify/functions/your-handler",
133
+ commitSha: "a1b2c3d4...",
134
+ branchName: "main",
135
+ repositoryUrl: "https://github.com/your-org/your-repo",
136
+ webhookUrl: "https://your-app.netlify.app/.netlify/functions/recording-complete",
137
+ requestId: "optional-uuid-for-log-correlation",
138
+ }),
139
+ }
140
+ );
141
+ // Returns 202 immediately (background function).
142
+ ```
143
+
144
+ **Request body:**
145
+
146
+ | Field | Required | Description |
147
+ |---|---|---|
148
+ | `blobUrl` | Yes | URL (or `data:` URI) of the captured request blob JSON |
149
+ | `handlerPath` | Yes | Handler file path relative to the app root (e.g. `netlify/functions/generate-haiku`) |
150
+ | `commitSha` | Yes | Git commit SHA to check out inside the recording container |
151
+ | `branchName` | Yes | Git branch name for cloning |
152
+ | `repositoryUrl` | No | Git repository URL. Required when the handler lives in a different repo than netlify-recorder |
153
+ | `webhookUrl` | No | URL the service will POST the result to on completion |
154
+ | `requestId` | No | Your internal request ID, used for log correlation |
155
+
156
+ **Webhook payload (POSTed to `webhookUrl`):**
157
+
158
+ On success:
159
+ ```json
160
+ { "status": "recorded", "recordingId": "a1b2c3d4-..." }
161
+ ```
162
+
163
+ On failure:
164
+ ```json
165
+ { "status": "failed", "error": "Error message" }
166
+ ```
167
+
168
+ #### Receive the result
169
+
170
+ Create a webhook endpoint in your app to receive the recording result:
171
+
172
+ ```typescript
173
+ import type { Handler } from "@netlify/functions";
174
+
175
+ const handler: Handler = async (event) => {
176
+ const { status, recordingId, error } = JSON.parse(event.body ?? "{}");
177
+
178
+ if (status === "recorded") {
179
+ // Update your database with the recording ID
180
+ await sql`
181
+ UPDATE requests SET status = 'recorded', recording_id = ${recordingId}, updated_at = NOW()
182
+ WHERE id = ${requestId}
183
+ `;
184
+ } else {
185
+ await sql`
186
+ UPDATE requests SET status = 'failed', updated_at = NOW()
187
+ WHERE id = ${requestId}
188
+ `;
189
+ }
190
+
191
+ return { statusCode: 200, body: "OK" };
192
+ };
193
+
194
+ export { handler };
195
+ ```
196
+
197
+ ### Option B: Self-hosted recording with your own containers
198
+
199
+ If you need full control over the recording infrastructure, you can run your own containers using `ensureRequestRecording`. This requires Fly.io and Infisical credentials configured in your environment.
200
+
201
+ #### Create a background function to produce recordings
202
+
203
+ ```typescript
204
+ import { ensureRequestRecording } from "@replayio-app-building/netlify-recorder";
108
205
  import type { Handler } from "@netlify/functions";
109
206
 
110
207
  const handler: Handler = async (event) => {
@@ -145,13 +242,13 @@ const handler: Handler = async (event) => {
145
242
  export { handler };
146
243
  ```
147
244
 
148
- ### 4. Create a container script for createRequestRecording
245
+ #### Create a container script
149
246
 
150
- This script runs inside the container spawned by `ensureRequestRecording`, under `replay-node`:
247
+ This script runs inside the recording container under `replay-node`:
151
248
 
152
249
  ```typescript
153
250
  // scripts/create-request-recording.ts
154
- import { createRequestRecording } from "@netlify-recorder/core";
251
+ import { createRequestRecording } from "@replayio-app-building/netlify-recorder";
155
252
 
156
253
  const args = process.argv.slice(2);
157
254
  const blobUrl = args[args.indexOf("--blob-url") + 1]!;
@@ -164,6 +261,21 @@ await createRequestRecording(blobUrl, handlerPath, {
164
261
  });
165
262
  ```
166
263
 
264
+ #### Required infrastructure
265
+
266
+ Self-hosted recording requires the following environment variables for container orchestration:
267
+
268
+ | Variable | Description |
269
+ |---|---|
270
+ | `INFISICAL_CLIENT_ID` | Infisical service account client ID |
271
+ | `INFISICAL_CLIENT_SECRET` | Infisical service account client secret |
272
+ | `INFISICAL_PROJECT_ID` | Infisical project ID |
273
+ | `INFISICAL_ENVIRONMENT` | Infisical environment (e.g. `production`) |
274
+ | `FLY_API_TOKEN` | Fly.io API token for container management |
275
+ | `FLY_APP_NAME` | Fly.io app name for container deployment |
276
+ | `APP_REPOSITORY_URL` | Git repository URL for container cloning |
277
+ | `RECORD_REPLAY_API_KEY` | Replay API key for recording upload |
278
+
167
279
  ## API Reference
168
280
 
169
281
  ### `startRequest(requestInfo): RequestContext`
@@ -190,7 +302,7 @@ Finalizes the request capture. Restores original `fetch` and `process.env`, seri
190
302
 
191
303
  ### `ensureRequestRecording(requestId, options): Promise<string>`
192
304
 
193
- Spawns a container via `@replayio/app-building` to create a Replay recording from captured request data. Returns the recording ID.
305
+ Spawns a container via `@replayio/app-building` to create a Replay recording from captured request data. Returns the recording ID. Only needed for Option B (self-hosted).
194
306
 
195
307
  **Parameters:**
196
308
  - `requestId` — The request to create a recording for
@@ -201,7 +313,7 @@ Spawns a container via `@replayio/app-building` to create a Replay recording fro
201
313
 
202
314
  ### `createRequestRecording(blobUrl, handlerPath, requestInfo): Promise<void>`
203
315
 
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.
316
+ 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 Option B (self-hosted).
205
317
 
206
318
  **Parameters:**
207
319
  - `blobUrl` — URL to the captured data blob
@@ -214,11 +326,11 @@ Called inside a container running under `replay-node`. Downloads the captured da
214
326
  |---|---|---|
215
327
  | `COMMIT_SHA` | No | Git commit hash (defaults to `"HEAD"`) |
216
328
  | `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 |
329
+ | `RECORD_REPLAY_API_KEY` | For self-hosted recording | Replay API key for uploading recordings |
330
+ | `APP_REPOSITORY_URL` | For self-hosted recording | Git repository URL for container cloning |
219
331
 
220
332
  ## How It Works
221
333
 
222
334
  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, uploads it as a blob, and records the request in the database.
223
335
 
224
- 2. **Recording phase** (`ensureRequestRecording` / `createRequestRecording`): A background function calls `ensureRequestRecording`, which spawns a container with `@replayio/app-building`. 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.
336
+ 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayio-app-building/netlify-recorder",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Capture and replay Netlify function executions as Replay recordings",
5
5
  "type": "module",
6
6
  "exports": {