@replayio-app-building/netlify-recorder 0.3.0 → 0.4.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 CHANGED
@@ -22,7 +22,29 @@ There are two ways to use this package:
22
22
 
23
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
24
 
25
- ### 1. Wrap your Netlify function
25
+ ### 1. Set required environment variables
26
+
27
+ `finishRequest` needs to know which repository, branch, and commit your deployed code belongs to. Set these three environment variables on your Netlify site:
28
+
29
+ | Variable | Description | How to set |
30
+ |---|---|---|
31
+ | `REPOSITORY_URL` | Your app's git repository URL (e.g. `https://github.com/org/repo.git`) | Set in your deploy script or Netlify site settings |
32
+ | `COMMIT_SHA` | The git commit hash of the deployed code | Set in your deploy script via `git rev-parse HEAD` |
33
+ | `BRANCH_NAME` | The git branch of the deployed code | Set in your deploy script via `git rev-parse --abbrev-ref HEAD` |
34
+
35
+ **These are required.** `finishRequest` will throw an error if any are missing. Your deploy script should resolve them from git and set them on the Netlify site before deploying. Example:
36
+
37
+ ```typescript
38
+ // In your deploy script:
39
+ const commitSha = execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
40
+ const branchName = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
41
+ const repositoryUrl = execSync("git remote get-url origin", { encoding: "utf-8" }).trim()
42
+ .replace(/\/\/[^@]+@/, "//"); // strip embedded credentials
43
+
44
+ // Set these on your Netlify site via the Netlify API or CLI
45
+ ```
46
+
47
+ ### 2. Wrap your Netlify function
26
48
 
27
49
  Use `startRequest` / `finishRequest` with `remoteCallbacks()` to capture request data and send it to the service:
28
50
 
