@riddledc/riddle-proof 0.7.132 → 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/README.md CHANGED
@@ -401,7 +401,7 @@ transport control, or other bounded interaction. Supported setup actions are
401
401
  `assert_text_absent`, `assert_selector_count`, `assert_window_value`,
402
402
  `assert_window_number`, `local_storage`, `session_storage`, `clear_storage`,
403
403
  `clear_console`, `screenshot`, `wait`, `wait_for_selector`, `wait_for_text`,
404
- and `window_call`;
404
+ `window_call`, and `window_call_until`;
405
405
  a failed setup action is recorded as a failed `setup_actions_succeeded` check so
406
406
  the profile cannot pass without reaching the intended state. Text-matched `click` actions prefer
407
407
  visible matching elements, which keeps responsive layouts from selecting hidden
@@ -447,6 +447,11 @@ errors, but keeps network mock hit evidence intact. Any setup action can include
447
447
  with `repeat_index` and `repeat_count`, and `after_ms` runs after each
448
448
  repetition. Use it for bounded game proof helpers, retry controls, or other
449
449
  workflows where one declarative action needs to advance the app several times.
450
+ Use `window_call_until` when a proof helper needs to advance randomized or
451
+ progressive state until a window-state receipt is true. It accepts `path` plus
452
+ optional `args`, `until_path`, `until_expected_value`, `max_calls` from 1 to
453
+ 100, and optional `interval_ms`; the action stops early when the predicate is
454
+ met and records `call_count`, final `returned`, and final `until_value`.
450
455
  Use `screenshot` with an optional `label` to capture durable Riddle screenshots
451
456
  at important setup milestones, such as after a route switch, terminal state, or
452
457
  reset. These labels are recorded in setup evidence and included in profile
@@ -61,7 +61,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
61
61
  "wait",
62
62
  "wait_for_selector",
63
63
  "wait_for_text",
64
- "window_call"
64
+ "window_call",
65
+ "window_call_until"
65
66
  ];
66
67
  var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
67
68
  "aborted",
@@ -560,7 +561,7 @@ function isSupportedCheckType(value) {
560
561
  }
561
562
  function normalizeSetupActionType(value, index) {
562
563
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
563
- 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;
564
+ 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;
564
565
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
565
566
  return normalized;
566
567
  }
@@ -691,10 +692,10 @@ function normalizeSetupAction(input, index) {
691
692
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
692
693
  }
693
694
  const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
694
- if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path) {
695
+ if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
695
696
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
696
697
  }
697
- const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
698
+ const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
698
699
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
699
700
  if (type === "assert_window_value" && !hasExpectedValue) {
700
701
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -711,6 +712,24 @@ function normalizeSetupAction(input, index) {
711
712
  }
712
713
  }
713
714
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
715
+ const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
716
+ 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");
717
+ if (type === "window_call_until") {
718
+ if (!untilPath) {
719
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
720
+ }
721
+ if (!hasUntilExpectedValue) {
722
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
723
+ }
724
+ }
725
+ const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
726
+ if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
727
+ throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
728
+ }
729
+ const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
730
+ if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
731
+ throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
732
+ }
714
733
  const steps = numberValue(input.steps);
715
734
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
716
735
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -737,6 +756,10 @@ function normalizeSetupAction(input, index) {
737
756
  path,
738
757
  args,
739
758
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
759
+ until_path: untilPath,
760
+ until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
761
+ max_calls: maxCalls,
762
+ interval_ms: intervalMs,
740
763
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
741
764
  min_value: minValue,
742
765
  max_value: maxValue,
@@ -4613,6 +4636,34 @@ async function setupReadWindowValue(context, path) {
4613
4636
  return { ok: true, value: toJsonValue(current) };
4614
4637
  }, { path });
4615
4638
  }
