@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 +57 -14
- package/dist/index.d.ts +8 -1
- package/dist/index.js +19 -3
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
|
|
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` |
|
|
329
|
-
| `BRANCH_NAME` |
|
|
330
|
-
| `
|
|
331
|
-
|
|
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
|
|
278
|
-
const
|
|
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
|
);
|