@replayio-app-building/netlify-recorder 0.40.0 → 0.42.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/dist/index.d.ts +24 -18
- package/dist/index.js +28 -40
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -344,33 +344,39 @@ interface RecordingEndpointResponse {
|
|
|
344
344
|
error?: string;
|
|
345
345
|
}
|
|
346
346
|
/**
|
|
347
|
-
*
|
|
348
|
-
*
|
|
347
|
+
* Payload the recorder service POSTs when a recording completes or fails.
|
|
348
|
+
* Also the shape forwarded to the user-configured `webhookUrl`.
|
|
349
|
+
*/
|
|
350
|
+
interface RecordingWebhookPayload {
|
|
351
|
+
requestId: string;
|
|
352
|
+
status: "recorded" | "failed";
|
|
353
|
+
recordingId?: string;
|
|
354
|
+
error?: string;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Creates a handler that other services can call to trigger recording creation
|
|
358
|
+
* for a backend request or retrieve its current status.
|
|
359
|
+
*
|
|
360
|
+
* ## Endpoints
|
|
349
361
|
*
|
|
350
|
-
* **
|
|
351
|
-
* needed and returns the current status. Idempotent: re-posting the same
|
|
352
|
-
* request ID will not re-queue an already-queued or recorded request.
|
|
362
|
+
* **GET** `?requestId=<uuid>` — returns the current recording status.
|
|
353
363
|
*
|
|
354
|
-
* **POST**
|
|
355
|
-
* recorder service. Updates `backend_requests` status and optionally forwards
|
|
356
|
-
* to the configured `webhookUrl`.
|
|
364
|
+
* **POST** — two contracts distinguished by body shape:
|
|
357
365
|
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
366
|
+
* *Trigger:* `{ "requestId": "<uuid>" }` — triggers recording creation if
|
|
367
|
+
* needed. Idempotent: re-posting won't re-queue.
|
|
368
|
+
*
|
|
369
|
+
* *Callback:* `RecordingWebhookPayload` — sent by the recorder service when
|
|
370
|
+
* a recording completes or fails. Body must include `requestId` and `status`
|
|
371
|
+
* (`"recorded"` | `"failed"`). The presence of `status` distinguishes a
|
|
372
|
+
* callback from a trigger.
|
|
360
373
|
*
|
|
361
374
|
* When `secret` is provided, every request must include an
|
|
362
375
|
* `Authorization: Bearer <secret>` header or receive a 401 response.
|
|
363
|
-
*
|
|
364
|
-
* Response body shape (`RecordingEndpointResponse`):
|
|
365
|
-
* - `{ status: "recorded", recordingId, requestId }` — recording exists
|
|
366
|
-
* - `{ status: "pending", requestId }` — recording is queued or processing
|
|
367
|
-
* - `{ status: "queued", requestId }` — recording was just queued by this call
|
|
368
|
-
* - `{ status: "not_found", error }` — request ID not in backend_requests
|
|
369
|
-
* - `{ status: "error", requestId?, error }` — recording failed or server error
|
|
370
376
|
*/
|
|
371
377
|
declare function createRecordingEndpoint(options: CreateRecordingEndpointOptions): (req: Request) => Promise<Response>;
|
|
372
378
|
|
|
373
379
|
declare function runInRequestContext<T>(requestId: string | null, fn: () => Promise<T>): Promise<T>;
|
|
374
380
|
declare function getCurrentRequestId(): string | null;
|
|
375
381
|
|
|
376
|
-
export { type BackendRequest, type BlobData, type CapturedData, type CreateRecordingEndpointOptions, type CreateRecordingRequestHandlerOptions, type EnsureRequestRecordingOptions, type EnvRead, type FinishRequestCallbacks, type FinishRequestOptions, type HandlerResponse$1 as HandlerResponse, type NetlifyEvent, type NetlifyV2Request, type NetworkCall, type RecordingEndpointResponse, type RecordingResult, type RequestContext, type RequestInfo, backendRequestsEnsureTable, backendRequestsGet, backendRequestsGetBlobUrl, backendRequestsInsert, backendRequestsList, backendRequestsUpdateStatus, createRecordingEndpoint, createRecordingRequestHandler, createRequestRecording, databaseAuditDumpLogTable, databaseAuditEnsureLogTable, databaseAuditMonitorTable, databaseCallbacks, ensureRequestRecording, finishRequest, getCurrentRequestId, redactBlobData, remoteCallbacks, runInRequestContext, startRequest };
|
|
382
|
+
export { type BackendRequest, type BlobData, type CapturedData, type CreateRecordingEndpointOptions, type CreateRecordingRequestHandlerOptions, type EnsureRequestRecordingOptions, type EnvRead, type FinishRequestCallbacks, type FinishRequestOptions, type HandlerResponse$1 as HandlerResponse, type NetlifyEvent, type NetlifyV2Request, type NetworkCall, type RecordingEndpointResponse, type RecordingResult, type RecordingWebhookPayload, type RequestContext, type RequestInfo, backendRequestsEnsureTable, backendRequestsGet, backendRequestsGetBlobUrl, backendRequestsInsert, backendRequestsList, backendRequestsUpdateStatus, createRecordingEndpoint, createRecordingRequestHandler, createRequestRecording, databaseAuditDumpLogTable, databaseAuditEnsureLogTable, databaseAuditMonitorTable, databaseCallbacks, ensureRequestRecording, finishRequest, getCurrentRequestId, redactBlobData, remoteCallbacks, runInRequestContext, startRequest };
|
package/dist/index.js
CHANGED
|
@@ -1517,6 +1517,28 @@ async function forwardWebhook(url, payload) {
|
|
|
1517
1517
|
}
|
|
1518
1518
|
function createRecordingEndpoint(options) {
|
|
1519
1519
|
const { sql, recorderUrl, secret, webhookUrl } = options;
|
|
1520
|
+
async function handleCallback(body) {
|
|
1521
|
+
const { requestId, status, recordingId, error } = body;
|
|
1522
|
+
if (!requestId) {
|
|
1523
|
+
return jsonResponse({ status: "error", error: "Missing requestId in callback body" }, 400);
|
|
1524
|
+
}
|
|
1525
|
+
if (status === "recorded" && recordingId) {
|
|
1526
|
+
await backendRequestsUpdateStatus(sql, requestId, "recorded", recordingId);
|
|
1527
|
+
if (webhookUrl) {
|
|
1528
|
+
await forwardWebhook(webhookUrl, { requestId, status: "recorded", recordingId });
|
|
1529
|
+
}
|
|
1530
|
+
return jsonResponse({ status: "recorded", recordingId, requestId }, 200);
|
|
1531
|
+
}
|
|
1532
|
+
if (status === "failed") {
|
|
1533
|
+
const errorMsg = error ?? "Recording failed";
|
|
1534
|
+
await backendRequestsUpdateStatus(sql, requestId, "failed", void 0, errorMsg);
|
|
1535
|
+
if (webhookUrl) {
|
|
1536
|
+
await forwardWebhook(webhookUrl, { requestId, status: "failed", error: errorMsg });
|
|
1537
|
+
}
|
|
1538
|
+
return jsonResponse({ status: "error", requestId, error: errorMsg }, 200);
|
|
1539
|
+
}
|
|
1540
|
+
return jsonResponse({ status: "error", error: "Invalid callback payload \u2014 expected status 'recorded' or 'failed'" }, 400);
|
|
1541
|
+
}
|
|
1520
1542
|
return async (req) => {
|
|
1521
1543
|
if (secret) {
|
|
1522
1544
|
const auth = req.headers.get("authorization");
|
|
@@ -1538,45 +1560,10 @@ function createRecordingEndpoint(options) {
|
|
|
1538
1560
|
return jsonResponse(formatStatus(request), 200);
|
|
1539
1561
|
}
|
|
1540
1562
|
if (req.method === "POST") {
|
|
1541
|
-
const url = new URL(req.url);
|
|
1542
|
-
if (url.searchParams.has("_callback")) {
|
|
1543
|
-
const callbackRequestId = url.searchParams.get("requestId");
|
|
1544
|
-
if (!callbackRequestId) {
|
|
1545
|
-
return jsonResponse({ status: "error", error: "Missing requestId in callback" }, 400);
|
|
1546
|
-
}
|
|
1547
|
-
const callbackBody = await req.json();
|
|
1548
|
-
if (callbackBody.status === "recorded" && callbackBody.recordingId) {
|
|
1549
|
-
await backendRequestsUpdateStatus(
|
|
1550
|
-
sql,
|
|
1551
|
-
callbackRequestId,
|
|
1552
|
-
"recorded",
|
|
1553
|
-
callbackBody.recordingId
|
|
1554
|
-
);
|
|
1555
|
-
if (webhookUrl) {
|
|
1556
|
-
await forwardWebhook(webhookUrl, {
|
|
1557
|
-
status: "recorded",
|
|
1558
|
-
recordingId: callbackBody.recordingId
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1561
|
-
return jsonResponse(
|
|
1562
|
-
{ status: "recorded", recordingId: callbackBody.recordingId, requestId: callbackRequestId },
|
|
1563
|
-
200
|
|
1564
|
-
);
|
|
1565
|
-
}
|
|
1566
|
-
if (callbackBody.status === "failed") {
|
|
1567
|
-
const errorMsg = callbackBody.error ?? "Recording failed";
|
|
1568
|
-
await backendRequestsUpdateStatus(sql, callbackRequestId, "failed", void 0, errorMsg);
|
|
1569
|
-
if (webhookUrl) {
|
|
1570
|
-
await forwardWebhook(webhookUrl, { status: "failed", error: errorMsg });
|
|
1571
|
-
}
|
|
1572
|
-
return jsonResponse(
|
|
1573
|
-
{ status: "error", requestId: callbackRequestId, error: errorMsg },
|
|
1574
|
-
200
|
|
1575
|
-
);
|
|
1576
|
-
}
|
|
1577
|
-
return jsonResponse({ status: "error", error: "Invalid callback payload" }, 400);
|
|
1578
|
-
}
|
|
1579
1563
|
const body = await req.json();
|
|
1564
|
+
if (body.status) {
|
|
1565
|
+
return handleCallback(body);
|
|
1566
|
+
}
|
|
1580
1567
|
const requestId = body.requestId;
|
|
1581
1568
|
if (!requestId) {
|
|
1582
1569
|
return jsonResponse({ status: "error", error: "Missing requestId in request body" }, 400);
|
|
@@ -1594,11 +1581,12 @@ function createRecordingEndpoint(options) {
|
|
|
1594
1581
|
if (request.status === "queued" || request.status === "processing") {
|
|
1595
1582
|
return jsonResponse({ status: "pending", requestId }, 200);
|
|
1596
1583
|
}
|
|
1597
|
-
const
|
|
1584
|
+
const url = new URL(req.url);
|
|
1585
|
+
const callbackUrl = `${url.origin}${url.pathname}`;
|
|
1598
1586
|
try {
|
|
1599
1587
|
const recordingId = await ensureRequestRecording(sql, requestId, {
|
|
1600
1588
|
recorderUrl,
|
|
1601
|
-
webhookUrl:
|
|
1589
|
+
webhookUrl: callbackUrl
|
|
1602
1590
|
});
|
|
1603
1591
|
if (recordingId) {
|
|
1604
1592
|
return jsonResponse({ status: "recorded", recordingId, requestId }, 200);
|