4639
+ async function setupCallWindowFunction(context, path, args) {
4640
+ return await context.evaluate(async ({ path, args }) => {
4641
+ const toJsonValue = (value) => {
4642
+ if (value === null || value === undefined) return null;
4643
+ if (typeof value === "string" || typeof value === "boolean") return value;
4644
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
4645
+ if (Array.isArray(value)) return value.map(toJsonValue);
4646
+ if (typeof value === "object") {
4647
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
4648
+ }
4649
+ return String(value);
4650
+ };
4651
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
4652
+ let parent = window;
4653
+ let current = window;
4654
+ for (const part of pathParts) {
4655
+ parent = current;
4656
+ current = current?.[part];
4657
+ }
4658
+ if (typeof current !== "function") return { ok: false, reason: "missing_function" };
4659
+ try {
4660
+ const returned = await current.apply(parent, Array.isArray(args) ? args : []);
4661
+ return { ok: true, returned: toJsonValue(returned) };
4662
+ } catch (error) {
4663
+ return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
4664
+ }
4665
+ }, { path, args });
4666
+ }
4616
4667
  function setupFrameSelector(action) {
4617
4668
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
4618
4669
  }
@@ -5130,32 +5181,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5130
5181
  if (!path) return { ...base, path, reason: "missing_path" };
5131
5182
  const scope = await setupActionScope(action, timeout);
5132
5183
  if (!scope.ok) return setupScopeFailure(base, scope);
5133
- const result = await scope.context.evaluate(async ({ path, args }) => {
5134
- const toJsonValue = (value) => {
5135
- if (value === null || value === undefined) return null;
5136
- if (typeof value === "string" || typeof value === "boolean") return value;
5137
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
5138
- if (Array.isArray(value)) return value.map(toJsonValue);
5139
- if (typeof value === "object") {
5140
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
5141
- }
5142
- return String(value);
5143
- };
5144
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
5145
- let parent = window;
5146
- let current = window;
5147
- for (const part of pathParts) {
5148
- parent = current;
5149
- current = current?.[part];
5150
- }
5151
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
5152
- try {
5153
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
5154
- return { ok: true, returned: toJsonValue(returned) };
5155
- } catch (error) {
5156
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
5157
- }
5158
- }, { path, args });
5184
+ const result = await setupCallWindowFunction(scope.context, path, args);
5159
5185
  const hasExpectation = setupHasOwn(action, "expect_return")
5160
5186
  || setupHasOwn(action, "expectReturn")
5161
5187
  || setupHasOwn(action, "expected_return")
@@ -5180,6 +5206,126 @@ async function executeSetupAction(action, ordinal, viewport) {
5180
5206
  error: result.error || undefined,
5181
5207
  };
5182
5208
  }
