@replayio-app-building/netlify-recorder 0.18.0 → 0.19.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 +39 -31
- package/dist/index.d.ts +25 -1
- package/dist/index.js +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,47 +114,40 @@ export default createRecordingRequestHandler(
|
|
|
114
114
|
|
|
115
115
|
### 4. Create recordings via the Netlify Recorder service
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
If your app exposes the blob data via an endpoint (e.g. using `backendRequestsGetBlobData`), construct the URL and pass it:
|
|
117
|
+
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 dispatches the work to the Netlify Recorder service and updates the row status to `"queued"`.
|
|
120
118
|
|
|
121
119
|
```typescript
|
|
120
|
+
import { ensureRequestRecording } from "@replayio-app-building/netlify-recorder";
|
|
121
|
+
|
|
122
122
|
const RECORDER_URL = "https://netlify-recorder-bm4wmw.netlify.app";
|
|
123
|
-
const blobDataUrl = `https://your-app.netlify.app/api/get-backend-request-blob?requestId=${requestId}`;
|
|
124
123
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
method: "POST",
|
|
129
|
-
headers: { "Content-Type": "application/json" },
|
|
130
|
-
body: JSON.stringify({
|
|
131
|
-
blobDataUrl,
|
|
132
|
-
handlerPath: "netlify/functions/my-handler",
|
|
133
|
-
commitSha: "abc123",
|
|
134
|
-
branchName: "main",
|
|
135
|
-
repositoryUrl: "https://github.com/org/repo.git", // optional
|
|
136
|
-
webhookUrl: "https://your-app.netlify.app/api/on-recording-complete", // optional
|
|
137
|
-
}),
|
|
138
|
-
}
|
|
139
|
-
);
|
|
124
|
+
const recordingId = await ensureRequestRecording(sql, requestId, {
|
|
125
|
+
recorderUrl: RECORDER_URL,
|
|
126
|
+
});
|
|
140
127
|
|
|
141
|
-
|
|
128
|
+
if (recordingId) {
|
|
129
|
+
console.log(`Recording already exists: ${recordingId}`);
|
|
130
|
+
} else {
|
|
131
|
+
console.log("Recording queued — check back later or use a webhook");
|
|
132
|
+
}
|
|
142
133
|
```
|
|
143
134
|
|
|
144
|
-
The
|
|
135
|
+
The function is idempotent — calling it multiple times for the same request is safe:
|
|
136
|
+
- **`status: "recorded"`** — returns the `recording_id` immediately
|
|
137
|
+
- **`status: "queued"` or `"processing"`** — returns `null` without re-queuing
|
|
138
|
+
- **`status: "captured"` or `"failed"`** — calls the service, updates status to `"queued"`, returns `null`
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|---|---|---|
|
|
148
|
-
| `blobDataUrl` | Yes | URL where the recording container can fetch the captured blob JSON |
|
|
149
|
-
| `handlerPath` | Yes | Path to the handler file (e.g. `netlify/functions/my-handler`) |
|
|
150
|
-
| `commitSha` | Yes | Git commit SHA of the deployed code |
|
|
151
|
-
| `branchName` | Yes | Git branch of the deployed code |
|
|
152
|
-
| `repositoryUrl` | No | Git repository URL for the container to clone |
|
|
153
|
-
| `webhookUrl` | No | URL to POST the result to when the recording completes or fails |
|
|
140
|
+
By default, the blob data URL points to `${recorderUrl}/api/get-backend-request-blob?requestId=${requestId}`. If your app serves blob data from a different endpoint, pass a custom `blobDataUrl`:
|
|
154
141
|
|
|
155
|
-
|
|
142
|
+
```typescript
|
|
143
|
+
const recordingId = await ensureRequestRecording(sql, requestId, {
|
|
144
|
+
recorderUrl: RECORDER_URL,
|
|
145
|
+
blobDataUrl: `https://your-app.netlify.app/api/get-blob?id=${requestId}`,
|
|
146
|
+
webhookUrl: "https://your-app.netlify.app/api/on-recording-complete", // optional
|
|
147
|
+
});
|
|
148
|
+
```
|
|
156
149
|
|
|
157
|
-
|
|
150
|
+
When `webhookUrl` is provided, the service POSTs the result when the recording completes:
|
|
158
151
|
|
|
159
152
|
On success:
|
|
160
153
|
```json
|
|
@@ -410,6 +403,21 @@ Updates the status of a request. Optionally sets `recording_id` (on success) or
|
|
|
410
403
|
- `recordingId` — Replay recording ID (optional, for `"recorded"` status)
|
|
411
404
|
- `errorMessage` — Error details (optional, for `"failed"` status)
|
|
412
405
|
|
|
406
|
+
### `ensureRequestRecording(sql, requestId, options): Promise<string | null>`
|
|
407
|
+
|
|
408
|
+
Ensures a Replay recording exists (or is being created) for a backend request. Looks up the request in `backend_requests`, returns the `recording_id` if already recorded, or calls the Netlify Recorder service to queue a recording. Idempotent — safe to call multiple times for the same request.
|
|
409
|
+
|
|
410
|
+
**Parameters:**
|
|
411
|
+
- `sql` — A Neon SQL tagged-template function
|
|
412
|
+
- `requestId` — The backend request UUID
|
|
413
|
+
- `options.recorderUrl` — Base URL of the Netlify Recorder service
|
|
414
|
+
- `options.blobDataUrl` — Override the URL where the recording container fetches the blob JSON (defaults to `${recorderUrl}/api/get-backend-request-blob?requestId=${requestId}`)
|
|
415
|
+
- `options.webhookUrl` — URL to POST the result to when the recording completes or fails
|
|
416
|
+
|
|
417
|
+
**Returns:** The recording ID (`string`) if the request is already recorded, or `null` if the recording was queued or is in progress.
|
|
418
|
+
|
|
419
|
+
**Throws:** If the request ID is not found in `backend_requests`, or if the service call fails.
|
|
420
|
+
|
|
413
421
|
### `createRequestRecording(blobUrlOrData, handlerPath, requestInfo): Promise<RecordingResult>`
|
|
414
422
|
|
|
415
423
|
Called inside a recording container running under `replay-node`. Downloads the captured data blob (or accepts pre-parsed `BlobData`), installs replay-mode interceptors that return pre-recorded responses instead of making real calls, and executes the original handler so `replay-node` can record the execution.
|
package/dist/index.d.ts
CHANGED
|
@@ -292,6 +292,30 @@ declare function backendRequestsUpdateStatus(sql: SqlFunction$1, id: string, sta
|
|
|
292
292
|
* captured request data directly in the `backend_requests` table.
|
|
293
293
|
*/
|
|
294
294
|
declare function databaseCallbacks(sql: SqlFunction$1): FinishRequestCallbacks;
|
|
295
|
+
interface EnsureRequestRecordingOptions {
|
|
296
|
+
/** Base URL of the Netlify Recorder service (e.g. "https://netlify-recorder-bm4wmw.netlify.app"). */
|
|
297
|
+
recorderUrl: string;
|
|
298
|
+
/**
|
|
299
|
+
* Full URL where the recording container can fetch the blob JSON for this request.
|
|
300
|
+
* Defaults to `${recorderUrl}/api/get-backend-request-blob?requestId=${requestId}`.
|
|
301
|
+
*/
|
|
302
|
+
blobDataUrl?: string;
|
|
303
|
+
/** URL to POST the result to when the recording completes or fails. */
|
|
304
|
+
webhookUrl?: string;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Ensures a Replay recording exists (or is being created) for a backend request.
|
|
308
|
+
*
|
|
309
|
+
* 1. Looks up the request in `backend_requests`.
|
|
310
|
+
* 2. If a recording already exists (`status === "recorded"`), returns the recording ID immediately.
|
|
311
|
+
* 3. If the request is already queued or processing, returns `null` without re-queuing.
|
|
312
|
+
* 4. Otherwise, calls the Netlify Recorder service's `create-recording` endpoint,
|
|
313
|
+
* updates the row to `"queued"`, and returns `null`.
|
|
314
|
+
*
|
|
315
|
+
* This function is idempotent — calling it multiple times for the same request
|
|
316
|
+
* is safe. Once the recording completes, subsequent calls return the recording ID.
|
|
317
|
+
*/
|
|
318
|
+
declare function ensureRequestRecording(sql: SqlFunction$1, requestId: string, options: EnsureRequestRecordingOptions): Promise<string | null>;
|
|
295
319
|
|
|
296
320
|
type SqlFunction = (...args: any[]) => Promise<any[]>;
|
|
297
321
|
/**
|
|
@@ -316,4 +340,4 @@ declare function databaseAuditDumpLogTable(sql: SqlFunction): Promise<Record<str
|
|
|
316
340
|
|
|
317
341
|
declare function getCurrentRequestId(): string | null;
|
|
318
342
|
|
|
319
|
-
export { type BackendRequest, type BlobData, type CapturedData, type CreateRecordingRequestHandlerOptions, type EnvRead, type FinishRequestCallbacks, type FinishRequestOptions, type HandlerResponse$1 as HandlerResponse, type NetlifyEvent, type NetlifyV2Request, type NetworkCall, type RecordingResult, type RequestContext, type RequestInfo, backendRequestsEnsureTable, backendRequestsGet, backendRequestsGetBlobData, backendRequestsInsert, backendRequestsList, backendRequestsUpdateStatus, createRecordingRequestHandler, createRequestRecording, databaseAuditDumpLogTable, databaseAuditEnsureLogTable, databaseAuditMonitorTable, databaseCallbacks, finishRequest, getCurrentRequestId, redactBlobData, startRequest };
|
|
343
|
+
export { type BackendRequest, type BlobData, type CapturedData, type CreateRecordingRequestHandlerOptions, type EnsureRequestRecordingOptions, type EnvRead, type FinishRequestCallbacks, type FinishRequestOptions, type HandlerResponse$1 as HandlerResponse, type NetlifyEvent, type NetlifyV2Request, type NetworkCall, type RecordingResult, type RequestContext, type RequestInfo, backendRequestsEnsureTable, backendRequestsGet, backendRequestsGetBlobData, backendRequestsInsert, backendRequestsList, backendRequestsUpdateStatus, createRecordingRequestHandler, createRequestRecording, databaseAuditDumpLogTable, databaseAuditEnsureLogTable, databaseAuditMonitorTable, databaseCallbacks, ensureRequestRecording, finishRequest, getCurrentRequestId, redactBlobData, startRequest };
|
package/dist/index.js
CHANGED
|
@@ -1034,6 +1034,40 @@ function databaseCallbacks(sql) {
|
|
|
1034
1034
|
}
|
|
1035
1035
|
};
|
|
1036
1036
|
}
|
|
1037
|
+
async function ensureRequestRecording(sql, requestId, options) {
|
|
1038
|
+
const request = await backendRequestsGet(sql, requestId);
|
|
1039
|
+
if (!request) {
|
|
1040
|
+
throw new Error(`Backend request ${requestId} not found`);
|
|
1041
|
+
}
|
|
1042
|
+
if (request.status === "recorded" && request.recording_id) {
|
|
1043
|
+
return request.recording_id;
|
|
1044
|
+
}
|
|
1045
|
+
if (request.status === "queued" || request.status === "processing") {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
const recorderUrl = options.recorderUrl.replace(/\/+$/, "");
|
|
1049
|
+
const blobDataUrl = options.blobDataUrl ?? `${recorderUrl}/api/get-backend-request-blob?requestId=${requestId}`;
|
|
1050
|
+
const res = await fetch(`${recorderUrl}/api/create-recording`, {
|
|
1051
|
+
method: "POST",
|
|
1052
|
+
headers: { "Content-Type": "application/json" },
|
|
1053
|
+
body: JSON.stringify({
|
|
1054
|
+
blobDataUrl,
|
|
1055
|
+
handlerPath: request.handler_path,
|
|
1056
|
+
commitSha: request.commit_sha,
|
|
1057
|
+
branchName: request.branch_name,
|
|
1058
|
+
repositoryUrl: request.repository_url ?? void 0,
|
|
1059
|
+
webhookUrl: options.webhookUrl
|
|
1060
|
+
})
|
|
1061
|
+
});
|
|
1062
|
+
if (!res.ok) {
|
|
1063
|
+
const errBody = await res.text().catch(() => "(unreadable)");
|
|
1064
|
+
throw new Error(
|
|
1065
|
+
`Netlify Recorder create-recording failed: ${res.status} ${errBody}`
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
await backendRequestsUpdateStatus(sql, requestId, "queued");
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1037
1071
|
|
|
1038
1072
|
// src/databaseAudit.ts
|
|
1039
1073
|
async function databaseAuditEnsureLogTable(sql) {
|
|
@@ -1127,6 +1161,7 @@ export {
|
|
|
1127
1161
|
databaseAuditEnsureLogTable,
|
|
1128
1162
|
databaseAuditMonitorTable,
|
|
1129
1163
|
databaseCallbacks,
|
|
1164
|
+
ensureRequestRecording,
|
|
1130
1165
|
finishRequest,
|
|
1131
1166
|
getCurrentRequestId,
|
|
1132
1167
|
redactBlobData,
|