@@ -66,7 +88,7 @@ const handler: Handler = async (event) => {
66
88
  export { handler };
67
89
  ```
68
90
 
69
- That's it for capturing. The `remoteCallbacks(url)` helper sends the captured blob data to the Netlify Recorder service's `/api/store-request` endpoint, 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.
91
+ The `remoteCallbacks(url)` helper sends the captured blob data — including the repository URL, branch, and commit — to the Netlify Recorder service's `/api/store-request` endpoint, 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
92
 
71
93
  ### 2. Create recordings
72
94
 
@@ -119,7 +141,11 @@ const { status, recordingId } = await res.json();
119
141
 
120
142
  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.
121
143
 
122
- ### 1. Wrap your Netlify function
144
+ ### 1. Set required environment variables
145
+
146
+ Same as Option A — you must set `REPOSITORY_URL`, `COMMIT_SHA`, and `BRANCH_NAME` on your Netlify site. See the table in Option A, Step 1 above.
147
+
148
+ ### 2. Wrap your Netlify function
123
149
 
124
150
  Use `startRequest` / `finishRequest` with custom callbacks that write to your own storage and database:
125
151
 
@@ -150,10 +176,10 @@ const handler: Handler = async (event) => {
150
176
  const { url } = await res.json();
151
177
  return url;
152
178
  },
153
- storeRequestData: async ({ blobUrl, commitSha, branchName, handlerPath }) => {
179
+ storeRequestData: async ({ blobUrl, commitSha, branchName, repositoryUrl, handlerPath }) => {
154
180
  const [row] = await sql`
155
- INSERT INTO requests (blob_url, commit_sha, branch_name, handler_path, status)
156
- VALUES (${blobUrl}, ${commitSha}, ${branchName}, ${handlerPath}, 'captured')
181
+ INSERT INTO requests (blob_url, commit_sha, branch_name, repository_url, handler_path, status)
182
+ VALUES (${blobUrl}, ${commitSha}, ${branchName}, ${repositoryUrl}, ${handlerPath}, 'captured')
157
183
  RETURNING id
158
184
  `;
159
185
  return row.id;
@@ -174,13 +200,15 @@ const handler: Handler = async (event) => {
174
200
  export { handler };
175
201
  ```
176
202
 
177
- ### 2. Create a requests database table
203
+ ### 3. Create a requests database table
178
204
 
179
205
  ```sql
180
206
  CREATE TABLE IF NOT EXISTS requests (
181
207
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
182
208
  blob_url TEXT,
183
209
  commit_sha TEXT,
210
+ branch_name TEXT,
211
+ repository_url TEXT,
184
212
  handler_path TEXT,
185
213
  recording_id TEXT,
186
214
  status TEXT NOT NULL DEFAULT 'captured'
@@ -190,7 +218,7 @@ CREATE TABLE IF NOT EXISTS requests (
190
218
  );
191
219
  ```
192
220
 
193
- ### 3. Create a background function to produce recordings
221
+ ### 4. Create a background function to produce recordings
194
222
 
195
223
  ```typescript
196
224
  import { ensureRequestRecording } from "@replayio-app-building/netlify-recorder";
@@ -234,7 +262,7 @@ const handler: Handler = async (event) => {
234
262
  export { handler };
235
263
  ```
236
264
 
237
- ### 4. Create a container script
265
+ ### 5. Create a container script
238
266
 
239
267
  This script runs inside the recording container under `replay-node`:
240
268
 
@@ -288,11 +316,16 @@ Begins capturing a Netlify handler execution. Patches `globalThis.fetch` and `pr
288
316
 
289
317
  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.
290
318
 
319
+ **Requires** the following environment variables (or equivalent options overrides): `COMMIT_SHA`, `BRANCH_NAME`, `REPOSITORY_URL`. Throws if any are missing.
320
+
291
321
  **Parameters:**
292
322
  - `requestContext` — The context returned by `startRequest`
293
323
  - `callbacks` — Either `remoteCallbacks(serviceUrl)` or custom `{ uploadBlob, storeRequestData }` callbacks
294
324
  - `response` — The handler's response object (`{ statusCode, headers?, body? }`)
295
325
  - `options.handlerPath` — Path to the handler file (used for recording metadata)
326
+ - `options.commitSha` — Override `COMMIT_SHA` env var
327
+ - `options.branchName` — Override `BRANCH_NAME` env var
328
+ - `options.repositoryUrl` — Override `REPOSITORY_URL` env var
296
329
 
297
330
  ### `remoteCallbacks(serviceUrl): FinishRequestCallbacks`
298
331
 
@@ -323,12 +356,22 @@ Called inside a container running under `replay-node`. Downloads the captured da
323
356
 
324
357
  ## Environment Variables
325
358
 
326
- | Variable | Required | Description |
359
+ ### Required for all setups (read by `finishRequest`)
360
+
361
+ These must be set on your Netlify site. Your deploy script should resolve them from git and push them to the Netlify environment before deploying. `finishRequest` will throw an error if any are missing.
362
+
363
+ | Variable | Description | How to resolve |
327
364
  |---|---|---|
328
- | `COMMIT_SHA` | No | Git commit hash (defaults to `"HEAD"`) |
329
- | `BRANCH_NAME` | No | Git branch name for container cloning (defaults to `"main"`) |
330
- | `RECORD_REPLAY_API_KEY` | For self-hosted recording | Replay API key for uploading recordings |
331
- | `APP_REPOSITORY_URL` | For self-hosted recording | Git repository URL for container cloning |
365
+ | `COMMIT_SHA` | Git commit hash of the deployed code | `git rev-parse HEAD` |
366
+ | `BRANCH_NAME` | Git branch of the deployed code | `git rev-parse --abbrev-ref HEAD` |
367
+ | `REPOSITORY_URL` | Git repository URL (no embedded credentials) | `git remote get-url origin` (strip tokens) |
368
+
369
+ ### Required for self-hosted recording (Option B)
370
+
371
+ | Variable | Description |
372
+ |---|---|
373
+ | `RECORD_REPLAY_API_KEY` | Replay API key for uploading recordings |
374
+ | `APP_REPOSITORY_URL` | Git repository URL for container cloning |
332
375
 
333
376
  ## How It Works
334
377
 
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ interface FinishRequestCallbacks {
46
46
  blobUrl: string;
47
47
  commitSha: string;
48
48
  branchName: string;
49
+ repositoryUrl: string;
49
50
  handlerPath: string;
50
51
  }) => Promise<string>;
51
52
  }
@@ -109,6 +110,12 @@ interface HandlerResponse {
109
110
  }
110
111
  interface FinishRequestOptions {
111
112
  handlerPath?: string;
113
+ /** Override COMMIT_SHA env var. */
114
+ commitSha?: string;
115
+ /** Override BRANCH_NAME env var. */
116
+ branchName?: string;
117
+ /** Override REPOSITORY_URL env var. */
118
+ repositoryUrl?: string;
112
119
  }
113
120
  /**
114
121
  * Called at the end of the handler execution.
@@ -220,4 +227,4 @@ interface SpawnRecordingContainerOptions {
220
227
  */
221
228
  declare function spawnRecordingContainer(options: SpawnRecordingContainerOptions): Promise<string>;
222
229
 
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 };
230
+ export { type BlobData, type CapturedData, type ContainerInfraConfig, type EnsureRecordingOptions, type EnvRead, type FinishRequestCallbacks, type FinishRequestOptions, type NetworkCall, type RequestContext, type RequestInfo, type SpawnRecordingContainerOptions, createRequestRecording, ensureRequestRecording, finishRequest, readInfraConfigFromEnv, redactBlobData, remoteCallbacks, spawnRecordingContainer, startRequest };
package/dist/index.js CHANGED
@@ -168,6 +168,7 @@ var ENV_ALLOW_LIST = /* @__PURE__ */ new Set([
168
168
  "LOGNAME",
169
169
  // Deploy metadata (non-secret identifiers)
170
170
  "COMMIT_SHA",
171
+ "BRANCH_NAME",
171
172
  // Common non-secret Netlify build vars
172
173
  "NETLIFY",
173
174
  "NETLIFY_DEV",
@@ -274,8 +275,21 @@ async function finishRequest(requestContext, callbacks, response, options) {
274
275
  if (globalThis.__REPLAY_RECORDING_MODE__ === true) {
275
276
  return response;
276
277
  }
277
- const commitSha = process.env.COMMIT_SHA ?? "HEAD";
278
- const branchName = process.env.BRANCH_NAME ?? "main";
278
+ const rawCommitSha = options?.commitSha ?? process.env.COMMIT_SHA;
279
+ const rawBranchName = options?.branchName ?? process.env.BRANCH_NAME;
280
+ const rawRepositoryUrl = options?.repositoryUrl ?? process.env.REPOSITORY_URL;
281
+ const missing = [];
282
+ if (!rawCommitSha) missing.push("COMMIT_SHA");
283
+ if (!rawBranchName) missing.push("BRANCH_NAME");
284
+ if (!rawRepositoryUrl) missing.push("REPOSITORY_URL");
285
+ if (missing.length > 0) {
286
+ throw new Error(
287
+ `netlify-recorder: missing required configuration: ${missing.join(", ")}. Set these as environment variables on your Netlify site, or pass them via the options parameter. See the package README for setup instructions.`
288
+ );
289
+ }
290
+ const commitSha = rawCommitSha;
291
+ const branchName = rawBranchName;
292
+ const repositoryUrl = rawRepositoryUrl;
279
293
  const rawBlobData = {
280
294
  requestInfo: requestContext.requestInfo,
281
295
  capturedData: requestContext.capturedData,
@@ -290,6 +304,7 @@ async function finishRequest(requestContext, callbacks, response, options) {
290
304
  blobUrl,
291
305
  commitSha,
292
306
  branchName,
307
+ repositoryUrl,
293
308
  handlerPath: options?.handlerPath ?? "unknown"
294
309
  });
295
310
  return {
@@ -327,7 +342,8 @@ function remoteCallbacks(serviceUrl) {
327
342
  blobData,
328
343
  handlerPath: metadata.handlerPath,
329
344
  commitSha: metadata.commitSha,
330
- branchName: metadata.branchName
345
+ branchName: metadata.branchName,
346
+ repositoryUrl: metadata.repositoryUrl
331
347
  })
332
348
  }
333
349
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayio-app-building/netlify-recorder",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Capture and replay Netlify function executions as Replay recordings",
5
5
  "type": "module",
6
6
  "exports": {