@riddledc/riddle-proof 0.7.131 → 0.7.133

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.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  profileStatusExitCode,
13
13
  resolveRiddleProofProfileTargetUrl,
14
14
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-ZYD2SGEM.js";
15
+ } from "./chunk-TA2KLHMX.js";
16
16
  import {
17
17
  createRiddleApiClient,
18
18
  parseRiddleViewport
@@ -605,6 +605,19 @@ function profileSetupSummaryMarkdown(result) {
605
605
  const observedPath = cliString(viewport.observed_path);
606
606
  lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
607
607
  }
608
+ const failedDetails = viewports.flatMap((viewport) => {
609
+ const name = cliString(viewport.name) || "viewport";
610
+ const failed = Array.isArray(viewport.failed) ? viewport.failed.map(cliRecord).filter((item) => Boolean(item)) : [];
611
+ return failed.map((failure) => ({ name, failure }));
612
+ });
613
+ for (const { name, failure } of failedDetails.slice(0, 8)) {
614
+ const action = cliString(failure.action) || "setup_action";
615
+ const selector = cliString(failure.selector);
616
+ const reason = cliString(failure.reason);
617
+ const caseInsensitiveText = cliString(failure.case_insensitive_text);
618
+ lines.push(`- failed ${name}: ${action}${selector ? ` ${markdownInlineCode(selector)}` : ""}${reason ? ` reason ${markdownInlineCode(reason)}` : ""}${caseInsensitiveText ? `; case-insensitive sample ${markdownInlineCode(caseInsensitiveText, 140)}` : ""}`);
619
+ }
620
+ if (failedDetails.length > 8) lines.push(`- ${failedDetails.length - 8} additional failed setup action(s) omitted.`);
608
621
  if (viewports.length > 8) lines.push(`- ${viewports.length - 8} additional viewport(s) omitted from setup summary.`);
609
622
  return lines;
610
623
  }
package/dist/index.cjs CHANGED
@@ -8794,7 +8794,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8794
8794
  "wait",
8795
8795
  "wait_for_selector",
8796
8796
  "wait_for_text",
8797
- "window_call"
8797
+ "window_call",
8798
+ "window_call_until"
8798
8799
  ];
8799
8800
  var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
8800
8801
  "aborted",
@@ -9248,14 +9249,16 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9248
9249
  action: profileSetupResultAction(result),
9249
9250
  selector: result.selector ?? null,
9250
9251
  frame_selector: result.frame_selector ?? null,
9251
- reason: result.reason ?? result.error ?? null
9252
+ reason: result.reason ?? result.error ?? null,
9253
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text)
9252
9254
  })),
9253
9255
  optional_failed: optionalFailed.map((result) => ({
9254
9256
  ordinal: result.ordinal ?? null,
9255
9257
  action: profileSetupResultAction(result),
9256
9258
  selector: result.selector ?? null,
9257
9259
  frame_selector: result.frame_selector ?? null,
9258
- reason: result.reason ?? result.error ?? null
9260
+ reason: result.reason ?? result.error ?? null,
9261
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text)
9259
9262
  }))
9260
9263
  };
9261
9264
  })
@@ -9291,7 +9294,7 @@ function isSupportedCheckType(value) {
9291
9294
  }
9292
9295
  function normalizeSetupActionType(value, index) {
9293
9296
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
9294
- 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 === "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;
9297
+ 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 === "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;
9295
9298
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
9296
9299
  return normalized;
9297
9300
  }
@@ -9422,10 +9425,10 @@ function normalizeSetupAction(input, index) {
9422
9425
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
9423
9426
  }
9424
9427
  const path6 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
9425
- if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path6) {
9428
+ if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path6) {
9426
9429
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
9427
9430
  }
9428
- const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
9431
+ const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
9429
9432
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
9430
9433
  if (type === "assert_window_value" && !hasExpectedValue) {
9431
9434
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -9442,6 +9445,24 @@ function normalizeSetupAction(input, index) {
9442
9445
  }
9443
9446
  }
9444
9447
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
9448
+ const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
9449
+ const hasUntilExpectedValue = hasOwn(input, "until_expected_value") || hasOwn(input, "untilExpectedValue") || hasOwn(input, "until_expected") || hasOwn(input, "untilExpected") || hasOwn(input, "until_value") || hasOwn(input, "untilValue") || hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected");
9450
+ if (type === "window_call_until") {
9451
+ if (!untilPath) {
9452
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
9453
+ }
9454
+ if (!hasUntilExpectedValue) {
9455
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
9456
+ }
9457
+ }
9458
+ const maxCalls = numberValue3(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
9459
+ if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
9460
+ throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
9461
+ }
9462
+ const intervalMs = numberValue3(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
9463
+ if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
9464
+ throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
9465
+ }
9445
9466
  const steps = numberValue3(input.steps);
