@riddledc/riddle-proof 0.8.35 → 0.8.37

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/profile.cjs CHANGED
@@ -1378,6 +1378,8 @@ function normalizeSetupAction(input, index) {
1378
1378
  expect_changed: booleanValue(valueFromOwn(input, "expect_changed", "expectChanged", "should_change", "shouldChange", "changed")),
1379
1379
  until_path: untilPath,
1380
1380
  until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
1381
+ expected_path: stringFromOwn(input, "expected_path", "expectedPath", "expected_terminal_path", "expectedTerminalPath"),
1382
+ expected_url: stringFromOwn(input, "expected_url", "expectedUrl", "expected_terminal_url", "expectedTerminalUrl"),
1381
1383
  max_calls: maxCalls,
1382
1384
  tap_burst_size: tapBurstSize,
1383
1385
  settle_ms: settleMs,
@@ -3735,6 +3737,80 @@ function routePathMatches(observed, expected, targetUrl) {
3735
3737
  if (normalizedObserved === normalizedExpected) return true;
3736
3738
  return normalizedObserved === normalizeRoutePath(mountedExpectedRoutePath(targetUrl, expected));
3737
3739
  }
3740
+ function setupActionExpectedRoute(action) {
3741
+ const expectedUrl = typeof action.expected_url === "string" && action.expected_url.trim()
3742
+ ? action.expected_url.trim()
3743
+ : typeof action.expectedUrl === "string" && action.expectedUrl.trim()
3744
+ ? action.expectedUrl.trim()
3745
+ : "";
3746
+ const expectedPath = typeof action.expected_path === "string" && action.expected_path.trim()
3747
+ ? action.expected_path.trim()
3748
+ : typeof action.expectedPath === "string" && action.expectedPath.trim()
3749
+ ? action.expectedPath.trim()
3750
+ : "";
3751
+ if (!expectedUrl && !expectedPath) return null;
3752
+ return { expected_url: expectedUrl || undefined, expected_path: expectedPath || undefined };
3753
+ }
3754
+ function setupUrlMatchesExpectedRoute(href, expected) {
3755
+ if (!expected) return true;
3756
+ let observedUrl;
3757
+ try {
3758
+ observedUrl = new URL(href, targetUrl);
3759
+ } catch {
3760
+ return false;
3761
+ }
3762
+ if (expected.expected_url) {
3763
+ let expectedUrl;
3764
+ try {
3765
+ expectedUrl = new URL(expected.expected_url, targetUrl);
3766
+ } catch {
3767
+ return false;
3768
+ }
3769
+ return observedUrl.href === expectedUrl.href;
3770
+ }
3771
+ const expectedPath = expected.expected_path || "/";
3772
+ if (/[?#]/.test(expectedPath)) {
3773
+ const observedRoute = observedUrl.pathname + observedUrl.search + observedUrl.hash;
3774
+ const normalizedObservedRoute = observedRoute === "/" ? "/" : observedRoute.replace(/\/+(?=[?#]|$)/, "");
3775
+ const normalizedExpectedRoute = expectedPath === "/" ? "/" : expectedPath.replace(/\/+(?=[?#]|$)/, "");
3776
+ return normalizedObservedRoute === normalizedExpectedRoute;
3777
+ }
3778
+ return routePathMatches(observedUrl.pathname, expectedPath, targetUrl);
3779
+ }
3780
+ function setupObservedRouteEvidence(expected, waitError) {
3781
+ let observedUrl = page.url();
3782
+ let observedPath = "";
3783
+ let observedRoute = "";
3784
+ try {
3785
+ const url = new URL(observedUrl, targetUrl);
3786
+ observedUrl = url.href;
3787
+ observedPath = url.pathname;
3788
+ observedRoute = url.pathname + url.search + url.hash;
3789
+ } catch {
3790
+ observedPath = "";
3791
+ observedRoute = "";
3792
+ }
3793
+ return {
3794
+ expected_url: expected && expected.expected_url || undefined,
3795
+ expected_path: expected && expected.expected_path || undefined,
3796
+ observed_url: observedUrl,
3797
+ observed_path: observedPath,
3798
+ observed_route: observedRoute,
3799
+ route_matched: setupUrlMatchesExpectedRoute(observedUrl, expected),
3800
+ route_wait_error: waitError ? String(waitError && waitError.message ? waitError.message : waitError).slice(0, 1000) : undefined,
3801
+ };
3802
+ }
3803
+ async function waitForSetupActionRoute(action, timeout) {
3804
+ const expected = setupActionExpectedRoute(action);
3805
+ if (!expected) return null;
3806
+ let waitError;
3807
+ try {
3808
+ await page.waitForURL((url) => setupUrlMatchesExpectedRoute(url.href, expected), { timeout: Math.min(timeout, 20000) });
3809
+ } catch (error) {
3810
+ waitError = error;
3811
+ }
3812
+ return setupObservedRouteEvidence(expected, waitError);
3813
+ }
3738
3814
  function routeOk(route, targetUrl) {
3739
3815
  return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
3740
3816
  }
@@ -6628,11 +6704,22 @@ async function executeSetupAction(action, ordinal, viewport) {
6628
6704
  const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
6629
6705
  if (prepared.result) return prepared.result;
6630
6706
  await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
6707
+ const routeEvidence = await waitForSetupActionRoute(action, timeout);
6708
+ if (routeEvidence && !routeEvidence.route_matched) {
6709
+ return {
6710
+ ...base,
6711
+ ...setupScopeEvidence(scope),
6712
+ ...setupTapTargetEvidence(prepared.target),
6713
+ ...routeEvidence,
6714
+ reason: "expected_route_not_reached",
6715
+ };
6716
+ }
6631
6717
  return {
6632
6718
  ...base,
6633
6719
  ...setupScopeEvidence(scope),
6634
6720
  ok: true,
6635
6721
  ...setupTapTargetEvidence(prepared.target),
6722
+ ...routeEvidence,
6636
6723
  };
6637
6724
  }
6638
6725
  if (type === "tap_until") {
@@ -7493,6 +7580,26 @@ async function executeSetupAction(action, ordinal, viewport) {
7493
7580
  : { x: box.x + box.width / 2, y: box.y + box.height / 2 };
7494
7581
  if (clickCount > 1) await page.mouse.click(fallbackPoint.x, fallbackPoint.y, { clickCount });
7495
7582
  else await page.mouse.click(fallbackPoint.x, fallbackPoint.y);
7583
+ const routeEvidence = await waitForSetupActionRoute(action, timeout);
7584
+ if (routeEvidence && !routeEvidence.route_matched) {
7585
+ return {
7586
+ ...base,
7587
+ ...setupScopeEvidence(scope),
7588
+ count,
7589
+ target_index: targetIndex,
7590
+ text: matchedText,
7591
+ force: action.force === true || undefined,
7592
+ fallback_to_tap: true,
7593
+ input_dispatch: "playwright_mouse",
7594
+ click_error: String(error && error.message ? error.message : error).slice(0, 1000),
7595
+ click_count: clickCount > 1 ? clickCount : undefined,
7596
+ coordinate_mode: mode,
7597
+ x: position ? fromX : undefined,
7598
+ y: position ? fromY : undefined,
7599
+ ...routeEvidence,
7600
+ reason: "expected_route_not_reached",
7601
+ };
7602
+ }
7496
7603
  return {
7497
7604
  ...base,
7498
7605
  ...setupScopeEvidence(scope),
@@ -7508,6 +7615,24 @@ async function executeSetupAction(action, ordinal, viewport) {
7508
7615
  coordinate_mode: mode,
7509
7616
  x: position ? fromX : undefined,
7510
7617
  y: position ? fromY : undefined,
7618
+ ...routeEvidence,
7619
+ };
7620
+ }
7621
+ const routeEvidence = await waitForSetupActionRoute(action, timeout);
7622
+ if (routeEvidence && !routeEvidence.route_matched) {
7623
+ return {
7624
+ ...base,
7625
+ ...setupScopeEvidence(scope),
7626
+ count,
7627
+ target_index: targetIndex,
7628
+ text: matchedText,
7629
+ force: action.force === true || undefined,
7630
+ click_count: clickCount > 1 ? clickCount : undefined,
7631
+ coordinate_mode: mode,
7632
+ x: position ? fromX : undefined,
7633
+ y: position ? fromY : undefined,
7634
+ ...routeEvidence,
7635
+ reason: "expected_route_not_reached",
7511
7636
  };
7512
7637
  }
7513
7638
  return {
@@ -7522,6 +7647,7 @@ async function executeSetupAction(action, ordinal, viewport) {
7522
7647
  coordinate_mode: mode,
7523
7648
  x: position ? fromX : undefined,
7524
7649
  y: position ? fromY : undefined,
7650
+ ...routeEvidence,
7525
7651
  };
7526
7652
  }
7527
7653
  if (type === "fill" || type === "set_input_value") {
@@ -145,6 +145,8 @@ interface RiddleProofProfileSetupAction {
145
145
  expect_changed?: boolean;
146
146
  until_path?: string;
147
147
  until_expected_value?: JsonValue;
148
+ expected_path?: string;
149
+ expected_url?: string;
148
150
  max_calls?: number;
149
151
  tap_burst_size?: number;
150
152
  settle_ms?: number;
package/dist/profile.d.ts CHANGED
@@ -145,6 +145,8 @@ interface RiddleProofProfileSetupAction {
145
145
  expect_changed?: boolean;
146
146
  until_path?: string;
147
147
  until_expected_value?: JsonValue;
148
+ expected_path?: string;
149
+ expected_url?: string;
148
150
  max_calls?: number;
149
151
  tap_burst_size?: number;
150
152
  settle_ms?: number;
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-PEWAIEER.js";
26
+ } from "./chunk-Z2LCVROU.js";
27
27
  import "./chunk-MLKGABMK.js";
28
28
  export {
29
29
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
@@ -130,10 +130,68 @@ function previewDeployResultFromRecord(input) {
130
130
  function canRecoverPreviewPublish(error) {
131
131
  return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
132
132
  }
133
+ function summarizePreviewDirectory(directory) {
134
+ const stack = [directory];
135
+ let fileCount = 0;
136
+ let totalBytes = 0;
137
+ while (stack.length) {
138
+ const current = stack.pop();
139
+ for (const entry of (0, import_node_fs.readdirSync)(current, { withFileTypes: true })) {
140
+ const fullPath = import_node_path.default.join(current, entry.name);
141
+ if (entry.isDirectory()) {
142
+ stack.push(fullPath);
143
+ continue;
144
+ }
145
+ if (!entry.isFile()) continue;
146
+ const stat = (0, import_node_fs.statSync)(fullPath);
147
+ fileCount += 1;
148
+ totalBytes += stat.size;
149
+ }
150
+ }
151
+ return { file_count: fileCount, total_bytes: totalBytes };
152
+ }
153
+ function previewProgressEmitter(config, base) {
154
+ return async (snapshot) => {
155
+ if (!config.onPreviewProgress) return;
156
+ await config.onPreviewProgress({
157
+ label: base.label,
158
+ framework: base.framework,
159
+ directory: base.directory,
160
+ elapsed_ms: Math.max(0, Date.now() - base.startedAt),
161
+ warnings: base.warnings?.length ? base.warnings : void 0,
162
+ ...snapshot
163
+ });
164
+ };
165
+ }
133
166
  async function waitForPublishedPreview(config, input) {
167
+ await input.emitProgress?.({
168
+ stage: "publish_recovering",
169
+ id: input.id,
170
+ file_count: input.localSummary?.file_count,
171
+ total_bytes: input.localSummary?.total_bytes,
172
+ publish_error: input.publishError.message,
173
+ message: `publish returned ${input.publishError.status}; polling preview status`
174
+ });
134
175
  for (let attempt = 1; attempt <= PREVIEW_PUBLISH_RECOVERY_ATTEMPTS; attempt += 1) {
135
176
  const status = await riddleRequestJson(config, `/v1/preview/${input.id}`);
177
+ await input.emitProgress?.({
178
+ stage: "checking_status",
179
+ id: input.id,
180
+ attempt,
181
+ attempts: PREVIEW_PUBLISH_RECOVERY_ATTEMPTS,
182
+ status: typeof status.status === "string" ? status.status : null,
183
+ preview_url: typeof status.preview_url === "string" ? status.preview_url : void 0,
184
+ file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
185
+ total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
186
+ });
136
187
  if (String(status.status || "") === "ready" && String(status.preview_url || "").trim()) {
188
+ await input.emitProgress?.({
189
+ stage: "ready",
190
+ id: input.id,
191
+ preview_url: String(status.preview_url),
192
+ file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
193
+ total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
194
+ });
137
195
  return previewDeployResultFromRecord({
138
196
  record: status,
139
197
  id: input.id,
@@ -155,7 +213,17 @@ async function deployRiddlePreview(config, directory, label, framework = "static
155
213
  if (!directory?.trim()) throw new Error("directory is required");
156
214
  if (!label?.trim()) throw new Error("label is required");
157
215
  if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
216
+ const startedAt = Date.now();
158
217
  const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
218
+ const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
219
+ await emitProgress({ stage: "validating", message: "checking preview input directory" });
220
+ const localSummary = summarizePreviewDirectory(directory);
221
+ await emitProgress({
222
+ stage: "creating",
223
+ file_count: localSummary.file_count,
224
+ total_bytes: localSummary.total_bytes,
225
+ message: "creating preview upload target"
226
+ });
159
227
  const created = await riddleRequestJson(config, "/v1/preview", {
160
228
  method: "POST",
161
229
  body: JSON.stringify({ framework, label })
@@ -163,10 +231,42 @@ async function deployRiddlePreview(config, directory, label, framework = "static
163
231
  const id = String(created.id || "");
164
232
  const uploadUrl = String(created.upload_url || "");
165
233
  if (!id || !uploadUrl) throw new Error("Riddle preview create response was missing id or upload_url.");
234
+ await emitProgress({
235
+ stage: "created",
236
+ id,
237
+ file_count: localSummary.file_count,
238
+ total_bytes: localSummary.total_bytes,
239
+ message: "preview upload target created"
240
+ });
166
241
  const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-preview-upload-"));
167
242
  const tarball = import_node_path.default.join(scratch, `${id}.tar.gz`);
243
+ let tarballBytes = 0;
168
244
  try {
245
+ await emitProgress({
246
+ stage: "archiving",
247
+ id,
248
+ file_count: localSummary.file_count,
249
+ total_bytes: localSummary.total_bytes,
250
+ message: "creating preview archive"
251
+ });
169
252
  (0, import_node_child_process.execFileSync)("tar", ["czf", tarball, "-C", directory, "."], { stdio: "pipe" });
253
+ tarballBytes = (0, import_node_fs.statSync)(tarball).size;
254
+ await emitProgress({
255
+ stage: "archived",
256
+ id,
257
+ file_count: localSummary.file_count,
258
+ total_bytes: localSummary.total_bytes,
259
+ tarball_bytes: tarballBytes,
260
+ message: "preview archive created"
261
+ });
262
+ await emitProgress({
263
+ stage: "uploading",
264
+ id,
265
+ file_count: localSummary.file_count,
266
+ total_bytes: localSummary.total_bytes,
267
+ tarball_bytes: tarballBytes,
268
+ message: "uploading preview archive"
269
+ });
170
270
  const upload = await fetchFor(config)(uploadUrl, {
171
271
  method: "PUT",
172
272
  headers: { "Content-Type": "application/gzip" },
@@ -175,14 +275,37 @@ async function deployRiddlePreview(config, directory, label, framework = "static
175
275
  if (!upload.ok) {
176
276
  throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
177
277
  }
278
+ await emitProgress({
279
+ stage: "uploaded",
280
+ id,
281
+ file_count: localSummary.file_count,
282
+ total_bytes: localSummary.total_bytes,
283
+ tarball_bytes: tarballBytes,
284
+ message: "preview archive uploaded"
285
+ });
178
286
  } finally {
179
287
  (0, import_node_fs.rmSync)(scratch, { recursive: true, force: true });
180
288
  }
181
289
  const expiresAt = typeof created.expires_at === "string" ? created.expires_at : void 0;
182
290
  try {
291
+ await emitProgress({
292
+ stage: "publishing",
293
+ id,
294
+ file_count: localSummary.file_count,
295
+ total_bytes: localSummary.total_bytes,
296
+ tarball_bytes: tarballBytes || void 0,
297
+ message: "publishing preview"
298
+ });
183
299
  const published = await riddleRequestJson(config, `/v1/preview/${id}/publish`, {
184
300
  method: "POST"
185
301
  });
302
+ await emitProgress({
303
+ stage: "ready",
304
+ id,
305
+ preview_url: String(published.preview_url || ""),
306
+ file_count: typeof published.file_count === "number" ? published.file_count : localSummary.file_count,
307
+ total_bytes: typeof published.total_bytes === "number" ? published.total_bytes : localSummary.total_bytes
308
+ });
186
309
  return previewDeployResultFromRecord({ record: published, id, label, framework, expiresAt, warnings });
187
310
  } catch (error) {
188
311
  if (!canRecoverPreviewPublish(error)) throw error;
@@ -192,7 +315,9 @@ async function deployRiddlePreview(config, directory, label, framework = "static
192
315
  framework,
193
316
  expiresAt,
194
317
  publishError: error,
195
- warnings
318
+ warnings,
319
+ localSummary,
320
+ emitProgress
196
321
  });
197
322
  }
198
323
  }
@@ -6,6 +6,7 @@ interface RiddleClientConfig {
6
6
  apiKeyFile?: string;
7
7
  apiBaseUrl?: string;
8
8
  fetchImpl?: RiddleFetch;
9
+ onPreviewProgress?: (snapshot: RiddlePreviewDeployProgressSnapshot) => void | Promise<void>;
9
10
  }
10
11
  interface RiddleApiKeySource {
11
12
  source: "option" | "env" | "file";
@@ -54,6 +55,25 @@ interface RiddlePollJobOptions {
54
55
  onProgress?: (snapshot: RiddlePollProgressSnapshot) => void | Promise<void>;
55
56
  }
56
57
  type RiddlePreviewFramework = "spa" | "static";
58
+ type RiddlePreviewDeployStage = "validating" | "creating" | "created" | "archiving" | "archived" | "uploading" | "uploaded" | "publishing" | "publish_recovering" | "checking_status" | "ready";
59
+ interface RiddlePreviewDeployProgressSnapshot {
60
+ stage: RiddlePreviewDeployStage;
61
+ label: string;
62
+ framework: RiddlePreviewFramework;
63
+ directory: string;
64
+ elapsed_ms: number;
65
+ id?: string;
66
+ preview_url?: string;
67
+ file_count?: number;
68
+ total_bytes?: number;
69
+ tarball_bytes?: number;
70
+ attempt?: number;
71
+ attempts?: number;
72
+ status?: string | null;
73
+ publish_error?: string;
74
+ warnings?: string[];
75
+ message?: string;
76
+ }
57
77
  interface RiddlePreviewDeployResult {
58
78
  ok: true;
59
79
  id: string;
@@ -151,4 +171,4 @@ declare function createRiddleApiClient(config?: RiddleClientConfig): {
151
171
  pollJob: (jobId: string, options?: RiddlePollJobOptions) => Promise<RiddlePollJobResult>;
152
172
  };
153
173
 
154
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, type RiddleApiKeySource, type RiddleBalanceResult, type RiddleClientConfig, type RiddleFetch, type RiddlePollJobOptions, type RiddlePollJobResult, type RiddlePollProgressSnapshot, type RiddlePollSummary, type RiddlePreviewDeployResult, type RiddlePreviewFramework, type RiddleRunScriptInput, type RiddleServerPreviewInput, type RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview };
174
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, type RiddleApiKeySource, type RiddleBalanceResult, type RiddleClientConfig, type RiddleFetch, type RiddlePollJobOptions, type RiddlePollJobResult, type RiddlePollProgressSnapshot, type RiddlePollSummary, type RiddlePreviewDeployProgressSnapshot, type RiddlePreviewDeployResult, type RiddlePreviewDeployStage, type RiddlePreviewFramework, type RiddleRunScriptInput, type RiddleServerPreviewInput, type RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview };
@@ -6,6 +6,7 @@ interface RiddleClientConfig {
6
6
  apiKeyFile?: string;
7
7
  apiBaseUrl?: string;
8
8
  fetchImpl?: RiddleFetch;
9
+ onPreviewProgress?: (snapshot: RiddlePreviewDeployProgressSnapshot) => void | Promise<void>;
9
10
  }
10
11
  interface RiddleApiKeySource {
11
12
  source: "option" | "env" | "file";
@@ -54,6 +55,25 @@ interface RiddlePollJobOptions {
54
55
  onProgress?: (snapshot: RiddlePollProgressSnapshot) => void | Promise<void>;
55
56
  }
56
57
  type RiddlePreviewFramework = "spa" | "static";
58
+ type RiddlePreviewDeployStage = "validating" | "creating" | "created" | "archiving" | "archived" | "uploading" | "uploaded" | "publishing" | "publish_recovering" | "checking_status" | "ready";
59
+ interface RiddlePreviewDeployProgressSnapshot {
60
+ stage: RiddlePreviewDeployStage;
61
+ label: string;
62
+ framework: RiddlePreviewFramework;
63
+ directory: string;
64
+ elapsed_ms: number;
65
+ id?: string;
66
+ preview_url?: string;
67
+ file_count?: number;
68
+ total_bytes?: number;
69
+ tarball_bytes?: number;
70
+ attempt?: number;
71
+ attempts?: number;
72
+ status?: string | null;
73
+ publish_error?: string;
74
+ warnings?: string[];
75
+ message?: string;
76
+ }
57
77
  interface RiddlePreviewDeployResult {
58
78
  ok: true;
59
79
  id: string;
@@ -151,4 +171,4 @@ declare function createRiddleApiClient(config?: RiddleClientConfig): {
151
171
  pollJob: (jobId: string, options?: RiddlePollJobOptions) => Promise<RiddlePollJobResult>;
152
172
  };
153
173
 
154
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, type RiddleApiKeySource, type RiddleBalanceResult, type RiddleClientConfig, type RiddleFetch, type RiddlePollJobOptions, type RiddlePollJobResult, type RiddlePollProgressSnapshot, type RiddlePollSummary, type RiddlePreviewDeployResult, type RiddlePreviewFramework, type RiddleRunScriptInput, type RiddleServerPreviewInput, type RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview };
174
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, type RiddleApiKeySource, type RiddleBalanceResult, type RiddleClientConfig, type RiddleFetch, type RiddlePollJobOptions, type RiddlePollJobResult, type RiddlePollProgressSnapshot, type RiddlePollSummary, type RiddlePreviewDeployProgressSnapshot, type RiddlePreviewDeployResult, type RiddlePreviewDeployStage, type RiddlePreviewFramework, type RiddleRunScriptInput, type RiddleServerPreviewInput, type RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview };
@@ -15,7 +15,7 @@ import {
15
15
  riddleRequestJson,
16
16
  runRiddleScript,
17
17
  runRiddleServerPreview
18
- } from "./chunk-TWTEUS7R.js";
18
+ } from "./chunk-DI2XNGEZ.js";
19
19
  import "./chunk-MLKGABMK.js";
20
20
  export {
21
21
  DEFAULT_RIDDLE_API_BASE_URL,
@@ -132,10 +132,68 @@ function previewDeployResultFromRecord(input) {
132
132
  function canRecoverPreviewPublish(error) {
133
133
  return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
134
134
  }
135
+ function summarizePreviewDirectory(directory) {
136
+ const stack = [directory];
137
+ let fileCount = 0;
138
+ let totalBytes = 0;
139
+ while (stack.length) {
140
+ const current = stack.pop();
141
+ for (const entry of (0, import_node_fs.readdirSync)(current, { withFileTypes: true })) {
142
+ const fullPath = import_node_path.default.join(current, entry.name);
143
+ if (entry.isDirectory()) {
144
+ stack.push(fullPath);
145
+ continue;
146
+ }
147
+ if (!entry.isFile()) continue;
148
+ const stat = (0, import_node_fs.statSync)(fullPath);
149
+ fileCount += 1;
150
+ totalBytes += stat.size;
151
+ }
152
+ }
153
+ return { file_count: fileCount, total_bytes: totalBytes };
154
+ }
155
+ function previewProgressEmitter(config, base) {
156
+ return async (snapshot) => {
157
+ if (!config.onPreviewProgress) return;
158
+ await config.onPreviewProgress({
159
+ label: base.label,
160
+ framework: base.framework,
161
+ directory: base.directory,
162
+ elapsed_ms: Math.max(0, Date.now() - base.startedAt),
163
+ warnings: base.warnings?.length ? base.warnings : void 0,
164
+ ...snapshot
165
+ });
166
+ };
167
+ }
135
168
  async function waitForPublishedPreview(config, input) {
169
+ await input.emitProgress?.({
170
+ stage: "publish_recovering",
171
+ id: input.id,
172
+ file_count: input.localSummary?.file_count,
173
+ total_bytes: input.localSummary?.total_bytes,
174
+ publish_error: input.publishError.message,
175
+ message: `publish returned ${input.publishError.status}; polling preview status`
176
+ });
136
177
  for (let attempt = 1; attempt <= PREVIEW_PUBLISH_RECOVERY_ATTEMPTS; attempt += 1) {
137
178
  const status = await riddleRequestJson(config, `/v1/preview/${input.id}`);
179
+ await input.emitProgress?.({
180
+ stage: "checking_status",
181
+ id: input.id,
182
+ attempt,
183
+ attempts: PREVIEW_PUBLISH_RECOVERY_ATTEMPTS,
184
+ status: typeof status.status === "string" ? status.status : null,
185
+ preview_url: typeof status.preview_url === "string" ? status.preview_url : void 0,
186
+ file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
187
+ total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
188
+ });
138
189
  if (String(status.status || "") === "ready" && String(status.preview_url || "").trim()) {
190
+ await input.emitProgress?.({
191
+ stage: "ready",
192
+ id: input.id,
193
+ preview_url: String(status.preview_url),
194
+ file_count: typeof status.file_count === "number" ? status.file_count : input.localSummary?.file_count,
195
+ total_bytes: typeof status.total_bytes === "number" ? status.total_bytes : input.localSummary?.total_bytes
196
+ });
139
197
  return previewDeployResultFromRecord({
140
198
  record: status,
141
199
  id: input.id,
@@ -157,7 +215,17 @@ async function deployRiddlePreview(config, directory, label, framework = "static
157
215
  if (!directory?.trim()) throw new Error("directory is required");
158
216
  if (!label?.trim()) throw new Error("label is required");
159
217
  if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
218
+ const startedAt = Date.now();
160
219
  const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
220
+ const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
221
+ await emitProgress({ stage: "validating", message: "checking preview input directory" });
222
+ const localSummary = summarizePreviewDirectory(directory);
223
+ await emitProgress({
224
+ stage: "creating",
225
+ file_count: localSummary.file_count,
226
+ total_bytes: localSummary.total_bytes,
227
+ message: "creating preview upload target"
228
+ });
161
229
  const created = await riddleRequestJson(config, "/v1/preview", {
162
230
  method: "POST",
163
231
  body: JSON.stringify({ framework, label })
@@ -165,10 +233,42 @@ async function deployRiddlePreview(config, directory, label, framework = "static
165
233
  const id = String(created.id || "");
166
234
  const uploadUrl = String(created.upload_url || "");
167
235
  if (!id || !uploadUrl) throw new Error("Riddle preview create response was missing id or upload_url.");
236
+ await emitProgress({
237
+ stage: "created",
238
+ id,
239
+ file_count: localSummary.file_count,
240
+ total_bytes: localSummary.total_bytes,
241
+ message: "preview upload target created"
242
+ });
168
243
  const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-preview-upload-"));
169
244
  const tarball = import_node_path.default.join(scratch, `${id}.tar.gz`);
245
+ let tarballBytes = 0;
170
246
  try {
247
+ await emitProgress({
248
+ stage: "archiving",
249
+ id,
250
+ file_count: localSummary.file_count,
251
+ total_bytes: localSummary.total_bytes,
252
+ message: "creating preview archive"
253
+ });
171
254
  (0, import_node_child_process.execFileSync)("tar", ["czf", tarball, "-C", directory, "."], { stdio: "pipe" });
255
+ tarballBytes = (0, import_node_fs.statSync)(tarball).size;
256
+ await emitProgress({
257
+ stage: "archived",
258
+ id,
259
+ file_count: localSummary.file_count,
260
+ total_bytes: localSummary.total_bytes,
261
+ tarball_bytes: tarballBytes,
262
+ message: "preview archive created"
263
+ });
264
+ await emitProgress({
265
+ stage: "uploading",
266
+ id,
267
+ file_count: localSummary.file_count,
268
+ total_bytes: localSummary.total_bytes,
269
+ tarball_bytes: tarballBytes,
270
+ message: "uploading preview archive"
271
+ });
172
272
  const upload = await fetchFor(config)(uploadUrl, {
173
273
  method: "PUT",
174
274
  headers: { "Content-Type": "application/gzip" },
@@ -177,14 +277,37 @@ async function deployRiddlePreview(config, directory, label, framework = "static
177
277
  if (!upload.ok) {
178
278
  throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
179
279
  }
280
+ await emitProgress({
281
+ stage: "uploaded",
282
+ id,
283
+ file_count: localSummary.file_count,
284
+ total_bytes: localSummary.total_bytes,
285
+ tarball_bytes: tarballBytes,
286
+ message: "preview archive uploaded"
287
+ });
180
288
  } finally {
181
289
  (0, import_node_fs.rmSync)(scratch, { recursive: true, force: true });
182
290
  }
183
291
  const expiresAt = typeof created.expires_at === "string" ? created.expires_at : void 0;
184
292
  try {
293
+ await emitProgress({
294
+ stage: "publishing",
295
+ id,
296
+ file_count: localSummary.file_count,
297
+ total_bytes: localSummary.total_bytes,
298
+ tarball_bytes: tarballBytes || void 0,
299
+ message: "publishing preview"
300
+ });
185
301
  const published = await riddleRequestJson(config, `/v1/preview/${id}/publish`, {
186
302
  method: "POST"
187
303
  });
304
+ await emitProgress({
305
+ stage: "ready",
306
+ id,
307
+ preview_url: String(published.preview_url || ""),
308
+ file_count: typeof published.file_count === "number" ? published.file_count : localSummary.file_count,
309
+ total_bytes: typeof published.total_bytes === "number" ? published.total_bytes : localSummary.total_bytes
310
+ });
188
311
  return previewDeployResultFromRecord({ record: published, id, label, framework, expiresAt, warnings });
189
312
  } catch (error) {
190
313
  if (!canRecoverPreviewPublish(error)) throw error;
@@ -194,7 +317,9 @@ async function deployRiddlePreview(config, directory, label, framework = "static
194
317
  framework,
195
318
  expiresAt,
196
319
  publishError: error,
197
- warnings
320
+ warnings,
321
+ localSummary,
322
+ emitProgress
198
323
  });
199
324
  }
200
325
  }
@@ -1 +1 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.cjs';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.cjs';
@@ -1 +1 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.js';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.js';
@@ -15,7 +15,7 @@ import {
15
15
  riddleRequestJson,
16
16
  runRiddleScript,
17
17
  runRiddleServerPreview
18
- } from "../chunk-TWTEUS7R.js";
18
+ } from "../chunk-DI2XNGEZ.js";
19
19
  import "../chunk-MLKGABMK.js";
20
20
  export {
21
21
  DEFAULT_RIDDLE_API_BASE_URL,