5209
+ if (type === "window_call_until") {
5210
+ const path = String(action.path || action.function_path || action.functionPath || "");
5211
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
5212
+ const args = Array.isArray(action.args) ? action.args : [];
5213
+ if (!path) return { ...base, path, reason: "missing_path" };
5214
+ if (!untilPath) return { ...base, path, reason: "missing_until_path" };
5215
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
5216
+ || setupHasOwn(action, "untilExpectedValue")
5217
+ || setupHasOwn(action, "until_expected")
5218
+ || setupHasOwn(action, "untilExpected")
5219
+ || setupHasOwn(action, "until_value")
5220
+ || setupHasOwn(action, "untilValue")
5221
+ || setupHasOwn(action, "expected_value")
5222
+ || setupHasOwn(action, "expectedValue")
5223
+ || setupHasOwn(action, "expected");
5224
+ const untilExpected = setupHasOwn(action, "until_expected_value")
5225
+ ? action.until_expected_value
5226
+ : setupHasOwn(action, "untilExpectedValue")
5227
+ ? action.untilExpectedValue
5228
+ : setupHasOwn(action, "until_expected")
5229
+ ? action.until_expected
5230
+ : setupHasOwn(action, "untilExpected")
5231
+ ? action.untilExpected
5232
+ : setupHasOwn(action, "until_value")
5233
+ ? action.until_value
5234
+ : setupHasOwn(action, "untilValue")
5235
+ ? action.untilValue
5236
+ : setupHasOwn(action, "expected_value")
5237
+ ? action.expected_value
5238
+ : setupHasOwn(action, "expectedValue")
5239
+ ? action.expectedValue
5240
+ : action.expected;
5241
+ if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
5242
+ 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)));
5243
+ 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)));
5244
+ const hasReturnExpectation = setupHasOwn(action, "expect_return")
5245
+ || setupHasOwn(action, "expectReturn")
5246
+ || setupHasOwn(action, "expected_return")
5247
+ || setupHasOwn(action, "expectedReturn");
5248
+ const expectedReturn = setupHasOwn(action, "expect_return")
5249
+ ? action.expect_return
5250
+ : setupHasOwn(action, "expectReturn")
5251
+ ? action.expectReturn
5252
+ : setupHasOwn(action, "expected_return")
5253
+ ? action.expected_return
5254
+ : action.expectedReturn;
5255
+ const scope = await setupActionScope(action, timeout);
5256
+ if (!scope.ok) return setupScopeFailure(base, scope);
5257
+ const startedAt = Date.now();
5258
+ let callCount = 0;
5259
+ let lastCallResult = null;
5260
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
5261
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
5262
+ return {
5263
+ ...base,
5264
+ ...setupScopeEvidence(scope),
5265
+ ok: true,
5266
+ path,
5267
+ arg_count: args.length,
5268
+ until_path: untilPath,
5269
+ until_value: setupJsonValue(lastPredicateResult.value),
5270
+ until_expected_value: setupJsonValue(untilExpected),
5271
+ call_count: callCount,
5272
+ max_calls: maxCalls,
5273
+ interval_ms: intervalMs,
5274
+ timeout_ms: timeout,
5275
+ };
5276
+ }
5277
+ while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
5278
+ lastCallResult = await setupCallWindowFunction(scope.context, path, args);
5279
+ callCount += 1;
5280
+ if (!lastCallResult.ok) break;
5281
+ if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
5282
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
5283
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
5284
+ return {
5285
+ ...base,
5286
+ ...setupScopeEvidence(scope),
5287
+ ok: true,
5288
+ path,
5289
+ arg_count: args.length,
5290
+ returned: setupJsonValue(lastCallResult.returned),
5291
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
5292
+ until_path: untilPath,
5293
+ until_value: setupJsonValue(lastPredicateResult.value),
5294
+ until_expected_value: setupJsonValue(untilExpected),
5295
+ call_count: callCount,
5296
+ max_calls: maxCalls,
5297
+ interval_ms: intervalMs,
5298
+ timeout_ms: timeout,
5299
+ };
5300
+ }
5301
+ if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
5302
+ }
5303
+ const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
5304
+ return {
5305
+ ...base,
5306
+ ...setupScopeEvidence(scope),
5307
+ path,
5308
+ arg_count: args.length,
5309
+ returned: setupJsonValue(lastCallResult?.returned),
5310
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
5311
+ until_path: untilPath,
5312
+ until_value: setupJsonValue(lastPredicateResult?.value),
5313
+ until_expected_value: setupJsonValue(untilExpected),
5314
+ call_count: callCount,
5315
+ max_calls: maxCalls,
5316
+ interval_ms: intervalMs,
5317
+ timeout_ms: timeout,
5318
+ reason: lastCallResult && !lastCallResult.ok
5319
+ ? lastCallResult.reason
5320
+ : hasReturnExpectation && !returnExpectationMet
5321
+ ? "unexpected_return_value"
5322
+ : Date.now() - startedAt > timeout
5323
+ ? "timeout"
5324
+ : "until_condition_not_met",
5325
+ error: lastCallResult?.error || undefined,
5326
+ missing_part: lastPredicateResult?.missing_part || undefined,
5327
+ };
5328
+ }
5183
5329
  if (type === "assert_window_value") {
5184
5330
  const path = String(action.path || action.window_path || action.windowPath || "");
5185
5331
  const hasExpected = setupHasOwn(action, "expected_value")
package/dist/cli.cjs CHANGED
@@ -6998,7 +6998,8 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
6998
6998
  "wait",
6999
6999
  "wait_for_selector",
7000
7000
  "wait_for_text",
7001
- "window_call"
7001
+ "window_call",
7002
+ "window_call_until"
7002
7003
  ];