9446
9467
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
9447
9468
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -9468,6 +9489,10 @@ function normalizeSetupAction(input, index) {
9468
9489
  path: path6,
9469
9490
  args,
9470
9491
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
9492
+ until_path: untilPath,
9493
+ until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
9494
+ max_calls: maxCalls,
9495
+ interval_ms: intervalMs,
9471
9496
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
9472
9497
  min_value: minValue,
9473
9498
  max_value: maxValue,
@@ -12420,6 +12445,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
12420
12445
  selector: result.selector ?? null,
12421
12446
  frame_selector: result.frame_selector ?? null,
12422
12447
  reason: result.reason || result.error || null,
12448
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text),
12423
12449
  })),
12424
12450
  optional_failed: optionalFailed.map((result) => ({
12425
12451
  ordinal: result.ordinal ?? null,
@@ -12427,6 +12453,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
12427
12453
  selector: result.selector ?? null,
12428
12454
  frame_selector: result.frame_selector ?? null,
12429
12455
  reason: result.reason || result.error || null,
12456
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text),
12430
12457
  })),
12431
12458
  };
12432
12459
  }),
@@ -13342,6 +13369,34 @@ async function setupReadWindowValue(context, path) {
13342
13369
  return { ok: true, value: toJsonValue(current) };
13343
13370
  }, { path });
13344
13371
  }
13372
+ async function setupCallWindowFunction(context, path, args) {
13373
+ return await context.evaluate(async ({ path, args }) => {
13374
+ const toJsonValue = (value) => {
13375
+ if (value === null || value === undefined) return null;
13376
+ if (typeof value === "string" || typeof value === "boolean") return value;
13377
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
13378
+ if (Array.isArray(value)) return value.map(toJsonValue);
13379
+ if (typeof value === "object") {
13380
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
13381
+ }
13382
+ return String(value);
13383
+ };
13384
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
13385
+ let parent = window;
13386
+ let current = window;
13387
+ for (const part of pathParts) {
13388
+ parent = current;
13389
+ current = current?.[part];
13390
+ }
13391
+ if (typeof current !== "function") return { ok: false, reason: "missing_function" };
13392
+ try {
13393
+ const returned = await current.apply(parent, Array.isArray(args) ? args : []);
13394
+ return { ok: true, returned: toJsonValue(returned) };
13395
+ } catch (error) {
13396
+ return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
13397
+ }
13398
+ }, { path, args });
13399
+ }
13345
13400
  function setupFrameSelector(action) {
13346
13401
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
13347
13402
  }
@@ -13859,32 +13914,7 @@ async function executeSetupAction(action, ordinal, viewport) {
13859
13914
  if (!path) return { ...base, path, reason: "missing_path" };
13860
13915
  const scope = await setupActionScope(action, timeout);
13861
13916
  if (!scope.ok) return setupScopeFailure(base, scope);
13862
- const result = await scope.context.evaluate(async ({ path, args }) => {
13863
- const toJsonValue = (value) => {
13864
- if (value === null || value === undefined) return null;
13865
- if (typeof value === "string" || typeof value === "boolean") return value;
13866
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
13867
- if (Array.isArray(value)) return value.map(toJsonValue);
13868
- if (typeof value === "object") {
13869
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
13870
- }
13871
- return String(value);
13872
- };
13873
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
13874
- let parent = window;
13875
- let current = window;
13876
- for (const part of pathParts) {
13877
- parent = current;
13878
- current = current?.[part];
13879
- }
13880
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
13881
- try {
13882
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
13883
- return { ok: true, returned: toJsonValue(returned) };
13884
- } catch (error) {
13885
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
13886
- }
13887
- }, { path, args });
13917
+ const result = await setupCallWindowFunction(scope.context, path, args);
13888
13918
  const hasExpectation = setupHasOwn(action, "expect_return")
13889
13919
  || setupHasOwn(action, "expectReturn")
13890
13920
  || setupHasOwn(action, "expected_return")
@@ -13909,6 +13939,126 @@ async function executeSetupAction(action, ordinal, viewport) {
13909
13939
  error: result.error || undefined,
13910
13940
  };
13911
13941
  }
