@replayio-app-building/netlify-recorder 0.25.0 → 0.26.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 CHANGED
@@ -137,15 +137,7 @@ The function is idempotent — calling it multiple times for the same request is
137
137
  - **`status: "queued"` or `"processing"`** — returns `null` without re-queuing
138
138
  - **`status: "captured"` or `"failed"`** — calls the service, updates status to `"queued"`, returns `null`
139
139
 
140
- The `blobDataUrl` must be a direct URL to the blob JSON (e.g. an UploadThing URL). The recording container fetches this URL directly no callback to the recorder service is involved:
141
-
142
- ```typescript
143
- const recordingId = await ensureRequestRecording(sql, requestId, {
144
- recorderUrl: RECORDER_URL,
145
- blobDataUrl: `https://utfs.io/f/${blobFileKey}`, // direct URL to stored blob data
146
- webhookUrl: "https://your-app.netlify.app/api/on-recording-complete", // optional
147
- });
148
- ```
140
+ The function reads the `blob_data` from `backend_requests`, uploads it to UploadThing, and passes the URL to the recorder service. This requires the `uploadthing` package and `UPLOADTHING_TOKEN` environment variable.
149
141
 
150
142
  When `webhookUrl` is provided, the service POSTs the result when the recording completes:
151
143
 
@@ -411,7 +403,6 @@ Ensures a Replay recording exists (or is being created) for a backend request. L
411
403
  - `sql` — A Neon SQL tagged-template function
412
404
  - `requestId` — The backend request UUID
413
405
  - `options.recorderUrl` — Base URL of the Netlify Recorder service
414
- - `options.blobDataUrl` — Direct URL where the recording container fetches the blob JSON (e.g. an UploadThing URL)
415
406
  - `options.webhookUrl` — URL to POST the result to when the recording completes or fails
416
407
 
417
408
  **Returns:** The recording ID (`string`) if the request is already recorded, or `null` if the recording was queued or is in progress.
package/dist/index.d.ts CHANGED
@@ -277,12 +277,6 @@ declare function databaseCallbacks(sql: SqlFunction$1): FinishRequestCallbacks;
277
277
  interface EnsureRequestRecordingOptions {
278
278
  /** Base URL of the Netlify Recorder service (e.g. "https://netlify-recorder-bm4wmw.netlify.app"). */
279
279
  recorderUrl: string;
280
- /**
281
- * Full URL where the recording container can fetch the blob JSON for this request.
282
- * Must be a direct URL to the blob data (e.g. an UploadThing URL). The container
283
- * fetches this URL directly — no callback to the recorder service is involved.
284
- */
285
- blobDataUrl: string;
286
280
  /** URL to POST the result to when the recording completes or fails. */
287
281
  webhookUrl?: string;
288
282
  }
@@ -292,8 +286,10 @@ interface EnsureRequestRecordingOptions {
292
286
  * 1. Looks up the request in `backend_requests`.
293
287
  * 2. If a recording already exists (`status === "recorded"`), returns the recording ID immediately.
294
288
  * 3. If the request is already queued or processing, returns `null` without re-queuing.
295
- * 4. Otherwise, calls the Netlify Recorder service's `create-recording` endpoint,
296
- * updates the row to `"queued"`, and returns `null`.
289
+ * 4. Otherwise, uploads the blob data to UploadThing, calls the Netlify Recorder
290
+ * service's `create-recording` endpoint, updates the row to `"queued"`, and returns `null`.
291
+ *
292
+ * Requires `UPLOADTHING_TOKEN` environment variable and the `uploadthing` package.
297
293
  *
298
294
  * This function is idempotent — calling it multiple times for the same request
299
295
  * is safe. Once the recording completes, subsequent calls return the recording ID.
package/dist/index.js CHANGED
@@ -1063,6 +1063,35 @@ function databaseCallbacks(sql) {
1063
1063
  }
1064
1064
  };
1065
1065
  }
1066
+ async function uploadBlobData(blobData, requestId) {
1067
+ let UTApi;
1068
+ try {
1069
+ ({ UTApi } = await Function('return import("uploadthing/server")')());
1070
+ } catch {
1071
+ throw new Error(
1072
+ "ensureRequestRecording requires the 'uploadthing' package. Install it with: npm install uploadthing"
1073
+ );
1074
+ }
1075
+ const token = process.env.UPLOADTHING_TOKEN;
1076
+ if (!token) {
1077
+ throw new Error(
1078
+ "ensureRequestRecording: UPLOADTHING_TOKEN environment variable is required to upload blob data"
1079
+ );
1080
+ }
1081
+ const utapi = new UTApi({ token });
1082
+ const file = new File(
1083
+ [blobData],
1084
+ `blob-${requestId}.json`,
1085
+ { type: "application/json" }
1086
+ );
1087
+ const result = await utapi.uploadFiles(file);
1088
+ if (result.error || !result.data?.ufsUrl) {
1089
+ throw new Error(
1090
+ `Failed to upload blob data for request ${requestId}: ${JSON.stringify(result.error ?? "no URL returned")}`
1091
+ );
1092
+ }
1093
+ return result.data.ufsUrl;
1094
+ }
1066
1095
  async function ensureRequestRecording(sql, requestId, options) {
1067
1096
  const request = await backendRequestsGet(sql, requestId);
1068
1097
  if (!request) {
@@ -1074,12 +1103,13 @@ async function ensureRequestRecording(sql, requestId, options) {
1074
1103
  if (request.status === "queued" || request.status === "processing") {
1075
1104
  return null;
1076
1105
  }
1106
+ const blobDataUrl = await uploadBlobData(request.blob_data, requestId);
1077
1107
  const recorderUrl = options.recorderUrl.replace(/\/+$/, "");
1078
1108
  const res = await fetch(`${recorderUrl}/api/create-recording`, {
1079
1109
  method: "POST",
1080
1110
  headers: { "Content-Type": "application/json" },
1081
1111
  body: JSON.stringify({
1082
- blobDataUrl: options.blobDataUrl,
1112
+ blobDataUrl,
1083
1113
  handlerPath: request.handler_path,
1084
1114
  commitSha: request.commit_sha,
1085
1115
  branchName: request.branch_name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayio-app-building/netlify-recorder",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Capture and replay Netlify function executions as Replay recordings",
5
5
  "type": "module",
6
6
  "exports": {
@@ -18,11 +18,15 @@
18
18
  "prepublishOnly": "tsup"
19
19
  },
20
20
  "peerDependencies": {
21
- "@replayio/app-building": ">=1.0.0"
21
+ "@replayio/app-building": ">=1.0.0",
22
+ "uploadthing": ">=7.0.0"
22
23
  },
23
24
  "peerDependenciesMeta": {
24
25
  "@replayio/app-building": {
25
26
  "optional": true
27
+ },
28
+ "uploadthing": {
29
+ "optional": true
26
30
  }
27
31
  },
28
32
  "devDependencies": {