7003
7004
  var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
7004
7005
  "aborted",
@@ -7497,7 +7498,7 @@ function isSupportedCheckType(value) {
7497
7498
  }
7498
7499
  function normalizeSetupActionType(value, index) {
7499
7500
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
7500
- 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;
7501
+ 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;
7501
7502
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
7502
7503
  return normalized;
7503
7504
  }
@@ -7628,10 +7629,10 @@ function normalizeSetupAction(input, index) {
7628
7629
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
7629
7630
  }
7630
7631
  const path7 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
7631
- if ((type === "window_call" || type === "assert_window_value" || type === "assert_window_number") && !path7) {
7632
+ if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path7) {
7632
7633
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
7633
7634
  }
7634
- const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
7635
+ const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
7635
7636
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
7636
7637
  if (type === "assert_window_value" && !hasExpectedValue) {
7637
7638
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -7648,6 +7649,24 @@ function normalizeSetupAction(input, index) {
7648
7649
  }
7649
7650
  }
7650
7651
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
7652
+ const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
7653
+ 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");
7654
+ if (type === "window_call_until") {
7655
+ if (!untilPath) {
7656
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
7657
+ }
7658
+ if (!hasUntilExpectedValue) {
7659
+ throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
7660
+ }
7661
+ }
7662
+ const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
7663
+ if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
7664
+ throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
7665
+ }
7666
+ const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
7667
+ if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
7668
+ throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
7669
+ }
7651
7670
  const steps = numberValue(input.steps);
7652
7671
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
7653
7672
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -7674,6 +7693,10 @@ function normalizeSetupAction(input, index) {
7674
7693
  path: path7,
7675
7694
  args,
7676
7695
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
7696
+ until_path: untilPath,
7697
+ until_expected_value: hasUntilExpectedValue ? toJsonValue(valueFromOwn(input, "until_expected_value", "untilExpectedValue", "until_expected", "untilExpected", "until_value", "untilValue", "expected_value", "expectedValue", "expected")) : void 0,
7698
+ max_calls: maxCalls,
7699
+ interval_ms: intervalMs,
7677
7700
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
7678
7701
  min_value: minValue,
7679
7702
  max_value: maxValue,
@@ -11534,6 +11557,34 @@ async function setupReadWindowValue(context, path) {
11534
11557
  return { ok: true, value: toJsonValue(current) };
11535
11558
  }, { path });
11536
11559
  }
11560
+ async function setupCallWindowFunction(context, path, args) {
11561
+ return await context.evaluate(async ({ path, args }) => {
11562
+ const toJsonValue = (value) => {
11563
+ if (value === null || value === undefined) return null;
11564
+ if (typeof value === "string" || typeof value === "boolean") return value;
11565
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
11566
+ if (Array.isArray(value)) return value.map(toJsonValue);
11567
+ if (typeof value === "object") {
11568
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
11569
+ }
11570
+ return String(value);
11571
+ };
11572
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
11573
+ let parent = window;
11574
+ let current = window;
11575
+ for (const part of pathParts) {
11576
+ parent = current;
11577
+ current = current?.[part];
11578
+ }
11579
+ if (typeof current !== "function") return { ok: false, reason: "missing_function" };
11580
+ try {
11581
+ const returned = await current.apply(parent, Array.isArray(args) ? args : []);
11582
+ return { ok: true, returned: toJsonValue(returned) };
11583
+ } catch (error) {
11584
+ return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
11585
+ }
11586
+ }, { path, args });
11587
+ }
11537
11588
  function setupFrameSelector(action) {
11538
11589
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
11539
11590
  }
