@replayio-app-building/netlify-recorder 0.15.4 → 0.15.6
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 +26 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,8 +31,9 @@ The Netlify Recorder app (`https://netlify-recorder-bm4wmw.netlify.app`) provide
|
|
|
31
31
|
| `REPLAY_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
32
|
| `COMMIT_SHA` | The git commit hash of the deployed code | Set in your deploy script via `git rev-parse HEAD` |
|
|
33
33
|
| `BRANCH_NAME` | The git branch of the deployed code | Set in your deploy script via `git rev-parse --abbrev-ref HEAD` |
|
|
34
|
+
| `NETLIFY_RECORDER_SECRET` | Secret string for access control — restricts who can view and act on your captured requests | Set in Netlify site environment variables or via `set-branch-secret` |
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
The first three are **required** — `finishRequest` will throw an error if any are missing. `NETLIFY_RECORDER_SECRET` is strongly recommended to prevent other apps from accessing your captured request data. Your deploy script should resolve the git values and set them on the Netlify site before deploying. Example:
|
|
36
37
|
|
|
37
38
|
```typescript
|
|
38
39
|
// In your deploy script:
|
|
@@ -46,7 +47,7 @@ const repositoryUrl = execSync("git remote get-url origin", { encoding: "utf-8"
|
|
|
46
47
|
|
|
47
48
|
### 2. Wrap your Netlify function
|
|
48
49
|
|
|
49
|
-
Use `createRecordingRequestHandler` with `remoteCallbacks()` to wrap your handler with automatic request capture.
|
|
50
|
+
Use `createRecordingRequestHandler` with `remoteCallbacks()` to wrap your handler with automatic request capture. Set `secret` to restrict access to captured requests — only API calls providing the same secret can view or act on them.
|
|
50
51
|
|
|
51
52
|
**v1 handler** (Netlify Functions v1 — `event` with `httpMethod`, `path`, etc.):
|
|
52
53
|
|
|
@@ -71,6 +72,7 @@ const handler = createRecordingRequestHandler(
|
|
|
71
72
|
{
|
|
72
73
|
callbacks: remoteCallbacks(RECORDER_URL),
|
|
73
74
|
handlerPath: "netlify/functions/my-handler",
|
|
75
|
+
secret: process.env.NETLIFY_RECORDER_SECRET,
|
|
74
76
|
}
|
|
75
77
|
);
|
|
76
78
|
|
|
@@ -102,6 +104,7 @@ export default createRecordingRequestHandler(
|
|
|
102
104
|
{
|
|
103
105
|
callbacks: remoteCallbacks(RECORDER_URL),
|
|
104
106
|
handlerPath: "netlify/functions/my-handler",
|
|
107
|
+
secret: process.env.NETLIFY_RECORDER_SECRET,
|
|
105
108
|
}
|
|
106
109
|
);
|
|
107
110
|
```
|
|
@@ -112,7 +115,7 @@ export default createRecordingRequestHandler(
|
|
|
112
115
|
|
|
113
116
|
### 2. Create recordings
|
|
114
117
|
|
|
115
|
-
When you want to turn a captured request into a Replay recording, POST to the service's `create-recording` endpoint with the request ID:
|
|
118
|
+
When you want to turn a captured request into a Replay recording, POST to the service's `create-recording` endpoint with the request ID. If the request was created with a secret, you must include it:
|
|
116
119
|
|
|
117
120
|
```typescript
|
|
118
121
|
const response = await fetch(
|
|
@@ -122,6 +125,7 @@ const response = await fetch(
|
|
|
122
125
|
headers: { "Content-Type": "application/json" },
|
|
123
126
|
body: JSON.stringify({
|
|
124
127
|
requestId,
|
|
128
|
+
secret,
|
|
125
129
|
webhookUrl: "https://your-app.netlify.app/api/on-recording-complete", // optional
|
|
126
130
|
}),
|
|
127
131
|
}
|
|
@@ -144,17 +148,19 @@ On failure:
|
|
|
144
148
|
|
|
145
149
|
### 3. Check recording status
|
|
146
150
|
|
|
147
|
-
You can poll the recording status at any time:
|
|
151
|
+
You can poll the recording status at any time. If the request was created with a secret, you must include it:
|
|
148
152
|
|
|
149
153
|
```typescript
|
|
150
154
|
const res = await fetch(
|
|
151
|
-
`${RECORDER_URL}/api/get-request?requestId=${requestId}`
|
|
155
|
+
`${RECORDER_URL}/api/get-request?requestId=${requestId}&secret=${secret}`
|
|
152
156
|
);
|
|
153
157
|
const { status, recordingId } = await res.json();
|
|
154
158
|
// status: "captured" | "processing" | "recorded" | "failed"
|
|
155
159
|
// recordingId: string | null
|
|
156
160
|
```
|
|
157
161
|
|
|
162
|
+
Requests created with a secret return 403 if the secret is missing or incorrect.
|
|
163
|
+
|
|
158
164
|
### 4. Access control with secrets
|
|
159
165
|
|
|
160
166
|
You can restrict access to captured requests by setting a `secret` string. When a secret is set, the request is only accessible via API calls that provide the same secret value. This lets each app isolate its requests from other apps sharing the same Netlify Recorder service.
|
|
@@ -179,11 +185,11 @@ export default createRecordingRequestHandler(
|
|
|
179
185
|
|
|
180
186
|
#### Listing requests by secret
|
|
181
187
|
|
|
182
|
-
Use the `
|
|
188
|
+
Use the `requests` endpoint with a `secret` parameter to retrieve all requests associated with your secret, with optional filtering by status, handler path, and time range:
|
|
183
189
|
|
|
184
190
|
```typescript
|
|
185
191
|
const res = await fetch(
|
|
186
|
-
`${RECORDER_URL}/api/
|
|
192
|
+
`${RECORDER_URL}/api/requests?secret=${secret}&status=recorded&handlerPath=netlify/functions/my-handler&after=2025-01-01T00:00:00Z&before=2025-12-31T23:59:59Z`
|
|
187
193
|
);
|
|
188
194
|
const { rows, total, page, limit } = await res.json();
|
|
189
195
|
```
|
|
@@ -193,13 +199,16 @@ Query parameters:
|
|
|
193
199
|
| Parameter | Description |
|
|
194
200
|
|---|---|
|
|
195
201
|
| `secret` | **(required)** The secret string used when creating the requests |
|
|
196
|
-
| `
|
|
202
|
+
| `id` | Search by request ID prefix |
|
|
203
|
+
| `status` | Filter by status: `captured`, `queued`, `processing`, `recorded`, `failed`, `all` |
|
|
197
204
|
| `handlerPath` | Filter by handler path (exact match) |
|
|
198
205
|
| `after` | Only include requests created at or after this ISO timestamp |
|
|
199
206
|
| `before` | Only include requests created at or before this ISO timestamp |
|
|
200
207
|
| `page` | Page number (default 1) |
|
|
201
208
|
| `limit` | Page size (default 20, max 100) |
|
|
202
209
|
|
|
210
|
+
Without a `secret` parameter, only requests created without a secret are returned.
|
|
211
|
+
|
|
203
212
|
#### Checking request status with a secret
|
|
204
213
|
|
|
205
214
|
When a request was created with a secret, you must include the secret when polling its status:
|
|
@@ -256,6 +265,7 @@ const handler = createRecordingRequestHandler(
|
|
|
256
265
|
};
|
|
257
266
|
},
|
|
258
267
|
{
|
|
268
|
+
secret: process.env.NETLIFY_RECORDER_SECRET,
|
|
259
269
|
callbacks: {
|
|
260
270
|
uploadBlob: async (data) => {
|
|
261
271
|
// Upload the JSON string to your blob storage (S3, R2, etc.)
|
|
@@ -266,10 +276,10 @@ const handler = createRecordingRequestHandler(
|
|
|
266
276
|
const { url } = await res.json();
|
|
267
277
|
return url;
|
|
268
278
|
},
|
|
269
|
-
storeRequestData: async ({ blobUrl, commitSha, branchName, repositoryUrl, handlerPath }) => {
|
|
279
|
+
storeRequestData: async ({ blobUrl, commitSha, branchName, repositoryUrl, handlerPath, secret }) => {
|
|
270
280
|
const [row] = await sql`
|
|
271
|
-
INSERT INTO requests (blob_url, commit_sha, branch_name, repository_url, handler_path, status)
|
|
272
|
-
VALUES (${blobUrl}, ${commitSha}, ${branchName}, ${repositoryUrl}, ${handlerPath}, 'captured')
|
|
281
|
+
INSERT INTO requests (blob_url, commit_sha, branch_name, repository_url, handler_path, secret, status)
|
|
282
|
+
VALUES (${blobUrl}, ${commitSha}, ${branchName}, ${repositoryUrl}, ${handlerPath}, ${secret}, 'captured')
|
|
273
283
|
RETURNING id
|
|
274
284
|
`;
|
|
275
285
|
return row.id;
|
|
@@ -291,12 +301,15 @@ CREATE TABLE IF NOT EXISTS requests (
|
|
|
291
301
|
branch_name TEXT,
|
|
292
302
|
repository_url TEXT,
|
|
293
303
|
handler_path TEXT,
|
|
304
|
+
secret TEXT,
|
|
294
305
|
recording_id TEXT,
|
|
295
306
|
status TEXT NOT NULL DEFAULT 'captured'
|
|
296
307
|
CHECK (status IN ('captured', 'processing', 'recorded', 'failed')),
|
|
297
308
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
298
309
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
299
310
|
);
|
|
311
|
+
|
|
312
|
+
CREATE INDEX IF NOT EXISTS idx_requests_secret ON requests (secret) WHERE secret IS NOT NULL;
|
|
300
313
|
```
|
|
301
314
|
|
|
302
315
|
### 4. Create a background function to produce recordings
|
|
@@ -428,6 +441,7 @@ export default createRecordingRequestHandler(
|
|
|
428
441
|
{
|
|
429
442
|
callbacks: remoteCallbacks(RECORDER_URL),
|
|
430
443
|
handlerPath: "netlify/functions/create-order",
|
|
444
|
+
secret: process.env.NETLIFY_RECORDER_SECRET,
|
|
431
445
|
}
|
|
432
446
|
);
|
|
433
447
|
```
|
|
@@ -589,6 +603,7 @@ These must be set on your Netlify site. Your deploy script should resolve them f
|
|
|
589
603
|
| `COMMIT_SHA` | Git commit hash of the deployed code | `git rev-parse HEAD` |
|
|
590
604
|
| `BRANCH_NAME` | Git branch of the deployed code | `git rev-parse --abbrev-ref HEAD` |
|
|
591
605
|
| `REPLAY_REPOSITORY_URL` | Git repository URL (no embedded credentials) | `git remote get-url origin` (strip tokens) |
|
|
606
|
+
| `NETLIFY_RECORDER_SECRET` | Secret for access control (strongly recommended) | `openssl rand -base64 32` — store in Netlify site env vars |
|
|
592
607
|
|
|
593
608
|
### Required for self-hosted recording (Option B)
|
|
594
609
|
|