13942
+ if (type === "window_call_until") {
13943
+ const path = String(action.path || action.function_path || action.functionPath || "");
13944
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
13945
+ const args = Array.isArray(action.args) ? action.args : [];
13946
+ if (!path) return { ...base, path, reason: "missing_path" };
13947
+ if (!untilPath) return { ...base, path, reason: "missing_until_path" };
13948
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
13949
+ || setupHasOwn(action, "untilExpectedValue")
13950
+ || setupHasOwn(action, "until_expected")
13951
+ || setupHasOwn(action, "untilExpected")
13952
+ || setupHasOwn(action, "until_value")
13953
+ || setupHasOwn(action, "untilValue")
13954
+ || setupHasOwn(action, "expected_value")
13955
+ || setupHasOwn(action, "expectedValue")
13956
+ || setupHasOwn(action, "expected");
13957
+ const untilExpected = setupHasOwn(action, "until_expected_value")
13958
+ ? action.until_expected_value
13959
+ : setupHasOwn(action, "untilExpectedValue")
13960
+ ? action.untilExpectedValue
13961
+ : setupHasOwn(action, "until_expected")
13962
+ ? action.until_expected
13963
+ : setupHasOwn(action, "untilExpected")
13964
+ ? action.untilExpected
13965
+ : setupHasOwn(action, "until_value")
13966
+ ? action.until_value
13967
+ : setupHasOwn(action, "untilValue")
13968
+ ? action.untilValue
13969
+ : setupHasOwn(action, "expected_value")
13970
+ ? action.expected_value
13971
+ : setupHasOwn(action, "expectedValue")
13972
+ ? action.expectedValue
13973
+ : action.expected;
13974
+ if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
13975
+ const maxCalls = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
13976
+ const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.call_interval_ms ?? action.callIntervalMs, 100) || 0)));
13977
+ const hasReturnExpectation = setupHasOwn(action, "expect_return")
13978
+ || setupHasOwn(action, "expectReturn")
13979
+ || setupHasOwn(action, "expected_return")
13980
+ || setupHasOwn(action, "expectedReturn");
13981
+ const expectedReturn = setupHasOwn(action, "expect_return")
13982
+ ? action.expect_return
13983
+ : setupHasOwn(action, "expectReturn")
13984
+ ? action.expectReturn
13985
+ : setupHasOwn(action, "expected_return")
13986
+ ? action.expected_return
13987
+ : action.expectedReturn;
13988
+ const scope = await setupActionScope(action, timeout);
13989
+ if (!scope.ok) return setupScopeFailure(base, scope);
13990
+ const startedAt = Date.now();
13991
+ let callCount = 0;
13992
+ let lastCallResult = null;
13993
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
13994
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
13995
+ return {
13996
+ ...base,
13997
+ ...setupScopeEvidence(scope),
13998
+ ok: true,
13999
+ path,
14000
+ arg_count: args.length,
14001
+ until_path: untilPath,
14002
+ until_value: setupJsonValue(lastPredicateResult.value),
14003
+ until_expected_value: setupJsonValue(untilExpected),
14004
+ call_count: callCount,
14005
+ max_calls: maxCalls,
14006
+ interval_ms: intervalMs,
14007
+ timeout_ms: timeout,
14008
+ };
14009
+ }
14010
+ while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
14011
+ lastCallResult = await setupCallWindowFunction(scope.context, path, args);
14012
+ callCount += 1;
14013
+ if (!lastCallResult.ok) break;
14014
+ if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
14015
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
14016
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
14017
+ return {
14018
+ ...base,
14019
+ ...setupScopeEvidence(scope),
14020
+ ok: true,
14021
+ path,
14022
+ arg_count: args.length,
14023
+ returned: setupJsonValue(lastCallResult.returned),
14024
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
14025
+ until_path: untilPath,
14026
+ until_value: setupJsonValue(lastPredicateResult.value),
14027
+ until_expected_value: setupJsonValue(untilExpected),
14028
+ call_count: callCount,
14029
+ max_calls: maxCalls,
14030
+ interval_ms: intervalMs,
14031
+ timeout_ms: timeout,
14032
+ };
14033
+ }
14034
+ if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
14035
+ }
14036
+ const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
14037
+ return {
14038
+ ...base,
14039
+ ...setupScopeEvidence(scope),
14040
+ path,
14041
+ arg_count: args.length,
14042
+ returned: setupJsonValue(lastCallResult?.returned),
14043
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
14044
+ until_path: untilPath,
14045
+ until_value: setupJsonValue(lastPredicateResult?.value),
14046
+ until_expected_value: setupJsonValue(untilExpected),
14047
+ call_count: callCount,
14048
+ max_calls: maxCalls,
14049
+ interval_ms: intervalMs,
14050
+ timeout_ms: timeout,
14051
+ reason: lastCallResult && !lastCallResult.ok
14052
+ ? lastCallResult.reason
14053
+ : hasReturnExpectation && !returnExpectationMet
14054
+ ? "unexpected_return_value"
14055
+ : Date.now() - startedAt > timeout
14056
+ ? "timeout"
14057
+ : "until_condition_not_met",
14058
+ error: lastCallResult?.error || undefined,
14059
+ missing_part: lastPredicateResult?.missing_part || undefined,
14060
+ };
14061
+ }
13912
14062
  if (type === "assert_window_value") {
13913
14063
  const path = String(action.path || action.window_path || action.windowPath || "");
13914
14064
  const hasExpected = setupHasOwn(action, "expected_value")
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-ZYD2SGEM.js";
65
+ } from "./chunk-TA2KLHMX.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -108,7 +108,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
108
108
  "wait",