@@ -12051,32 +12102,7 @@ async function executeSetupAction(action, ordinal, viewport) {
12051
12102
  if (!path) return { ...base, path, reason: "missing_path" };
12052
12103
  const scope = await setupActionScope(action, timeout);
12053
12104
  if (!scope.ok) return setupScopeFailure(base, scope);
12054
- const result = await scope.context.evaluate(async ({ path, args }) => {
12055
- const toJsonValue = (value) => {
12056
- if (value === null || value === undefined) return null;
12057
- if (typeof value === "string" || typeof value === "boolean") return value;
12058
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
12059
- if (Array.isArray(value)) return value.map(toJsonValue);
12060
- if (typeof value === "object") {
12061
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
12062
- }
12063
- return String(value);
12064
- };
12065
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
12066
- let parent = window;
12067
- let current = window;
12068
- for (const part of pathParts) {
12069
- parent = current;
12070
- current = current?.[part];
12071
- }
12072
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
12073
- try {
12074
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
12075
- return { ok: true, returned: toJsonValue(returned) };
12076
- } catch (error) {
12077
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
12078
- }
12079
- }, { path, args });
12105
+ const result = await setupCallWindowFunction(scope.context, path, args);
12080
12106
  const hasExpectation = setupHasOwn(action, "expect_return")
12081
12107
  || setupHasOwn(action, "expectReturn")
12082
12108
  || setupHasOwn(action, "expected_return")
@@ -12101,6 +12127,126 @@ async function executeSetupAction(action, ordinal, viewport) {
12101
12127
  error: result.error || undefined,
12102
12128
  };
12103
12129
  }
