@replayio-app-building/netlify-recorder 0.45.0 → 0.47.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 +15 -0
- package/dist/index.js +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,6 +169,21 @@ const status = await fetch(
|
|
|
169
169
|
| `not_found` | 404 | Request ID not found in `backend_requests` |
|
|
170
170
|
| `error` | 4xx/5xx | Validation error, auth failure, or recording failure |
|
|
171
171
|
|
|
172
|
+
#### Warm-start replay (preceding requests)
|
|
173
|
+
|
|
174
|
+
Netlify Functions run on AWS Lambda, where module-level state persists across invocations on the same container instance (warm starts). For example, a module-level `Map` used as a cache will retain entries across requests handled by the same container. This means a recording of a warm-start request may behave differently than the original if module-level state is empty.
|
|
175
|
+
|
|
176
|
+
The recorder handles this automatically. `createRecordingRequestHandler` maintains a module-level `originalRequestId` that captures the ID of the first request handled by each module instance. Every subsequent request on the same instance includes this reference in its blob data, linking all requests from the same warm-start chain.
|
|
177
|
+
|
|
178
|
+
When a recording is triggered for a request that has an `originalRequestId`, the recording service:
|
|
179
|
+
|
|
180
|
+
1. Looks up all preceding requests from the same module instance (same `original_request_id`, earlier `created_at`)
|
|
181
|
+
2. Fetches the blob data for each preceding request
|
|
182
|
+
3. Replays the preceding requests in order on the handler module before executing the target request — each preceding request runs with its own replay interceptors so recorded network responses are served without making real calls
|
|
183
|
+
4. Executes the target request, now with module-level state populated exactly as it was in production
|
|
184
|
+
|
|
185
|
+
This is fully automatic — no configuration or code changes are needed beyond wrapping your handlers with `createRecordingRequestHandler`. The `original_request_id` column is stored in the `backend_requests` table and the preceding blob URLs are resolved server-side.
|
|
186
|
+
|
|
172
187
|
### 5. Create recordings programmatically
|
|
173
188
|
|
|
174
189
|
Use `ensureRequestRecording` to turn a captured request into a Replay recording. It checks the `backend_requests` table first — if a recording already exists, it returns the recording ID immediately without calling the service. Otherwise it passes the stored blob data URL to the Netlify Recorder service and updates the row status to `"queued"`.
|
package/dist/index.js
CHANGED
|
@@ -225,8 +225,9 @@ function installNetworkInterceptor(mode, calls) {
|
|
|
225
225
|
);
|
|
226
226
|
}
|
|
227
227
|
consumed.add(matchIdx);
|
|
228
|
+
const duration = call.endTime - call.startTime;
|
|
228
229
|
console.log(
|
|
229
|
-
` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus}`
|
|
230
|
+
` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus} (original: ${duration}ms)`
|
|
230
231
|
);
|
|
231
232
|
const body = call.responseBody ?? "";
|
|
232
233
|
const status = call.responseStatus;
|
|
@@ -1308,7 +1309,7 @@ async function backendRequestsInsert(sql, data) {
|
|
|
1308
1309
|
async function backendRequestsGet(sql, id) {
|
|
1309
1310
|
const rows = await sql`
|
|
1310
1311
|
SELECT id, blob_data_url, handler_path, commit_sha, branch_name, repository_url,
|
|
1311
|
-
status, recording_id, error_message, created_at, updated_at
|
|
1312
|
+
original_request_id, status, recording_id, error_message, created_at, updated_at
|
|
1312
1313
|
FROM backend_requests WHERE id = ${id}
|
|
1313
1314
|
`;
|
|
1314
1315
|
return rows[0] ?? null;
|
|
@@ -1324,7 +1325,7 @@ async function backendRequestsList(sql, filters) {
|
|
|
1324
1325
|
if (filters?.status) {
|
|
1325
1326
|
const rows2 = await sql`
|
|
1326
1327
|
SELECT id, blob_data_url, handler_path, commit_sha, branch_name, repository_url,
|
|
1327
|
-
status, recording_id, error_message, created_at, updated_at
|
|
1328
|
+
original_request_id, status, recording_id, error_message, created_at, updated_at
|
|
1328
1329
|
FROM backend_requests
|
|
1329
1330
|
WHERE status = ${filters.status}
|
|
1330
1331
|
ORDER BY created_at DESC
|
|
@@ -1446,7 +1447,8 @@ async function ensureRequestRecording(sql, requestId, options) {
|
|
|
1446
1447
|
commitSha: request.commit_sha,
|
|
1447
1448
|
branchName: request.branch_name,
|
|
1448
1449
|
repositoryUrl: request.repository_url ?? void 0,
|
|
1449
|
-
webhookUrl: options.webhookUrl
|
|
1450
|
+
webhookUrl: options.webhookUrl,
|
|
1451
|
+
originalRequestId: request.original_request_id ?? void 0
|
|
1450
1452
|
})
|
|
1451
1453
|
});
|
|
1452
1454
|
if (!res.ok) {
|