109
109
  "wait_for_selector",
110
110
  "wait_for_text",
111
- "window_call"
111
+ "window_call",
112
+ "window_call_until"
112
113
  ];
113
114
  var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
114
115
  "aborted",
@@ -562,14 +563,16 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
562
563
  action: profileSetupResultAction(result),
563
564
  selector: result.selector ?? null,
564
565
  frame_selector: result.frame_selector ?? null,
565
- reason: result.reason ?? result.error ?? null
566
+ reason: result.reason ?? result.error ?? null,
567
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text)
566
568
  })),
567
569
  optional_failed: optionalFailed.map((result) => ({
568
570
  ordinal: result.ordinal ?? null,
569
571
  action: profileSetupResultAction(result),
570
572
  selector: result.selector ?? null,
571
573
  frame_selector: result.frame_selector ?? null,
572
- reason: result.reason ?? result.error ?? null
574
+ reason: result.reason ?? result.error ?? null,
575
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text)
573
576
  }))
574
577
  };
575
578
  })
@@ -605,7 +608,7 @@ function isSupportedCheckType(value) {
605
608
  }
606
609
  function normalizeSetupActionType(value, index) {
607
610
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
608
- 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 === "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;
611
+ 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 === "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;
609
612
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
610
613
  return normalized;
611
614
  }
@@ -736,10 +739,10 @@ function normalizeSetupAction(input, index) {
736
739
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
737
740
  }
738
741
  const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
739
- if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path) {
742
+ if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
740
743
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
741
744
  }
742
- const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
745
+ const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
743
746
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
744
747
  if (type === "assert_window_value" && !hasExpectedValue) {
745
748
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -756,6 +759,24 @@ function normalizeSetupAction(input, index) {
756
759
  }
757
760
  }
758
761
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
762
+ const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
763
+ const hasUntilExpectedValue = hasOwn(input, "until_expected_value") || hasOwn(input, "untilExpectedValue") || hasOwn(input, "until_expected") || hasOwn(input, "untilExpected") || hasOwn(input, "until_value") || hasOwn(input, "untilValue") || hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected");
764
+ if (type === "window_call_until") {
765
+ if (!untilPath) {
766
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
767
+ }
768
+ if (!hasUntilExpectedValue) {
769
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
770
+ }
771
+ }
772
+ const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
773
+ if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
774
+ throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
775
+ }
776
+ const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
777
+ if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
778
+ throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
779
+ }
759
780
  const steps = numberValue(input.steps);
760
781
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
761
782
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -782,6 +803,10 @@ function normalizeSetupAction(input, index) {
782
803
  path,
783
804
  args,
784
805
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
806
+ until_path: untilPath,
807
+ until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
808
+ max_calls: maxCalls,
809
+ interval_ms: intervalMs,
785
810
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
786
811
  min_value: minValue,
787
812
  max_value: maxValue,
@@ -3734,6 +3759,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
3734
3759
  selector: result.selector ?? null,
3735
3760
  frame_selector: result.frame_selector ?? null,
3736
3761
  reason: result.reason || result.error || null,
3762
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text),
3737
3763
  })),