12130
+ if (type === "window_call_until") {
12131
+ const path = String(action.path || action.function_path || action.functionPath || "");
12132
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
12133
+ const args = Array.isArray(action.args) ? action.args : [];
12134
+ if (!path) return { ...base, path, reason: "missing_path" };
12135
+ if (!untilPath) return { ...base, path, reason: "missing_until_path" };
12136
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
12137
+ || setupHasOwn(action, "untilExpectedValue")
12138
+ || setupHasOwn(action, "until_expected")
12139
+ || setupHasOwn(action, "untilExpected")
12140
+ || setupHasOwn(action, "until_value")
12141
+ || setupHasOwn(action, "untilValue")
12142
+ || setupHasOwn(action, "expected_value")
12143
+ || setupHasOwn(action, "expectedValue")
12144
+ || setupHasOwn(action, "expected");
12145
+ const untilExpected = setupHasOwn(action, "until_expected_value")
12146
+ ? action.until_expected_value
12147
+ : setupHasOwn(action, "untilExpectedValue")
12148
+ ? action.untilExpectedValue
12149
+ : setupHasOwn(action, "until_expected")
12150
+ ? action.until_expected
12151
+ : setupHasOwn(action, "untilExpected")
12152
+ ? action.untilExpected
12153
+ : setupHasOwn(action, "until_value")
12154
+ ? action.until_value
12155
+ : setupHasOwn(action, "untilValue")
12156
+ ? action.untilValue
12157
+ : setupHasOwn(action, "expected_value")
12158
+ ? action.expected_value
12159
+ : setupHasOwn(action, "expectedValue")
12160
+ ? action.expectedValue
12161
+ : action.expected;
12162
+ if (!hasUntilExpected) return { ...base, path, until_path: untilPath, reason: "missing_until_expected_value" };
12163
+ 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)));
12164
+ 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)));
12165
+ const hasReturnExpectation = setupHasOwn(action, "expect_return")
12166
+ || setupHasOwn(action, "expectReturn")
12167
+ || setupHasOwn(action, "expected_return")
12168
+ || setupHasOwn(action, "expectedReturn");
12169
+ const expectedReturn = setupHasOwn(action, "expect_return")
12170
+ ? action.expect_return
12171
+ : setupHasOwn(action, "expectReturn")
12172
+ ? action.expectReturn
12173
+ : setupHasOwn(action, "expected_return")
12174
+ ? action.expected_return
12175
+ : action.expectedReturn;
12176
+ const scope = await setupActionScope(action, timeout);
12177
+ if (!scope.ok) return setupScopeFailure(base, scope);
12178
+ const startedAt = Date.now();
12179
+ let callCount = 0;
12180
+ let lastCallResult = null;
12181
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
12182
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
12183
+ return {
12184
+ ...base,
12185
+ ...setupScopeEvidence(scope),
12186
+ ok: true,
12187
+ path,
12188
+ arg_count: args.length,
12189
+ until_path: untilPath,
12190
+ until_value: setupJsonValue(lastPredicateResult.value),
12191
+ until_expected_value: setupJsonValue(untilExpected),
12192
+ call_count: callCount,
12193
+ max_calls: maxCalls,
12194
+ interval_ms: intervalMs,
12195
+ timeout_ms: timeout,
12196
+ };
12197
+ }
12198
+ while (callCount < maxCalls && Date.now() - startedAt <= timeout) {
12199
+ lastCallResult = await setupCallWindowFunction(scope.context, path, args);
12200
+ callCount += 1;
12201
+ if (!lastCallResult.ok) break;
12202
+ if (hasReturnExpectation && !setupValuesEqual(lastCallResult.returned, expectedReturn)) break;
12203
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
12204
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
12205
+ return {
12206
+ ...base,
12207
+ ...setupScopeEvidence(scope),
12208
+ ok: true,
12209
+ path,
12210
+ arg_count: args.length,
12211
+ returned: setupJsonValue(lastCallResult.returned),
12212
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
12213
+ until_path: untilPath,
12214
+ until_value: setupJsonValue(lastPredicateResult.value),
12215
+ until_expected_value: setupJsonValue(untilExpected),
12216
+ call_count: callCount,
12217
+ max_calls: maxCalls,
12218
+ interval_ms: intervalMs,
12219
+ timeout_ms: timeout,
12220
+ };
12221
+ }
12222
+ if (callCount < maxCalls && intervalMs) await page.waitForTimeout(intervalMs);
12223
+ }
12224
+ const returnExpectationMet = !hasReturnExpectation || setupValuesEqual(lastCallResult?.returned, expectedReturn);
12225
+ return {
12226
+ ...base,
12227
+ ...setupScopeEvidence(scope),
12228
+ path,
12229
+ arg_count: args.length,
12230
+ returned: setupJsonValue(lastCallResult?.returned),
12231
+ expected_return: hasReturnExpectation ? setupJsonValue(expectedReturn) : undefined,
12232
+ until_path: untilPath,
12233
+ until_value: setupJsonValue(lastPredicateResult?.value),
12234
+ until_expected_value: setupJsonValue(untilExpected),
12235
+ call_count: callCount,
12236
+ max_calls: maxCalls,
12237
+ interval_ms: intervalMs,
12238
+ timeout_ms: timeout,
12239
+ reason: lastCallResult && !lastCallResult.ok
12240
+ ? lastCallResult.reason
12241
+ : hasReturnExpectation && !returnExpectationMet
12242
+ ? "unexpected_return_value"
12243
+ : Date.now() - startedAt > timeout
12244
+ ? "timeout"
12245
+ : "until_condition_not_met",
12246
+ error: lastCallResult?.error || undefined,
12247
+ missing_part: lastPredicateResult?.missing_part || undefined,
12248
+ };
12249
+ }
12104
12250
  if (type === "assert_window_value") {
12105
12251
  const path = String(action.path || action.window_path || action.windowPath || "");
12106
12252
  const hasExpected = setupHasOwn(action, "expected_value")
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  profileStatusExitCode,
13
13
  resolveRiddleProofProfileTargetUrl,
14
14
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-PKE223TX.js";
15
+ } from "./chunk-TA2KLHMX.js";
16
16
  import {
17
17
  createRiddleApiClient,
18
18
  parseRiddleViewport
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",
@@ -9293,7 +9294,7 @@ function isSupportedCheckType(value) {
9293
9294
  }
9294
9295
  function normalizeSetupActionType(value, index) {
9295
9296
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
9296
- 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;
9297
9298
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
9298
9299
  return normalized;
9299
9300
  }
@@ -9424,10 +9425,10 @@ function normalizeSetupAction(input, index) {
9424
9425
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
9425
9426
  }
9426
9427
  const path6 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
9427
- 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) {
9428
9429
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
9429
9430
  }
