@replayio-app-building/netlify-recorder 0.40.0 → 0.41.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 +23 -18
- package/dist/index.js +32 -40
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -344,33 +344,38 @@ interface RecordingEndpointResponse {
|
|
|
344
344
|
error?: string;
|
|
345
345
|
}
|
|
346
346
|
/**
|
|
347
|
-
*
|
|
348
|
-
*
|
|
347
|
+
* Payload sent by the recorder service when a recording completes or fails.
|
|
348
|
+
* Used for both the PUT callback to this endpoint and the downstream
|
|
349
|
+
* notification to the user-configured `webhookUrl`.
|
|
350
|
+
*/
|
|
351
|
+
interface RecordingWebhookPayload {
|
|
352
|
+
requestId: string;
|
|
353
|
+
status: "recorded" | "failed";
|
|
354
|
+
recordingId?: string;
|
|
355
|
+
error?: string;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Creates a handler that other services can call to trigger recording creation
|
|
359
|
+
* for a backend request or retrieve its current status.
|
|
360
|
+
*
|
|
361
|
+
* ## Endpoints
|
|
349
362
|
*
|
|
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.
|
|
363
|
+
* **GET** `?requestId=<uuid>` — returns the current recording status.
|
|
353
364
|
*
|
|
354
|
-
* **POST**
|
|
355
|
-
*
|
|
356
|
-
* to the configured `webhookUrl`.
|
|
365
|
+
* **POST** `{ "requestId": "<uuid>" }` — triggers recording creation if needed.
|
|
366
|
+
* Idempotent: re-posting the same request ID will not re-queue.
|
|
357
367
|
*
|
|
358
|
-
* **
|
|
359
|
-
*
|
|
368
|
+
* **PUT** `RecordingWebhookPayload` — webhook callback from the recorder
|
|
369
|
+
* service when a recording completes or fails. Body must include
|
|
370
|
+
* `requestId`, `status` (`"recorded"` | `"failed"`), and either
|
|
371
|
+
* `recordingId` or `error`.
|
|
360
372
|
*
|
|
361
373
|
* When `secret` is provided, every request must include an
|
|
362
374
|
* `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
375
|
*/
|
|
371
376
|
declare function createRecordingEndpoint(options: CreateRecordingEndpointOptions): (req: Request) => Promise<Response>;
|
|
372
377
|
|
|
373
378
|
declare function runInRequestContext<T>(requestId: string | null, fn: () => Promise<T>): Promise<T>;
|
|
374
379
|
declare function getCurrentRequestId(): string | null;
|
|
375
380
|
|
|
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 };
|
|
381
|
+
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");
|
|
@@ -1537,46 +1559,15 @@ function createRecordingEndpoint(options) {
|
|
|
1537
1559
|
}
|
|
1538
1560
|
return jsonResponse(formatStatus(request), 200);
|
|
1539
1561
|
}
|
|
1562
|
+
if (req.method === "PUT") {
|
|
1563
|
+
const body = await req.json();
|
|
1564
|
+
return handleCallback(body);
|
|
1565
|
+
}
|
|
1540
1566
|
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
1567
|
const body = await req.json();
|
|
1568
|
+
if (body.status) {
|
|
1569
|
+
return handleCallback(body);
|
|
1570
|
+
}
|
|
1580
1571
|
const requestId = body.requestId;
|
|
1581
1572
|
if (!requestId) {
|
|
1582
1573
|
return jsonResponse({ status: "error", error: "Missing requestId in request body" }, 400);
|
|
@@ -1594,11 +1585,12 @@ function createRecordingEndpoint(options) {
|
|
|
1594
1585
|
if (request.status === "queued" || request.status === "processing") {
|
|
1595
1586
|
return jsonResponse({ status: "pending", requestId }, 200);
|
|
1596
1587
|
}
|
|
1597
|
-
const
|
|
1588
|
+
const url = new URL(req.url);
|
|
1589
|
+
const callbackUrl = `${url.origin}${url.pathname}`;
|
|
1598
1590
|
try {
|
|
1599
1591
|
const recordingId = await ensureRequestRecording(sql, requestId, {
|
|
1600
1592
|
recorderUrl,
|
|
1601
|
-
webhookUrl:
|
|
1593
|
+
webhookUrl: callbackUrl
|
|
1602
1594
|
});
|
|
1603
1595
|
if (recordingId) {
|
|
1604
1596
|
return jsonResponse({ status: "recorded", recordingId, requestId }, 200);
|