3738
3764
  optional_failed: optionalFailed.map((result) => ({
3739
3765
  ordinal: result.ordinal ?? null,
@@ -3741,6 +3767,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
3741
3767
  selector: result.selector ?? null,
3742
3768
  frame_selector: result.frame_selector ?? null,
3743
3769
  reason: result.reason || result.error || null,
3770
+ case_insensitive_text: compactProfileSetupSummaryText(result.case_insensitive_text),
3744
3771
  })),
3745
3772
  };
3746
3773
  }),
@@ -4656,6 +4683,34 @@ async function setupReadWindowValue(context, path) {
4656
4683
  return { ok: true, value: toJsonValue(current) };
4657
4684
  }, { path });
4658
4685
  }
4686
+ async function setupCallWindowFunction(context, path, args) {
4687
+ return await context.evaluate(async ({ path, args }) => {
4688
+ const toJsonValue = (value) => {
4689
+ if (value === null || value === undefined) return null;
4690
+ if (typeof value === "string" || typeof value === "boolean") return value;
4691
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
4692
+ if (Array.isArray(value)) return value.map(toJsonValue);
4693
+ if (typeof value === "object") {
4694
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
4695
+ }
4696
+ return String(value);
4697
+ };
4698
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
4699
+ let parent = window;
4700
+ let current = window;
4701
+ for (const part of pathParts) {
4702
+ parent = current;
4703
+ current = current?.[part];
4704
+ }
4705
+ if (typeof current !== "function") return { ok: false, reason: "missing_function" };
4706
+ try {
4707
+ const returned = await current.apply(parent, Array.isArray(args) ? args : []);
4708
+ return { ok: true, returned: toJsonValue(returned) };
4709
+ } catch (error) {
4710
+ return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
4711
+ }
4712
+ }, { path, args });
4713
+ }
4659
4714
  function setupFrameSelector(action) {
4660
4715
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
4661
4716
  }
@@ -5173,32 +5228,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5173
5228
  if (!path) return { ...base, path, reason: "missing_path" };
5174
5229
  const scope = await setupActionScope(action, timeout);
5175
5230
  if (!scope.ok) return setupScopeFailure(base, scope);
5176
- const result = await scope.context.evaluate(async ({ path, args }) => {
5177
- const toJsonValue = (value) => {
5178
- if (value === null || value === undefined) return null;
5179
- if (typeof value === "string" || typeof value === "boolean") return value;
5180
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
5181
- if (Array.isArray(value)) return value.map(toJsonValue);
5182
- if (typeof value === "object") {
5183
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
5184
- }
5185
- return String(value);
5186
- };
5187
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
5188
- let parent = window;
5189
- let current = window;
5190
- for (const part of pathParts) {
5191
- parent = current;
5192
- current = current?.[part];
5193
- }
5194
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
5195
- try {
5196
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
5197
- return { ok: true, returned: toJsonValue(returned) };
5198
- } catch (error) {
5199
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
5200
- }
5201
- }, { path, args });
5231
+ const result = await setupCallWindowFunction(scope.context, path, args);
5202
5232
  const hasExpectation = setupHasOwn(action, "expect_return")
5203
5233
  || setupHasOwn(action, "expectReturn")
5204
5234
  || setupHasOwn(action, "expected_return")
@@ -5223,6 +5253,126 @@ async function executeSetupAction(action, ordinal, viewport) {
5223
5253
  error: result.error || undefined,
5224
5254
  };
5225
5255
  }