9430
- 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;
9431
9432
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
9432
9433
  if (type === "assert_window_value" && !hasExpectedValue) {
9433
9434
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -9444,6 +9445,24 @@ function normalizeSetupAction(input, index) {
9444
9445
  }
9445
9446
  }
9446
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
+ }
9447
9466
  const steps = numberValue3(input.steps);
9448
9467
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
9449
9468
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -9470,6 +9489,10 @@ function normalizeSetupAction(input, index) {
9470
9489
  path: path6,
9471
9490
  args,
9472
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,
9473
9496
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
9474
9497
  min_value: minValue,
9475
9498
  max_value: maxValue,
@@ -13346,6 +13369,34 @@ async function setupReadWindowValue(context, path) {
13346
13369
  return { ok: true, value: toJsonValue(current) };
13347
13370
  }, { path });
13348
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
+ }
13349
13400
  function setupFrameSelector(action) {
13350
13401
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
13351
13402
  }
@@ -13863,32 +13914,7 @@ async function executeSetupAction(action, ordinal, viewport) {
13863
13914
  if (!path) return { ...base, path, reason: "missing_path" };
13864
13915
  const scope = await setupActionScope(action, timeout);
13865
13916
  if (!scope.ok) return setupScopeFailure(base, scope);
13866
- const result = await scope.context.evaluate(async ({ path, args }) => {
13867
- const toJsonValue = (value) => {
13868
- if (value === null || value === undefined) return null;
13869
- if (typeof value === "string" || typeof value === "boolean") return value;
13870
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
13871
- if (Array.isArray(value)) return value.map(toJsonValue);
13872
- if (typeof value === "object") {
13873
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
13874
- }
13875
- return String(value);
13876
- };
13877
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
13878
- let parent = window;
13879
- let current = window;
13880
- for (const part of pathParts) {
13881
- parent = current;
13882
- current = current?.[part];
13883
- }
13884
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
13885
- try {
13886
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
13887
- return { ok: true, returned: toJsonValue(returned) };
13888
- } catch (error) {
13889
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
13890
- }
13891
- }, { path, args });
13917
+ const result = await setupCallWindowFunction(scope.context, path, args);
13892
13918
  const hasExpectation = setupHasOwn(action, "expect_return")
13893
13919
  || setupHasOwn(action, "expectReturn")
13894
13920
  || setupHasOwn(action, "expected_return")
@@ -13913,6 +13939,126 @@ async function executeSetupAction(action, ordinal, viewport) {
13913
13939
  error: result.error || undefined,
13914
13940
  };
13915
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
+ }
13916
14062
  if (type === "assert_window_value") {
13917
14063
  const path = String(action.path || action.window_path || action.windowPath || "");
13918
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-PKE223TX.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",
@@ -607,7 +608,7 @@ function isSupportedCheckType(value) {
607
608
  }
608
609
  function normalizeSetupActionType(value, index) {
609
610
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
610
- 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;
611
612
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
612
613
  return normalized;
613
614
  }
@@ -738,10 +739,10 @@ function normalizeSetupAction(input, index) {
738
739
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
739
740
  }
740
741
  const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
741
- 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) {
742
743
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
743
744
  }
744
- 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;
745
746
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
746
747
  if (type === "assert_window_value" && !hasExpectedValue) {
747
748
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -758,6 +759,24 @@ function normalizeSetupAction(input, index) {
758
759
  }
759
760
  }
760
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
+ }
761
780
  const steps = numberValue(input.steps);
