@replayio-app-building/netlify-recorder 0.15.3 → 0.15.5
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 +84 -3
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,7 +112,7 @@ export default createRecordingRequestHandler(
|
|
|
112
112
|
|
|
113
113
|
### 2. Create recordings
|
|
114
114
|
|
|
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:
|
|
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. If the request was created with a secret, you must include it:
|
|
116
116
|
|
|
117
117
|
```typescript
|
|
118
118
|
const response = await fetch(
|
|
@@ -122,6 +122,7 @@ const response = await fetch(
|
|
|
122
122
|
headers: { "Content-Type": "application/json" },
|
|
123
123
|
body: JSON.stringify({
|
|
124
124
|
requestId,
|
|
125
|
+
secret,
|
|
125
126
|
webhookUrl: "https://your-app.netlify.app/api/on-recording-complete", // optional
|
|
126
127
|
}),
|
|
127
128
|
}
|
|
@@ -144,17 +145,95 @@ On failure:
|
|
|
144
145
|
|
|
145
146
|
### 3. Check recording status
|
|
146
147
|
|
|
147
|
-
You can poll the recording status at any time:
|
|
148
|
+
You can poll the recording status at any time. If the request was created with a secret, you must include it:
|
|
148
149
|
|
|
149
150
|
```typescript
|
|
150
151
|
const res = await fetch(
|
|
151
|
-
`${RECORDER_URL}/api/get-request?requestId=${requestId}`
|
|
152
|
+
`${RECORDER_URL}/api/get-request?requestId=${requestId}&secret=${secret}`
|
|
152
153
|
);
|
|
153
154
|
const { status, recordingId } = await res.json();
|
|
154
155
|
// status: "captured" | "processing" | "recorded" | "failed"
|
|
155
156
|
// recordingId: string | null
|
|
156
157
|
```
|
|
157
158
|
|
|
159
|
+
Requests created with a secret return 403 if the secret is missing or incorrect.
|
|
160
|
+
|
|
161
|
+
### 4. Access control with secrets
|
|
162
|
+
|
|
163
|
+
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.
|
|
164
|
+
|
|
165
|
+
#### Setting a secret
|
|
166
|
+
|
|
167
|
+
Pass `secret` in the options when wrapping your handler:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
export default createRecordingRequestHandler(
|
|
171
|
+
async (req) => {
|
|
172
|
+
const result = await myBusinessLogic();
|
|
173
|
+
return { statusCode: 200, body: JSON.stringify(result) };
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
callbacks: remoteCallbacks(RECORDER_URL),
|
|
177
|
+
handlerPath: "netlify/functions/my-handler",
|
|
178
|
+
secret: process.env.NETLIFY_RECORDER_SECRET,
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Listing requests by secret
|
|
184
|
+
|
|
185
|
+
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:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const res = await fetch(
|
|
189
|
+
`${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`
|
|
190
|
+
);
|
|
191
|
+
const { rows, total, page, limit } = await res.json();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Query parameters:
|
|
195
|
+
|
|
196
|
+
| Parameter | Description |
|
|
197
|
+
|---|---|
|
|
198
|
+
| `secret` | **(required)** The secret string used when creating the requests |
|
|
199
|
+
| `id` | Search by request ID prefix |
|
|
200
|
+
| `status` | Filter by status: `captured`, `queued`, `processing`, `recorded`, `failed`, `all` |
|
|
201
|
+
| `handlerPath` | Filter by handler path (exact match) |
|
|
202
|
+
| `after` | Only include requests created at or after this ISO timestamp |
|
|
203
|
+
| `before` | Only include requests created at or before this ISO timestamp |
|
|
204
|
+
| `page` | Page number (default 1) |
|
|
205
|
+
| `limit` | Page size (default 20, max 100) |
|
|
206
|
+
|
|
207
|
+
Without a `secret` parameter, only requests created without a secret are returned.
|
|
208
|
+
|
|
209
|
+
#### Checking request status with a secret
|
|
210
|
+
|
|
211
|
+
When a request was created with a secret, you must include the secret when polling its status:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
const res = await fetch(
|
|
215
|
+
`${RECORDER_URL}/api/get-request?requestId=${requestId}&secret=${secret}`
|
|
216
|
+
);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Requests created without a secret remain accessible without one (backward compatible).
|
|
220
|
+
|
|
221
|
+
#### Managing your secret
|
|
222
|
+
|
|
223
|
+
Store your secret as a `NETLIFY_RECORDER_SECRET` environment variable. To keep it secure:
|
|
224
|
+
|
|
225
|
+
1. **Netlify site environment:** Add `NETLIFY_RECORDER_SECRET` in your Netlify site's environment variables (Site settings → Environment variables). This makes it available to all deployed functions.
|
|
226
|
+
|
|
227
|
+
2. **Branch-level secret** (for CI/development): If you're using the Netlify Recorder agent infrastructure, store the secret as a branch secret so deploy scripts and background agents can access it:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
set-branch-secret NETLIFY_RECORDER_SECRET "your-secret-value"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
3. **Local development:** Add `NETLIFY_RECORDER_SECRET` to your `.env` file (make sure `.env` is in `.gitignore`).
|
|
234
|
+
|
|
235
|
+
Use a strong random string (e.g. `openssl rand -base64 32`) and rotate it if compromised. All requests created under the old secret remain accessible only with the old secret value — there is no migration mechanism, so plan rotations during low-traffic windows.
|
|
236
|
+
|
|
158
237
|
---
|
|
159
238
|
|
|
160
239
|
## Option B: Self-Hosted
|
|
@@ -406,6 +485,7 @@ When `context.waitUntil` is not available (v1 handlers or missing context), the
|
|
|
406
485
|
- `options.commitSha` — Override `COMMIT_SHA` env var
|
|
407
486
|
- `options.branchName` — Override `BRANCH_NAME` env var
|
|
408
487
|
- `options.repositoryUrl` — Override `REPLAY_REPOSITORY_URL` env var
|
|
488
|
+
- `options.secret` — Optional secret string. When set, the stored request is only accessible via API calls that provide the same secret value.
|
|
409
489
|
|
|
410
490
|
**Returns:** A wrapped handler function with the same signature.
|
|
411
491
|
|
|
@@ -443,6 +523,7 @@ Logs a `console.warn` when the total duration exceeds 2 seconds or when individu
|
|
|
443
523
|
- `options.branchName` — Override `BRANCH_NAME` env var
|
|
444
524
|
- `options.repositoryUrl` — Override `REPLAY_REPOSITORY_URL` env var
|
|
445
525
|
- `options.requestId` — Pre-generated request ID (used by `createRecordingRequestHandler` in the `waitUntil` flow)
|
|
526
|
+
- `options.secret` — Optional secret string. When set, the stored request is only accessible via API calls that provide the same secret value.
|
|
446
527
|
|
|
447
528
|
### `remoteCallbacks(serviceUrl): FinishRequestCallbacks`
|
|
448
529
|
|
package/dist/index.d.ts
CHANGED
|
@@ -111,6 +111,8 @@ interface FinishRequestCallbacks {
|
|
|
111
111
|
handlerPath: string;
|
|
112
112
|
/** Pre-generated request ID. Use as the row ID when provided. */
|
|
113
113
|
requestId?: string;
|
|
114
|
+
/** Optional secret that restricts access to this request. */
|
|
115
|
+
secret?: string;
|
|
114
116
|
}) => Promise<string>;
|
|
115
117
|
}
|
|
116
118
|
/**
|
|
@@ -217,6 +219,11 @@ interface FinishRequestOptions {
|
|
|
217
219
|
* the response is returned before `finishRequest` runs.
|
|
218
220
|
*/
|
|
219
221
|
requestId?: string;
|
|
222
|
+
/**
|
|
223
|
+
* Optional secret string. When set, the stored request is only
|
|
224
|
+
* accessible via API calls that provide the same secret value.
|
|
225
|
+
*/
|
|
226
|
+
secret?: string;
|
|
220
227
|
}
|
|
221
228
|
/**
|
|
222
229
|
* Called at the end of the handler execution.
|
package/dist/index.js
CHANGED
|
@@ -458,7 +458,8 @@ async function finishRequest(requestContext, callbacks, response, options) {
|
|
|
458
458
|
branchName,
|
|
459
459
|
repositoryUrl,
|
|
460
460
|
handlerPath,
|
|
461
|
-
requestId: options?.requestId
|
|
461
|
+
requestId: options?.requestId,
|
|
462
|
+
secret: options?.secret
|
|
462
463
|
});
|
|
463
464
|
const storeDuration = Date.now() - storeStart;
|
|
464
465
|
if (storeDuration > SLOW_STEP_THRESHOLD_MS) {
|
|
@@ -564,7 +565,8 @@ function remoteCallbacks(serviceUrl) {
|
|
|
564
565
|
commitSha: metadata.commitSha,
|
|
565
566
|
branchName: metadata.branchName,
|
|
566
567
|
repositoryUrl: metadata.repositoryUrl,
|
|
567
|
-
requestId: metadata.requestId
|
|
568
|
+
requestId: metadata.requestId,
|
|
569
|
+
secret: metadata.secret
|
|
568
570
|
})
|
|
569
571
|
}
|
|
570
572
|
);
|