5256
+ if (type === "window_call_until") {
5257
+ const path = String(action.path || action.function_path || action.functionPath || "");
5258
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
5259
+ const args = Array.isArray(action.args) ? action.args : [];
5260
+ if (!path) return { ...base, path, reason: "missing_path" };
5261
+ if (!untilPath) return { ...base, path, reason: "missing_until_path" };
5262
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
5263
+ || setupHasOwn(action, "untilExpectedValue")
5264
+ || setupHasOwn(action, "until_expected")
5265
+ || setupHasOwn(action, "untilExpected")
5266
+ || setupHasOwn(action, "until_value")
5267
+ || setupHasOwn(action, "untilValue")
5268
+ || setupHasOwn(action, "expected_value")
5269
+ || setupHasOwn(action, "expectedValue")
5270
+ || setupHasOwn(action, "expected");
5271
+ const untilExpected = setupHasOwn(action, "until_expected_value")
5272
+ ? action.until_expected_value
5273
+ : setupHasOwn(action, "untilExpectedValue")
5274
+ ? action.untilExpectedValue
5275
+ : setupHasOwn(action, "until_expected")
5276
+ ? action.until_expected
5277
+ : setupHasOwn(action, "untilExpected")
5278
+ ? action.untilExpected
5279
+ : setupHasOwn(action, "until_value")
5280
+ ? action.until_value
5281
+ : setupHasOwn(action, "untilValue")
5282
+ ? action.untilValue
5283
+ : setupHasOwn(action, "expected_value")
5284
+ ? action.expected_value
5285
+ : setupHasOwn(action, "expectedValue")
5286
+ ? action.expectedValue
5287
+ : action.expected;
5288
+ if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
5289
+ const maxCalls = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
5290
+ const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.call_interval_ms ?? action.callIntervalMs, 100) || 0)));
5291
+ const hasReturnExpectation = setupHasOwn(action, "expect_return")
5292
+ || setupHasOwn(action, "expectReturn")
5293
+ || setupHasOwn(action, "expected_return")
5294
+ || setupHasOwn(action, "expectedReturn");
5295
+ const expectedReturn = setupHasOwn(action, "expect_return")
5296
+ ? action.expect_return
5297
+ : setupHasOwn(action, "expectReturn")
5298
+ ? action.expectReturn
5299
+ : setupHasOwn(action, "expected_return")
5300
+ ? action.expected_return
5301
+ : action.expectedReturn;
5302
+ const scope = await setupActionScope(action, timeout);
5303
+ if (!scope.ok) return setupScopeFailure(base, scope);
5304
+ const startedAt = Date.now();
5305
+ let callCount = 0;
5306
+ let lastCallResult = null;
5307
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
5308
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
5309
+ return {
5310
+ ...base,
5311
+ ...setupScopeEvidence(scope),
5312
+ ok: true,
5313
+ path,
5314
+ arg_count: args.length,
5315
+ until_path: untilPath,
5316
+ until_value: setupJsonValue(lastPredicateResult.value),
5317
+ until_expected_value: setupJsonValue(untilExpected),
5318
+ call_count: callCount,
5319
+ max_calls: maxCalls,
5320
+ interval_ms: intervalMs,
5321
+ timeout_ms: timeout,
5322
+ };
5323
+ }
5324
+ while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
5325
+ lastCallResult = await setupCallWindowFunction(scope.context, path, args);
5326
+ callCount += 1;
5327
+ if (!lastCallResult.ok) break;
5328
+ if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
5329
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
5330
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
5331
+ return {
5332
+ ...base,
5333
+ ...setupScopeEvidence(scope),
5334
+ ok: true,
5335
+ path,
5336
+ arg_count: args.length,
5337
+ returned: setupJsonValue(lastCallResult.returned),
5338
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
5339
+ until_path: untilPath,
5340
+ until_value: setupJsonValue(lastPredicateResult.value),
5341
+ until_expected_value: setupJsonValue(untilExpected),
5342
+ call_count: callCount,
5343
+ max_calls: maxCalls,
5344
+ interval_ms: intervalMs,
5345
+ timeout_ms: timeout,
5346
+ };
5347
+ }
5348
+ if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
5349
+ }
5350
+ const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
5351
+ return {
5352
+ ...base,
5353
+ ...setupScopeEvidence(scope),
5354
+ path,
5355
+ arg_count: args.length,
5356
+ returned: setupJsonValue(lastCallResult?.returned),
5357
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
5358
+ until_path: untilPath,
5359
+ until_value: setupJsonValue(lastPredicateResult?.value),
5360
+ until_expected_value: setupJsonValue(untilExpected),
5361
+ call_count: callCount,
5362
+ max_calls: maxCalls,
5363
+ interval_ms: intervalMs,
5364
+ timeout_ms: timeout,
5365
+ reason: lastCallResult && !lastCallResult.ok
5366
+ ? lastCallResult.reason
5367
+ : hasReturnExpectation && !returnExpectationMet
5368
+ ? "unexpected_return_value"
5369
+ : Date.now() - startedAt > timeout
5370
+ ? "timeout"
5371
+ : "until_condition_not_met",
5372
+ error: lastCallResult?.error || undefined,
5373
+ missing_part: lastPredicateResult?.missing_part || undefined,
5374
+ };
5375
+ }
5226
5376
  if (type === "assert_window_value") {
5227
5377
  const path = String(action.path || action.window_path || action.windowPath || "");
5228
5378
  const hasExpected = setupHasOwn(action, "expected_value")