762
781
  if (type === "drag" && steps !== void 0 && (!Number.isInteger(steps) || steps < 1 || steps > 100)) {
763
782
  throw new Error(`target.setup_actions[${index}].steps must be an integer from 1 to 100.`);
@@ -784,6 +803,10 @@ function normalizeSetupAction(input, index) {
784
803
  path,
785
804
  args,
786
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,
787
810
  expected_value: hasExpectedValue ? toJsonValue(rawExpectedValue) : void 0,
788
811
  min_value: minValue,
789
812
  max_value: maxValue,
@@ -4660,6 +4683,34 @@ async function setupReadWindowValue(context, path) {
4660
4683
  return { ok: true, value: toJsonValue(current) };
4661
4684
  }, { path });
4662
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
+ }
4663
4714
  function setupFrameSelector(action) {
4664
4715
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
4665
4716
  }
@@ -5177,32 +5228,7 @@ async function executeSetupAction(action, ordinal, viewport) {
5177
5228
  if (!path) return { ...base, path, reason: "missing_path" };
5178
5229
  const scope = await setupActionScope(action, timeout);
5179
5230
  if (!scope.ok) return setupScopeFailure(base, scope);
5180
- const result = await scope.context.evaluate(async ({ path, args }) => {
5181
- const toJsonValue = (value) => {
5182
- if (value === null || value === undefined) return null;
5183
- if (typeof value === "string" || typeof value === "boolean") return value;
5184
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
5185
- if (Array.isArray(value)) return value.map(toJsonValue);
5186
- if (typeof value === "object") {
5187
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
5188
- }
5189
- return String(value);
5190
- };
5191
- const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
5192
- let parent = window;
5193
- let current = window;
5194
- for (const part of pathParts) {
5195
- parent = current;
5196
- current = current?.[part];
5197
- }
5198
- if (typeof current !== "function") return { ok: false, reason: "missing_function" };
5199
- try {
5200
- const returned = await current.apply(parent, Array.isArray(args) ? args : []);
5201
- return { ok: true, returned: toJsonValue(returned) };
5202
- } catch (error) {
5203
- return { ok: false, reason: "function_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
5204
- }
5205
- }, { path, args });
5231
+ const result = await setupCallWindowFunction(scope.context, path, args);
5206
5232
  const hasExpectation = setupHasOwn(action, "expect_return")
5207
5233
  || setupHasOwn(action, "expectReturn")
5208
5234
  || setupHasOwn(action, "expected_return")
@@ -5227,6 +5253,126 @@ async function executeSetupAction(action, ordinal, viewport) {
5227
5253
  error: result.error || undefined,
5228
5254
  };
5229
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
+ }
5230
5376
  if (type === "assert_window_value") {
5231
5377
  const path = String(action.path || action.window_path || action.windowPath || "");
5232
5378
  const hasExpected = setupHasOwn(action, "expected_value")
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
@@ -129,6 +129,10 @@ interface RiddleProofProfileSetupAction {
129
129
  path?: string;
130
130
  args?: JsonValue[];
131
131
  expect_return?: JsonValue;
132
+ until_path?: string;
133
+ until_expected_value?: JsonValue;
134
+ max_calls?: number;
135
+ interval_ms?: number;
132
136
  expected_value?: JsonValue;
133
137
  min_value?: number;
134
138
  max_value?: number;
package/dist/profile.d.ts CHANGED
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
@@ -129,6 +129,10 @@ interface RiddleProofProfileSetupAction {
129
129
  path?: string;
130
130
  args?: JsonValue[];
131
131
  expect_return?: JsonValue;
132
+ until_path?: string;
133
+ until_expected_value?: JsonValue;
134
+ max_calls?: number;
135
+ interval_ms?: number;
132
136
  expected_value?: JsonValue;
133
137
  min_value?: number;
134
138
  max_value?: number;
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-PKE223TX.js";
26
+ } from "./chunk-TA2KLHMX.js";
27
27
  export {
28
28
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
29
29
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.132",
3
+ "version": "0.7.133",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",