@riddledc/riddle-proof 0.7.159 → 0.7.161

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/cli.cjs CHANGED
@@ -7006,6 +7006,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
7006
7006
  "fill",
7007
7007
  "set_input_value",
7008
7008
  "set_range_value",
7009
+ "canvas_signature",
7009
7010
  "assert_text_visible",
7010
7011
  "assert_text_absent",
7011
7012
  "assert_selector_count",
@@ -7507,6 +7508,26 @@ function profileSetupRangeValueReceipts(results) {
7507
7508
  reason: result.reason ?? result.error ?? null
7508
7509
  }));
7509
7510
  }
7511
+ function profileSetupCanvasSignatureReceipts(results) {
7512
+ return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
7513
+ ordinal: result.ordinal ?? null,
7514
+ ok: result.ok !== false,
7515
+ selector: result.selector ?? null,
7516
+ frame_selector: result.frame_selector ?? null,
7517
+ label: result.label ?? null,
7518
+ hash: result.hash ?? null,
7519
+ data_length: result.data_length ?? null,
7520
+ width: result.width ?? null,
7521
+ height: result.height ?? null,
7522
+ css_width: result.css_width ?? null,
7523
+ css_height: result.css_height ?? null,
7524
+ compare_to: result.compare_to ?? null,
7525
+ previous_hash: result.previous_hash ?? null,
7526
+ changed: result.changed ?? null,
7527
+ return_stored_to: result.return_stored_to ?? null,
7528
+ reason: result.reason ?? result.error ?? null
7529
+ }));
7530
+ }
7510
7531
  function sampleProfileSetupSummaryItems(items, limit) {
7511
7532
  if (items.length <= limit) return items;
7512
7533
  const firstCount = Math.floor(limit / 2);
@@ -7551,6 +7572,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
7551
7572
  const sampledWindowEvalReceipts = sampleProfileSetupSummaryItems(windowEvalReceipts, 8);
7552
7573
  const rangeValueReceipts = profileSetupRangeValueReceipts(results);
7553
7574
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
7575
+ const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
7576
+ const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
7554
7577
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
7555
7578
  const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
7556
7579
  return {
@@ -7602,6 +7625,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
7602
7625
  set_range_value_total: rangeValueReceipts.length,
7603
7626
  set_range_value_truncated: rangeValueReceipts.length > sampledRangeValueReceipts.length,
7604
7627
  set_range_value: sampledRangeValueReceipts,
7628
+ canvas_signature_total: canvasSignatureReceipts.length,
7629
+ canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
7630
+ canvas_signature: sampledCanvasSignatureReceipts,
7605
7631
  clicked,
7606
7632
  text_samples,
7607
7633
  failed: failed.map((result) => ({
@@ -7654,7 +7680,7 @@ function isSupportedCheckType(value) {
7654
7680
  }
7655
7681
  function normalizeSetupActionType(value, index) {
7656
7682
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
7657
- const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
7683
+ const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
7658
7684
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
7659
7685
  return normalized;
7660
7686
  }
@@ -7783,7 +7809,7 @@ function normalizeSetupAction(input, index) {
7783
7809
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
7784
7810
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
7785
7811
  }
7786
- if ((type === "click" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
7812
+ if ((type === "click" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
7787
7813
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
7788
7814
  }
7789
7815
  const fromX = numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
@@ -7877,7 +7903,11 @@ function normalizeSetupAction(input, index) {
7877
7903
  "assign_return_to",
7878
7904
  "assignReturnTo",
7879
7905
  "return_state_path",
7880
- "returnStatePath"
7906
+ "returnStatePath",
7907
+ "store_signature_to",
7908
+ "storeSignatureTo",
7909
+ "signature_path",
7910
+ "signaturePath"
7881
7911
  );
7882
7912
  const captureReturn = input.capture_return === false || input.captureReturn === false || input.include_return === false || input.includeReturn === false || input.omit_return === true || input.omitReturn === true ? false : void 0;
7883
7913
  const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
@@ -7929,6 +7959,8 @@ function normalizeSetupAction(input, index) {
7929
7959
  store_return_to: storeReturnTo,
7930
7960
  capture_return: captureReturn,
7931
7961
  return_summary_fields: normalizeReturnSummaryFields(input, index),
7962
+ compare_to: stringFromOwn(input, "compare_to", "compareTo", "previous_signature_path", "previousSignaturePath", "previous_path", "previousPath", "changed_from", "changedFrom"),
7963
+ expect_changed: booleanValue(valueFromOwn(input, "expect_changed", "expectChanged", "should_change", "shouldChange", "changed")),
7932
7964
  until_path: untilPath,
7933
7965
  until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
7934
7966
  max_calls: maxCalls,
@@ -11039,6 +11071,28 @@ function profileSetupRangeValueReceipts(results) {
11039
11071
  reason: result.reason || result.error || null,
11040
11072
  }));
11041
11073
  }
11074
+ function profileSetupCanvasSignatureReceipts(results) {
11075
+ return (results || [])
11076
+ .filter((result) => result && profileSetupResultAction(result) === "canvas_signature")
11077
+ .map((result) => ({
11078
+ ordinal: result.ordinal ?? null,
11079
+ ok: result.ok !== false,
11080
+ selector: result.selector ?? null,
11081
+ frame_selector: result.frame_selector ?? null,
11082
+ label: result.label ?? null,
11083
+ hash: result.hash ?? null,
11084
+ data_length: result.data_length ?? null,
11085
+ width: result.width ?? null,
11086
+ height: result.height ?? null,
11087
+ css_width: result.css_width ?? null,
11088
+ css_height: result.css_height ?? null,
11089
+ compare_to: result.compare_to ?? null,
11090
+ previous_hash: result.previous_hash ?? null,
11091
+ changed: result.changed ?? null,
11092
+ return_stored_to: result.return_stored_to ?? null,
11093
+ reason: result.reason || result.error || null,
11094
+ }));
11095
+ }
11042
11096
  function sampleProfileSetupSummaryItems(items, limit) {
11043
11097
  if ((items || []).length <= limit) return items || [];
11044
11098
  const firstCount = Math.floor(limit / 2);
@@ -11097,6 +11151,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
11097
11151
  const sampledWindowEvalReceipts = sampleProfileSetupSummaryItems(windowEvalReceipts, 8);
11098
11152
  const rangeValueReceipts = profileSetupRangeValueReceipts(results);
11099
11153
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
11154
+ const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
11155
+ const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
11100
11156
  const clickedItems = results
11101
11157
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
11102
11158
  .map((result) => {
@@ -11158,6 +11214,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
11158
11214
  set_range_value_total: rangeValueReceipts.length,
11159
11215
  set_range_value_truncated: rangeValueReceipts.length > sampledRangeValueReceipts.length,
11160
11216
  set_range_value: sampledRangeValueReceipts,
11217
+ canvas_signature_total: canvasSignatureReceipts.length,
11218
+ canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
11219
+ canvas_signature: sampledCanvasSignatureReceipts,
11161
11220
  clicked,
11162
11221
  text_samples: textSamples,
11163
11222
  failed: failed.map((result) => ({
@@ -12632,6 +12691,54 @@ async function executeSetupAction(action, ordinal, viewport) {
12632
12691
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12633
12692
  const rect = element.getBoundingClientRect();
12634
12693
  const pointerId = payload.pointerType === "touch" ? 11 : 12;
12694
+ const capturedPointers = new Set();
12695
+ const originalOwnSetPointerCapture = Object.getOwnPropertyDescriptor(element, "setPointerCapture");
12696
+ const originalOwnReleasePointerCapture = Object.getOwnPropertyDescriptor(element, "releasePointerCapture");
12697
+ const originalOwnHasPointerCapture = Object.getOwnPropertyDescriptor(element, "hasPointerCapture");
12698
+ const originalSetPointerCapture = typeof element.setPointerCapture === "function" ? element.setPointerCapture.bind(element) : undefined;
12699
+ const originalReleasePointerCapture = typeof element.releasePointerCapture === "function" ? element.releasePointerCapture.bind(element) : undefined;
12700
+ const originalHasPointerCapture = typeof element.hasPointerCapture === "function" ? element.hasPointerCapture.bind(element) : undefined;
12701
+ const restorePointerCapture = () => {
12702
+ if (originalOwnSetPointerCapture) Object.defineProperty(element, "setPointerCapture", originalOwnSetPointerCapture);
12703
+ else delete (element as any).setPointerCapture;
12704
+ if (originalOwnReleasePointerCapture) Object.defineProperty(element, "releasePointerCapture", originalOwnReleasePointerCapture);
12705
+ else delete (element as any).releasePointerCapture;
12706
+ if (originalOwnHasPointerCapture) Object.defineProperty(element, "hasPointerCapture", originalOwnHasPointerCapture);
12707
+ else delete (element as any).hasPointerCapture;
12708
+ };
12709
+ Object.defineProperty(element, "setPointerCapture", {
12710
+ configurable: true,
12711
+ value: (activePointerId) => {
12712
+ capturedPointers.add(activePointerId);
12713
+ try {
12714
+ return originalSetPointerCapture?.(activePointerId);
12715
+ } catch {
12716
+ return undefined;
12717
+ }
12718
+ },
12719
+ });
12720
+ Object.defineProperty(element, "releasePointerCapture", {
12721
+ configurable: true,
12722
+ value: (activePointerId) => {
12723
+ capturedPointers.delete(activePointerId);
12724
+ try {
12725
+ return originalReleasePointerCapture?.(activePointerId);
12726
+ } catch {
12727
+ return undefined;
12728
+ }
12729
+ },
12730
+ });
12731
+ Object.defineProperty(element, "hasPointerCapture", {
12732
+ configurable: true,
12733
+ value: (activePointerId) => {
12734
+ if (capturedPointers.has(activePointerId)) return true;
12735
+ try {
12736
+ return Boolean(originalHasPointerCapture?.(activePointerId));
12737
+ } catch {
12738
+ return false;
12739
+ }
12740
+ },
12741
+ });
12635
12742
  const point = (progress) => ({
12636
12743
  clientX: rect.left + payload.start.x + (payload.end.x - payload.start.x) * progress,
12637
12744
  clientY: rect.top + payload.start.y + (payload.end.y - payload.start.y) * progress,
@@ -12651,16 +12758,20 @@ async function executeSetupAction(action, ordinal, viewport) {
12651
12758
  clientY: coords.clientY,
12652
12759
  }));
12653
12760
  };
12654
- dispatch("pointerover", 0);
12655
- dispatch("pointerenter", 0);
12656
- dispatch("pointerdown", 0);
12657
- for (let step = 1; step <= payload.steps; step += 1) {
12658
- dispatch("pointermove", step / payload.steps);
12659
- if (payload.durationMs && payload.steps > 1) await wait(payload.durationMs / payload.steps);
12761
+ try {
12762
+ dispatch("pointerover", 0);
12763
+ dispatch("pointerenter", 0);
12764
+ dispatch("pointerdown", 0);
12765
+ for (let step = 1; step <= payload.steps; step += 1) {
12766
+ dispatch("pointermove", step / payload.steps);
12767
+ if (payload.durationMs && payload.steps > 1) await wait(payload.durationMs / payload.steps);
12768
+ }
12769
+ dispatch("pointerup", 1);
12770
+ dispatch("pointerout", 1);
12771
+ dispatch("pointerleave", 1);
12772
+ } finally {
12773
+ restorePointerCapture();
12660
12774
  }
12661
- dispatch("pointerup", 1);
12662
- dispatch("pointerout", 1);
12663
- dispatch("pointerleave", 1);
12664
12775
  }, {
12665
12776
  pointerType,
12666
12777
  start: localStart,
@@ -12700,6 +12811,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12700
12811
  to_x: toX,
12701
12812
  to_y: toY,
12702
12813
  pointer_type: pointerType,
12814
+ pointer_capture_polyfill: pointerType === "touch" || pointerType === "pen" ? true : undefined,
12703
12815
  steps,
12704
12816
  duration_ms: durationMs || undefined,
12705
12817
  };
@@ -13173,6 +13285,156 @@ async function executeSetupAction(action, ordinal, viewport) {
13173
13285
  reason: rangeResult && rangeResult.ok === true ? undefined : rangeResult?.reason || "range_value_not_set",
13174
13286
  };
13175
13287
  }
13288
+ if (type === "canvas_signature") {
13289
+ const scope = await setupActionScope(action, timeout);
13290
+ if (!scope.ok) return setupScopeFailure(base, scope);
13291
+ const locator = scope.context.locator(action.selector);
13292
+ const count = await locator.count();
13293
+ if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
13294
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
13295
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
13296
+ const target = locator.nth(targetIndex);
13297
+ await target.waitFor({ state: "visible", timeout });
13298
+ const storeReturnTo = String(action.store_return_to || action.storeReturnTo || action.save_return_to || action.saveReturnTo || action.store_signature_to || action.storeSignatureTo || action.signature_path || action.signaturePath || "").trim();
13299
+ const compareTo = String(action.compare_to || action.compareTo || action.previous_signature_path || action.previousSignaturePath || action.previous_path || action.previousPath || action.changed_from || action.changedFrom || "").trim();
13300
+ const expectChanged = action.expect_changed === true || action.expectChanged === true || action.should_change === true || action.shouldChange === true || action.changed === true
13301
+ ? true
13302
+ : action.expect_changed === false || action.expectChanged === false || action.should_change === false || action.shouldChange === false || action.changed === false
13303
+ ? false
13304
+ : undefined;
13305
+ const signatureResult = await target.evaluate((element, payload) => {
13306
+ const toJsonValue = (value) => {
13307
+ if (value === null || value === undefined) return null;
13308
+ if (typeof value === "string" || typeof value === "boolean") return value;
13309
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
13310
+ if (Array.isArray(value)) return value.map(toJsonValue);
13311
+ if (typeof value === "object") {
13312
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
13313
+ }
13314
+ return String(value);
13315
+ };
13316
+ const pathParts = (path) => String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
13317
+ const readWindowPath = (path) => {
13318
+ const parts = pathParts(path);
13319
+ if (parts[0] === "window") parts.shift();
13320
+ if (!parts.length) return { ok: false, reason: "missing_path" };
13321
+ let current = window;
13322
+ for (const part of parts) {
13323
+ if (current === null || current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
13324
+ current = current[part];
13325
+ if (current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
13326
+ }
13327
+ return { ok: true, value: toJsonValue(current) };
13328
+ };
13329
+ const storeWindowValue = (path, value) => {
13330
+ const parts = pathParts(path);
13331
+ if (parts[0] === "window") parts.shift();
13332
+ if (!parts.length) return { ok: false, reason: "missing_store_path" };
13333
+ let target = window;
13334
+ for (let index = 0; index < parts.length - 1; index += 1) {
13335
+ const part = parts[index];
13336
+ if (target[part] === null || typeof target[part] !== "object") target[part] = {};
13337
+ target = target[part];
13338
+ }
13339
+ target[parts[parts.length - 1]] = value;
13340
+ return { ok: true, path: parts.join(".") };
13341
+ };
13342
+ const hashText = (text) => {
13343
+ let hash = 2166136261;
13344
+ const step = Math.max(1, Math.floor((text.length || 1) / 4000));
13345
+ for (let index = 0; index < text.length; index += step) {
13346
+ hash ^= text.charCodeAt(index);
13347
+ hash = Math.imul(hash, 16777619) >>> 0;
13348
+ }
13349
+ return String(hash);
13350
+ };
13351
+ const tag = String(element && element.tagName ? element.tagName : "").toLowerCase();
13352
+ if (tag !== "canvas") return { ok: false, reason: "not_canvas_element", tag };
13353
+ const rect = element.getBoundingClientRect();
13354
+ let data = "";
13355
+ try {
13356
+ data = element.toDataURL("image/png");
13357
+ } catch (error) {
13358
+ return {
13359
+ ok: false,
13360
+ reason: "canvas_read_failed",
13361
+ error: String(error && error.message ? error.message : error).slice(0, 1000),
13362
+ width: element.width || 0,
13363
+ height: element.height || 0,
13364
+ css_width: Math.round(rect.width || 0),
13365
+ css_height: Math.round(rect.height || 0),
13366
+ };
13367
+ }
13368
+ const result = {
13369
+ ok: Boolean(element.width > 0 && element.height > 0 && data.length > 0),
13370
+ reason: element.width > 0 && element.height > 0 && data.length > 0 ? undefined : "empty_canvas_signature",
13371
+ hash: hashText(data),
13372
+ data_length: data.length,
13373
+ width: element.width || 0,
13374
+ height: element.height || 0,
13375
+ css_width: Math.round(rect.width || 0),
13376
+ css_height: Math.round(rect.height || 0),
13377
+ compare_to: payload.compareTo || undefined,
13378
+ previous_hash: null,
13379
+ changed: null,
13380
+ };
13381
+ if (payload.compareTo) {
13382
+ const previous = readWindowPath(payload.compareTo);
13383
+ if (!previous.ok) {
13384
+ result.ok = false;
13385
+ result.reason = previous.reason || "compare_path_not_found";
13386
+ result.missing_part = previous.missing_part || undefined;
13387
+ } else {
13388
+ const previousValue = previous.value;
13389
+ const previousHash = previousValue && typeof previousValue === "object" && !Array.isArray(previousValue)
13390
+ ? previousValue.hash || previousValue.signature || previousValue.canvas_hash || null
13391
+ : typeof previousValue === "string"
13392
+ ? previousValue
13393
+ : null;
13394
+ result.previous_hash = previousHash === null || previousHash === undefined ? null : String(previousHash);
13395
+ result.changed = result.previous_hash === null ? null : result.previous_hash !== result.hash;
13396
+ if (payload.expectChanged === true && result.changed !== true) {
13397
+ result.ok = false;
13398
+ result.reason = "canvas_signature_unchanged";
13399
+ } else if (payload.expectChanged === false && result.changed !== false) {
13400
+ result.ok = false;
13401
+ result.reason = "canvas_signature_changed";
13402
+ }
13403
+ }
13404
+ }
13405
+ if (payload.storeReturnTo) {
13406
+ const stored = storeWindowValue(payload.storeReturnTo, result);
13407
+ if (!stored.ok) {
13408
+ return { ...result, ok: false, reason: "signature_store_failed", store_reason: stored.reason };
13409
+ }
13410
+ return { ...result, return_stored_to: stored.path };
13411
+ }
13412
+ return result;
13413
+ }, { compareTo, expectChanged, storeReturnTo });
13414
+ return {
13415
+ ...base,
13416
+ ...setupScopeEvidence(scope),
13417
+ ok: signatureResult && signatureResult.ok === true,
13418
+ count,
13419
+ target_index: targetIndex,
13420
+ label: action.label || action.name || undefined,
13421
+ hash: signatureResult?.hash,
13422
+ data_length: signatureResult?.data_length,
13423
+ width: signatureResult?.width,
13424
+ height: signatureResult?.height,
13425
+ css_width: signatureResult?.css_width,
13426
+ css_height: signatureResult?.css_height,
13427
+ compare_to: signatureResult?.compare_to || compareTo || undefined,
13428
+ previous_hash: signatureResult?.previous_hash,
13429
+ changed: signatureResult?.changed,
13430
+ return_stored_to: signatureResult?.return_stored_to || storeReturnTo || undefined,
13431
+ missing_part: signatureResult?.missing_part || undefined,
13432
+ store_reason: signatureResult?.store_reason || undefined,
13433
+ tag: signatureResult?.tag,
13434
+ reason: signatureResult && signatureResult.ok === true ? undefined : signatureResult?.reason || "canvas_signature_failed",
13435
+ error: signatureResult?.error || undefined,
13436
+ };
13437
+ }
13176
13438
  if (type === "assert_selector_count") {
13177
13439
  const scope = await setupActionScope(action, timeout);
13178
13440
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -15412,22 +15674,34 @@ function balancedSetupReceiptDetails(groups, limit) {
15412
15674
  const total = groups.reduce((sum, group) => sum + group.length, 0);
15413
15675
  if (total <= limit) return groups.flat();
15414
15676
  const selected = [];
15677
+ const selectedKeys = /* @__PURE__ */ new Set();
15415
15678
  const indexes = new Array(groups.length).fill(0);
15416
15679
  const nonEmptyIndexes = groups.map((group, index) => group.length ? index : -1).filter((index) => index >= 0);
15680
+ const pushReceipt = (groupIndex, itemIndex, advance = true) => {
15681
+ const receipt = groups[groupIndex][itemIndex];
15682
+ if (!receipt) return false;
15683
+ const key = `${groupIndex}:${itemIndex}`;
15684
+ if (selectedKeys.has(key)) return false;
15685
+ selected.push(receipt);
15686
+ selectedKeys.add(key);
15687
+ if (advance) indexes[groupIndex] = Math.max(indexes[groupIndex], itemIndex + 1);
15688
+ return true;
15689
+ };
15417
15690
  for (const index of nonEmptyIndexes) {
15418
15691
  if (selected.length >= limit) return selected;
15419
- selected.push(groups[index][0]);
15420
- indexes[index] = 1;
15692
+ pushReceipt(index, 0);
15693
+ }
15694
+ for (const index of nonEmptyIndexes) {
15695
+ if (selected.length >= limit) return selected;
15696
+ const lastIndex = groups[index].length - 1;
15697
+ if (lastIndex > 0) pushReceipt(index, lastIndex, false);
15421
15698
  }
15422
15699
  while (selected.length < limit) {
15423
15700
  let progressed = false;
15424
15701
  for (const index of nonEmptyIndexes) {
15425
15702
  const nextIndex = indexes[index];
15426
- const next = groups[index][nextIndex];
15427
- if (!next) continue;
15428
- selected.push(next);
15429
- indexes[index] = nextIndex + 1;
15430
- progressed = true;
15703
+ if (nextIndex >= groups[index].length) continue;
15704
+ progressed = pushReceipt(index, nextIndex) || progressed;
15431
15705
  if (selected.length >= limit) break;
15432
15706
  }
15433
15707
  if (!progressed) break;
@@ -15538,6 +15812,7 @@ function profileSetupSummaryMarkdown(result) {
15538
15812
  const windowCallUntilTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_total) || 0), 0);
15539
15813
  const windowCallUntilCallTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_call_total) || 0), 0);
15540
15814
  const rangeValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.set_range_value_total) || 0), 0);
15815
+ const canvasSignatureTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.canvas_signature_total) || 0), 0);
15541
15816
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
15542
15817
  const lines = [
15543
15818
  `- setup actions: ${declaredActions === void 0 ? "unknown" : declaredActions} declared, ${totalResults} recorded result(s) across ${viewports.length} viewport(s)`,
@@ -15560,6 +15835,9 @@ function profileSetupSummaryMarkdown(result) {
15560
15835
  if (rangeValueTotal) {
15561
15836
  lines.push(`- set_range_value: ${rangeValueTotal} action(s)`);
15562
15837
  }
15838
+ if (canvasSignatureTotal) {
15839
+ lines.push(`- canvas_signature: ${canvasSignatureTotal} action(s)`);
15840
+ }
15563
15841
  for (const viewport of viewports.slice(0, 8)) {
15564
15842
  const name = cliString(viewport.name) || "viewport";
15565
15843
  const ok = viewport.ok === false ? "failed" : "ok";
@@ -15576,9 +15854,37 @@ function profileSetupSummaryMarkdown(result) {
15576
15854
  const windowCallUntilActions = cliFiniteNumber(viewport.window_call_until_total) || 0;
15577
15855
  const windowCallUntilCalls = cliFiniteNumber(viewport.window_call_until_call_total) || 0;
15578
15856
  const rangeValueActions = cliFiniteNumber(viewport.set_range_value_total) || 0;
15857
+ const canvasSignatureActions = cliFiniteNumber(viewport.canvas_signature_total) || 0;
15579
15858
  const observedPath = cliString(viewport.observed_path);
15580
- lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
15859
+ lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${canvasSignatureActions ? `, ${canvasSignatureActions} canvas_signature action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
15860
+ }
15861
+ const canvasSignatureGroups = viewports.map((viewport) => {
15862
+ const name = cliString(viewport.name) || "viewport";
15863
+ const receipts = Array.isArray(viewport.canvas_signature) ? viewport.canvas_signature.map(cliRecord).filter((item) => Boolean(item)) : [];
15864
+ return receipts.map((receipt) => ({ name, receipt }));
15865
+ });
15866
+ const canvasSignatureDetails = canvasSignatureGroups.flat();
15867
+ const sampledCanvasSignatureDetails = balancedSetupReceiptDetails(canvasSignatureGroups, 12);
15868
+ for (const { name, receipt } of sampledCanvasSignatureDetails) {
15869
+ const selector = cliString(receipt.selector) || "canvas";
15870
+ const label = cliString(receipt.label);
15871
+ const hash = cliString(receipt.hash);
15872
+ const dataLength = cliFiniteNumber(receipt.data_length);
15873
+ const width = cliFiniteNumber(receipt.width);
15874
+ const height = cliFiniteNumber(receipt.height);
15875
+ const cssWidth = cliFiniteNumber(receipt.css_width);
15876
+ const cssHeight = cliFiniteNumber(receipt.css_height);
15877
+ const compareTo = cliString(receipt.compare_to);
15878
+ const previousHash = cliString(receipt.previous_hash);
15879
+ const changed = typeof receipt.changed === "boolean" ? receipt.changed : void 0;
15880
+ const storedTo = cliString(receipt.return_stored_to);
15881
+ const ok = receipt.ok === false ? "failed" : "ok";
15882
+ const reason = cliString(receipt.reason);
15883
+ const sizeText = width === void 0 || height === void 0 ? "" : `, ${width}x${height}`;
15884
+ const cssSizeText = cssWidth === void 0 || cssHeight === void 0 ? "" : `, css ${cssWidth}x${cssHeight}`;
15885
+ lines.push(`- ${name} canvas_signature: ${ok}, ${markdownInlineCode(selector)}${label ? ` ${markdownInlineCode(label, 80)}` : ""}${hash ? ` hash ${markdownInlineCode(hash, 80)}` : ""}${sizeText}${cssSizeText}${dataLength === void 0 ? "" : `, data chars ${dataLength}`}${compareTo ? `, compared ${markdownInlineCode(compareTo)}` : ""}${previousHash ? ` previous ${markdownInlineCode(previousHash, 80)}` : ""}${changed === void 0 ? "" : `, changed ${changed}`}${storedTo ? `, stored ${markdownInlineCode(storedTo)}` : ""}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
15581
15886
  }
15887
+ if (canvasSignatureDetails.length > sampledCanvasSignatureDetails.length) lines.push(`- ${canvasSignatureDetails.length - sampledCanvasSignatureDetails.length} additional canvas_signature receipt(s) omitted.`);
15582
15888
  const rangeValueGroups = viewports.map((viewport) => {
15583
15889
  const name = cliString(viewport.name) || "viewport";
15584
15890
  const receipts = Array.isArray(viewport.set_range_value) ? viewport.set_range_value.map(cliRecord).filter((item) => Boolean(item)) : [];
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  profileStatusExitCode,
14
14
  resolveRiddleProofProfileTargetUrl,
15
15
  resolveRiddleProofProfileTimeoutSec
16
- } from "./chunk-TBTMD5WV.js";
16
+ } from "./chunk-ZE2U5EML.js";
17
17
  import {
18
18
  createRiddleApiClient,
19
19
  isTerminalRiddleJobStatus,
@@ -649,22 +649,34 @@ function balancedSetupReceiptDetails(groups, limit) {
649
649
  const total = groups.reduce((sum, group) => sum + group.length, 0);
650
650
  if (total <= limit) return groups.flat();
651
651
  const selected = [];
652
+ const selectedKeys = /* @__PURE__ */ new Set();
652
653
  const indexes = new Array(groups.length).fill(0);
653
654
  const nonEmptyIndexes = groups.map((group, index) => group.length ? index : -1).filter((index) => index >= 0);
655
+ const pushReceipt = (groupIndex, itemIndex, advance = true) => {
656
+ const receipt = groups[groupIndex][itemIndex];
657
+ if (!receipt) return false;
658
+ const key = `${groupIndex}:${itemIndex}`;
659
+ if (selectedKeys.has(key)) return false;
660
+ selected.push(receipt);
661
+ selectedKeys.add(key);
662
+ if (advance) indexes[groupIndex] = Math.max(indexes[groupIndex], itemIndex + 1);
663
+ return true;
664
+ };
665
+ for (const index of nonEmptyIndexes) {
666
+ if (selected.length >= limit) return selected;
667
+ pushReceipt(index, 0);
668
+ }
654
669
  for (const index of nonEmptyIndexes) {
655
670
  if (selected.length >= limit) return selected;
656
- selected.push(groups[index][0]);
657
- indexes[index] = 1;
671
+ const lastIndex = groups[index].length - 1;
672
+ if (lastIndex > 0) pushReceipt(index, lastIndex, false);
658
673
  }
659
674
  while (selected.length < limit) {
660
675
  let progressed = false;
661
676
  for (const index of nonEmptyIndexes) {
662
677
  const nextIndex = indexes[index];
663
- const next = groups[index][nextIndex];
664
- if (!next) continue;
665
- selected.push(next);
666
- indexes[index] = nextIndex + 1;
667
- progressed = true;
678
+ if (nextIndex >= groups[index].length) continue;
679
+ progressed = pushReceipt(index, nextIndex) || progressed;
668
680
  if (selected.length >= limit) break;
669
681
  }
670
682
  if (!progressed) break;
@@ -775,6 +787,7 @@ function profileSetupSummaryMarkdown(result) {
775
787
  const windowCallUntilTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_total) || 0), 0);
776
788
  const windowCallUntilCallTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_call_total) || 0), 0);
777
789
  const rangeValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.set_range_value_total) || 0), 0);
790
+ const canvasSignatureTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.canvas_signature_total) || 0), 0);
778
791
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
779
792
  const lines = [
780
793
  `- setup actions: ${declaredActions === void 0 ? "unknown" : declaredActions} declared, ${totalResults} recorded result(s) across ${viewports.length} viewport(s)`,
@@ -797,6 +810,9 @@ function profileSetupSummaryMarkdown(result) {
797
810
  if (rangeValueTotal) {
798
811
  lines.push(`- set_range_value: ${rangeValueTotal} action(s)`);
799
812
  }
813
+ if (canvasSignatureTotal) {
814
+ lines.push(`- canvas_signature: ${canvasSignatureTotal} action(s)`);
815
+ }
800
816
  for (const viewport of viewports.slice(0, 8)) {
801
817
  const name = cliString(viewport.name) || "viewport";
802
818
  const ok = viewport.ok === false ? "failed" : "ok";
@@ -813,9 +829,37 @@ function profileSetupSummaryMarkdown(result) {
813
829
  const windowCallUntilActions = cliFiniteNumber(viewport.window_call_until_total) || 0;
814
830
  const windowCallUntilCalls = cliFiniteNumber(viewport.window_call_until_call_total) || 0;
815
831
  const rangeValueActions = cliFiniteNumber(viewport.set_range_value_total) || 0;
832
+ const canvasSignatureActions = cliFiniteNumber(viewport.canvas_signature_total) || 0;
816
833
  const observedPath = cliString(viewport.observed_path);
817
- lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
834
+ lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${canvasSignatureActions ? `, ${canvasSignatureActions} canvas_signature action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
835
+ }
836
+ const canvasSignatureGroups = viewports.map((viewport) => {
837
+ const name = cliString(viewport.name) || "viewport";
838
+ const receipts = Array.isArray(viewport.canvas_signature) ? viewport.canvas_signature.map(cliRecord).filter((item) => Boolean(item)) : [];
839
+ return receipts.map((receipt) => ({ name, receipt }));
840
+ });
841
+ const canvasSignatureDetails = canvasSignatureGroups.flat();
842
+ const sampledCanvasSignatureDetails = balancedSetupReceiptDetails(canvasSignatureGroups, 12);
843
+ for (const { name, receipt } of sampledCanvasSignatureDetails) {
844
+ const selector = cliString(receipt.selector) || "canvas";
845
+ const label = cliString(receipt.label);
846
+ const hash = cliString(receipt.hash);
847
+ const dataLength = cliFiniteNumber(receipt.data_length);
848
+ const width = cliFiniteNumber(receipt.width);
849
+ const height = cliFiniteNumber(receipt.height);
850
+ const cssWidth = cliFiniteNumber(receipt.css_width);
851
+ const cssHeight = cliFiniteNumber(receipt.css_height);
852
+ const compareTo = cliString(receipt.compare_to);
853
+ const previousHash = cliString(receipt.previous_hash);
854
+ const changed = typeof receipt.changed === "boolean" ? receipt.changed : void 0;
855
+ const storedTo = cliString(receipt.return_stored_to);
856
+ const ok = receipt.ok === false ? "failed" : "ok";
857
+ const reason = cliString(receipt.reason);
858
+ const sizeText = width === void 0 || height === void 0 ? "" : `, ${width}x${height}`;
859
+ const cssSizeText = cssWidth === void 0 || cssHeight === void 0 ? "" : `, css ${cssWidth}x${cssHeight}`;
860
+ lines.push(`- ${name} canvas_signature: ${ok}, ${markdownInlineCode(selector)}${label ? ` ${markdownInlineCode(label, 80)}` : ""}${hash ? ` hash ${markdownInlineCode(hash, 80)}` : ""}${sizeText}${cssSizeText}${dataLength === void 0 ? "" : `, data chars ${dataLength}`}${compareTo ? `, compared ${markdownInlineCode(compareTo)}` : ""}${previousHash ? ` previous ${markdownInlineCode(previousHash, 80)}` : ""}${changed === void 0 ? "" : `, changed ${changed}`}${storedTo ? `, stored ${markdownInlineCode(storedTo)}` : ""}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
818
861
  }
862
+ if (canvasSignatureDetails.length > sampledCanvasSignatureDetails.length) lines.push(`- ${canvasSignatureDetails.length - sampledCanvasSignatureDetails.length} additional canvas_signature receipt(s) omitted.`);
819
863
  const rangeValueGroups = viewports.map((viewport) => {
820
864
  const name = cliString(viewport.name) || "viewport";
821
865
  const receipts = Array.isArray(viewport.set_range_value) ? viewport.set_range_value.map(cliRecord).filter((item) => Boolean(item)) : [];