@riddledc/riddle-proof 0.7.8 → 0.7.9

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/index.cjs CHANGED
@@ -2917,6 +2917,7 @@ __export(index_exports, {
2917
2917
  RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
2918
2918
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
2919
2919
  RIDDLE_PROOF_PROFILE_RESULT_VERSION: () => RIDDLE_PROOF_PROFILE_RESULT_VERSION,
2920
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
2920
2921
  RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
2921
2922
  RIDDLE_PROOF_PROFILE_VERSION: () => RIDDLE_PROOF_PROFILE_VERSION,
2922
2923
  RIDDLE_PROOF_RUN_CARD_VERSION: () => RIDDLE_PROOF_RUN_CARD_VERSION,
@@ -8525,6 +8526,12 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8525
8526
  "no_mobile_horizontal_overflow",
8526
8527
  "no_fatal_console_errors"
8527
8528
  ];
8529
+ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8530
+ "click",
8531
+ "wait",
8532
+ "wait_for_selector",
8533
+ "wait_for_text"
8534
+ ];
8528
8535
  var DEFAULT_VIEWPORTS = [
8529
8536
  { name: "desktop", width: 1280, height: 800 }
8530
8537
  ];
@@ -8577,6 +8584,41 @@ function normalizeViewports(value) {
8577
8584
  function isSupportedCheckType(value) {
8578
8585
  return RIDDLE_PROOF_PROFILE_CHECK_TYPES.includes(value);
8579
8586
  }
8587
+ function normalizeSetupActionType(value, index) {
8588
+ const normalized = String(value || "").trim().replace(/-/g, "_");
8589
+ if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
8590
+ return normalized;
8591
+ }
8592
+ throw new Error(`target.setup_actions[${index}].type ${value || "(missing)"} is not supported. Supported actions: ${RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.join(", ")}`);
8593
+ }
8594
+ function normalizeSetupAction(input, index) {
8595
+ if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
8596
+ const type = normalizeSetupActionType(stringValue5(input.type), index);
8597
+ const selector = stringValue5(input.selector);
8598
+ if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
8599
+ throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
8600
+ }
8601
+ if (type === "wait_for_text" && !stringValue5(input.text) && !stringValue5(input.pattern)) {
8602
+ throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
8603
+ }
8604
+ return {
8605
+ type,
8606
+ selector,
8607
+ text: stringValue5(input.text),
8608
+ pattern: stringValue5(input.pattern),
8609
+ flags: stringValue5(input.flags),
8610
+ index: numberValue3(input.index),
8611
+ ms: numberValue3(input.ms) ?? numberValue3(input.wait_ms) ?? numberValue3(input.waitMs),
8612
+ timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
8613
+ after_ms: numberValue3(input.after_ms) ?? numberValue3(input.afterMs),
8614
+ continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
8615
+ };
8616
+ }
8617
+ function normalizeSetupActions(value) {
8618
+ if (value === void 0) return void 0;
8619
+ if (!Array.isArray(value)) throw new Error("target.setup_actions must be an array.");
8620
+ return value.map(normalizeSetupAction);
8621
+ }
8580
8622
  function normalizeCheck(input, index) {
8581
8623
  if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
8582
8624
  const type = stringValue5(input.type);
@@ -8644,7 +8686,8 @@ function normalizeRiddleProofProfile(input, options = {}) {
8644
8686
  viewports: options.viewports?.length ? options.viewports : normalizeViewports(targetInput.viewports),
8645
8687
  auth: stringValue5(targetInput.auth) || "none",
8646
8688
  wait_for_selector: stringValue5(targetInput.wait_for_selector) || stringValue5(targetInput.waitForSelector),
8647
- wait_ms: numberValue3(targetInput.wait_ms) ?? numberValue3(targetInput.waitMs)
8689
+ wait_ms: numberValue3(targetInput.wait_ms) ?? numberValue3(targetInput.waitMs),
8690
+ setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions)
8648
8691
  },
8649
8692
  checks,
8650
8693
  artifacts: Array.isArray(input.artifacts) ? input.artifacts.map((item) => String(item)).filter(Boolean) : ["screenshot", "console", "dom_summary", "proof_json"],
@@ -8817,6 +8860,48 @@ function assessCheckFromEvidence(check, evidence) {
8817
8860
  message: "Unsupported check type."
8818
8861
  };
8819
8862
  }
8863
+ function assessSetupActionsFromEvidence(profile, evidence) {
8864
+ if (!profile.target.setup_actions?.length) return void 0;
8865
+ const actionCount = profile.target.setup_actions.length;
8866
+ const failed = [];
8867
+ const viewports = evidence.viewports || [];
8868
+ for (const viewport of viewports) {
8869
+ const results = viewport.setup_action_results || [];
8870
+ for (const result of results) {
8871
+ if (result.ok === false) {
8872
+ failed.push({
8873
+ viewport: viewport.name,
8874
+ action: result.action ?? result.type ?? null,
8875
+ selector: result.selector ?? null,
8876
+ reason: result.reason ?? result.error ?? null
8877
+ });
8878
+ }
8879
+ }
8880
+ if (results.length < actionCount && results.every((result) => result.ok !== false)) {
8881
+ failed.push({
8882
+ viewport: viewport.name,
8883
+ action: "setup_actions",
8884
+ selector: null,
8885
+ reason: `missing setup action results: ${results.length}/${actionCount}`
8886
+ });
8887
+ }
8888
+ }
8889
+ return {
8890
+ type: "setup_actions_succeeded",
8891
+ label: "setup actions succeeded",
8892
+ status: failed.length ? "failed" : "passed",
8893
+ evidence: {
8894
+ action_count: actionCount,
8895
+ viewports: viewports.map((viewport) => ({
8896
+ name: viewport.name,
8897
+ ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
8898
+ result_count: (viewport.setup_action_results || []).length
8899
+ })),
8900
+ failed
8901
+ },
8902
+ message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
8903
+ };
8904
+ }
8820
8905
  function profileStatusFromEvidence(evidence, checks) {
8821
8906
  if (!evidence) return "proof_insufficient";
8822
8907
  const viewports = evidence.viewports || [];
@@ -8828,7 +8913,10 @@ function profileStatusFromEvidence(evidence, checks) {
8828
8913
  }
8829
8914
  function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
8830
8915
  const capturedAt = evidence?.captured_at || (/* @__PURE__ */ new Date()).toISOString();
8831
- const checks = evidence ? profile.checks.map((check) => assessCheckFromEvidence(check, evidence)) : [];
8916
+ const checks = evidence ? [
8917
+ assessSetupActionsFromEvidence(profile, evidence),
8918
+ ...profile.checks.map((check) => assessCheckFromEvidence(check, evidence))
8919
+ ].filter((check) => Boolean(check)) : [];
8832
8920
  const status = profileStatusFromEvidence(evidence, checks);
8833
8921
  const firstViewport = evidence?.viewports?.[0];
8834
8922
  const screenshots = (evidence?.viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => Boolean(label));
@@ -8942,6 +9030,47 @@ function textMatches(sample, check) {
8942
9030
  function assessProfile(profile, evidence) {
8943
9031
  const checks = [];
8944
9032
  const viewports = evidence.viewports || [];
9033
+ if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
9034
+ const actionCount = profile.target.setup_actions.length;
9035
+ const failed = [];
9036
+ for (const viewport of viewports) {
9037
+ const results = viewport.setup_action_results || [];
9038
+ for (const result of results) {
9039
+ if (result && result.ok === false) {
9040
+ failed.push({
9041
+ viewport: viewport.name,
9042
+ action: result.action || result.type || null,
9043
+ selector: result.selector || null,
9044
+ reason: result.reason || result.error || null,
9045
+ });
9046
+ }
9047
+ }
9048
+ if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
9049
+ failed.push({
9050
+ viewport: viewport.name,
9051
+ action: "setup_actions",
9052
+ selector: null,
9053
+ reason: "missing setup action results: " + results.length + "/" + actionCount,
9054
+ });
9055
+ }
9056
+ }
9057
+ checks.push({
9058
+ type: "setup_actions_succeeded",
9059
+ label: "setup actions succeeded",
9060
+ status: failed.length ? "failed" : "passed",
9061
+ evidence: {
9062
+ action_count: actionCount,
9063
+ viewports: viewports.map((viewport) => ({
9064
+ name: viewport.name,
9065
+ ok: (viewport.setup_action_results || []).length >= actionCount
9066
+ && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
9067
+ result_count: (viewport.setup_action_results || []).length,
9068
+ })),
9069
+ failed,
9070
+ },
9071
+ message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
9072
+ });
9073
+ }
8945
9074
  for (const check of profile.checks || []) {
8946
9075
  if (check.type === "route_loaded") {
8947
9076
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
@@ -9104,6 +9233,92 @@ function textMatches(sample, check) {
9104
9233
  }
9105
9234
  return String(sample || "").includes(check.text || "");
9106
9235
  }
9236
+ function setupActionType(action) {
9237
+ return String(action && action.type ? action.type : "").replace(/-/g, "_");
9238
+ }
9239
+ function setupNumber(value, fallback) {
9240
+ const number = Number(value);
9241
+ return Number.isFinite(number) && number >= 0 ? number : fallback;
9242
+ }
9243
+ function setupTextMatches(sample, action) {
9244
+ if (action.pattern) {
9245
+ try { return new RegExp(action.pattern, action.flags || "").test(sample || ""); } catch { return false; }
9246
+ }
9247
+ return String(sample || "").includes(action.text || "");
9248
+ }
9249
+ async function setupLocatorText(locator, index) {
9250
+ return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
9251
+ }
9252
+ async function executeSetupAction(action, ordinal) {
9253
+ const type = setupActionType(action);
9254
+ const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
9255
+ const timeout = setupNumber(action.timeout_ms, 5000);
9256
+ try {
9257
+ if (type === "wait") {
9258
+ const ms = setupNumber(action.ms, 500);
9259
+ await page.waitForTimeout(ms);
9260
+ return { ...base, ok: true, ms };
9261
+ }
9262
+ if (type === "wait_for_selector") {
9263
+ await page.waitForSelector(action.selector, { state: "visible", timeout });
9264
+ return { ...base, ok: true, timeout_ms: timeout };
9265
+ }
9266
+ if (type === "click") {
9267
+ const locator = page.locator(action.selector);
9268
+ const count = await locator.count();
9269
+ if (!count) return { ...base, reason: "selector_not_found", count };
9270
+ let targetIndex = Number.isInteger(action.index) ? action.index : 0;
9271
+ let matchedText = null;
9272
+ if (action.text || action.pattern) {
9273
+ targetIndex = -1;
9274
+ for (let index = 0; index < count; index += 1) {
9275
+ const text = await setupLocatorText(locator, index);
9276
+ if (setupTextMatches(text, action)) {
9277
+ targetIndex = index;
9278
+ matchedText = text;
9279
+ break;
9280
+ }
9281
+ }
9282
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
9283
+ }
9284
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
9285
+ await locator.nth(targetIndex).click({ timeout });
9286
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
9287
+ }
9288
+ if (type === "wait_for_text") {
9289
+ const locator = page.locator(action.selector);
9290
+ const startedAt = Date.now();
9291
+ let lastText = "";
9292
+ while (Date.now() - startedAt <= timeout) {
9293
+ const count = await locator.count().catch(() => 0);
9294
+ for (let index = 0; index < count; index += 1) {
9295
+ const text = await setupLocatorText(locator, index);
9296
+ lastText = text || lastText;
9297
+ if (setupTextMatches(text, action)) {
9298
+ return { ...base, ok: true, text, target_index: index, timeout_ms: timeout };
9299
+ }
9300
+ }
9301
+ await page.waitForTimeout(100);
9302
+ }
9303
+ return { ...base, reason: "text_not_found", text: lastText, timeout_ms: timeout };
9304
+ }
9305
+ return { ...base, reason: "unsupported_action" };
9306
+ } catch (error) {
9307
+ return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
9308
+ }
9309
+ }
9310
+ async function executeSetupActions(actions) {
9311
+ const results = [];
9312
+ for (let index = 0; index < (actions || []).length; index += 1) {
9313
+ const action = actions[index] || {};
9314
+ const result = await executeSetupAction(action, index);
9315
+ results.push(result);
9316
+ const afterMs = setupNumber(action.after_ms, 0);
9317
+ if (afterMs) await page.waitForTimeout(afterMs);
9318
+ if (result.ok === false && action.continue_on_failure !== true) break;
9319
+ }
9320
+ return results;
9321
+ }
9107
9322
  function expectedPathFor(check) {
9108
9323
  return check.expected_path || new URL(targetUrl).pathname || "/";
9109
9324
  }
@@ -9138,6 +9353,9 @@ async function captureViewport(viewport) {
9138
9353
  if (!navigationError && profile.target.wait_ms) {
9139
9354
  await page.waitForTimeout(profile.target.wait_ms);
9140
9355
  }
9356
+ const setupActionResults = (!navigationError && !waitError)
9357
+ ? await executeSetupActions(profile.target.setup_actions || [])
9358
+ : [];
9141
9359
  const dom = await page.evaluate(() => {
9142
9360
  const body = document.body;
9143
9361
  const documentElement = document.documentElement;
@@ -9199,6 +9417,7 @@ async function captureViewport(viewport) {
9199
9417
  overflow_px: Math.max(0, (dom.scroll_width || 0) - (dom.client_width || viewport.width)),
9200
9418
  selectors,
9201
9419
  text_matches,
9420
+ setup_action_results: setupActionResults,
9202
9421
  screenshot_label: screenshotLabel,
9203
9422
  navigation_error: navigationError,
9204
9423
  wait_error: waitError,
@@ -9544,6 +9763,7 @@ function createRiddleApiClient(config = {}) {
9544
9763
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
9545
9764
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
9546
9765
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
9766
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
9547
9767
  RIDDLE_PROOF_PROFILE_STATUSES,
9548
9768
  RIDDLE_PROOF_PROFILE_VERSION,
9549
9769
  RIDDLE_PROOF_RUN_CARD_VERSION,
package/dist/index.d.cts CHANGED
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
10
10
  export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.cjs';
11
11
  export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.cjs';
12
12
  export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.cjs';
13
- export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRunner, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
13
+ export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
14
14
  export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobResult, RiddlePreviewDeployResult, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.cjs';
package/dist/index.d.ts CHANGED
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
10
10
  export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.js';
11
11
  export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.js';
12
12
  export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.js';
13
- export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRunner, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
13
+ export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileTargetUrl, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
14
14
  export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobResult, RiddlePreviewDeployResult, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.js';
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ import {
41
41
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
42
42
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
43
43
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
44
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
44
45
  RIDDLE_PROOF_PROFILE_STATUSES,
45
46
  RIDDLE_PROOF_PROFILE_VERSION,
46
47
  assessRiddleProofProfileEvidence,
@@ -55,7 +56,7 @@ import {
55
56
  resolveRiddleProofProfileTargetUrl,
56
57
  slugifyRiddleProofProfileName,
57
58
  summarizeRiddleProofProfileResult
58
- } from "./chunk-7NMAU4DP.js";
59
+ } from "./chunk-NUSUGO2P.js";
59
60
  import {
60
61
  DEFAULT_RIDDLE_API_BASE_URL,
61
62
  DEFAULT_RIDDLE_API_KEY_FILE,
@@ -153,6 +154,7 @@ export {
153
154
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
154
155
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
155
156
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
157
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
156
158
  RIDDLE_PROOF_PROFILE_STATUSES,
157
159
  RIDDLE_PROOF_PROFILE_VERSION,
158
160
  RIDDLE_PROOF_RUN_CARD_VERSION,
package/dist/profile.cjs CHANGED
@@ -23,6 +23,7 @@ __export(profile_exports, {
23
23
  RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
24
24
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
25
25
  RIDDLE_PROOF_PROFILE_RESULT_VERSION: () => RIDDLE_PROOF_PROFILE_RESULT_VERSION,
26
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
26
27
  RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
27
28
  RIDDLE_PROOF_PROFILE_VERSION: () => RIDDLE_PROOF_PROFILE_VERSION,
28
29
  assessRiddleProofProfileEvidence: () => assessRiddleProofProfileEvidence,
@@ -60,6 +61,12 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
60
61
  "no_mobile_horizontal_overflow",
61
62
  "no_fatal_console_errors"
62
63
  ];
64
+ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
65
+ "click",
66
+ "wait",
67
+ "wait_for_selector",
68
+ "wait_for_text"
69
+ ];
63
70
  var DEFAULT_VIEWPORTS = [
64
71
  { name: "desktop", width: 1280, height: 800 }
65
72
  ];
@@ -112,6 +119,41 @@ function normalizeViewports(value) {
112
119
  function isSupportedCheckType(value) {
113
120
  return RIDDLE_PROOF_PROFILE_CHECK_TYPES.includes(value);
114
121
  }
122
+ function normalizeSetupActionType(value, index) {
123
+ const normalized = String(value || "").trim().replace(/-/g, "_");
124
+ if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
125
+ return normalized;
126
+ }
127
+ throw new Error(`target.setup_actions[${index}].type ${value || "(missing)"} is not supported. Supported actions: ${RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.join(", ")}`);
128
+ }
129
+ function normalizeSetupAction(input, index) {
130
+ if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
131
+ const type = normalizeSetupActionType(stringValue(input.type), index);
132
+ const selector = stringValue(input.selector);
133
+ if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
134
+ throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
135
+ }
136
+ if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
137
+ throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
138
+ }
139
+ return {
140
+ type,
141
+ selector,
142
+ text: stringValue(input.text),
143
+ pattern: stringValue(input.pattern),
144
+ flags: stringValue(input.flags),
145
+ index: numberValue(input.index),
146
+ ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
147
+ timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
148
+ after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
149
+ continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
150
+ };
151
+ }
152
+ function normalizeSetupActions(value) {
153
+ if (value === void 0) return void 0;
154
+ if (!Array.isArray(value)) throw new Error("target.setup_actions must be an array.");
155
+ return value.map(normalizeSetupAction);
156
+ }
115
157
  function normalizeCheck(input, index) {
116
158
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
117
159
  const type = stringValue(input.type);
@@ -179,7 +221,8 @@ function normalizeRiddleProofProfile(input, options = {}) {
179
221
  viewports: options.viewports?.length ? options.viewports : normalizeViewports(targetInput.viewports),
180
222
  auth: stringValue(targetInput.auth) || "none",
181
223
  wait_for_selector: stringValue(targetInput.wait_for_selector) || stringValue(targetInput.waitForSelector),
182
- wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs)
224
+ wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs),
225
+ setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions)
183
226
  },
184
227
  checks,
185
228
  artifacts: Array.isArray(input.artifacts) ? input.artifacts.map((item) => String(item)).filter(Boolean) : ["screenshot", "console", "dom_summary", "proof_json"],
@@ -352,6 +395,48 @@ function assessCheckFromEvidence(check, evidence) {
352
395
  message: "Unsupported check type."
353
396
  };
354
397
  }
398
+ function assessSetupActionsFromEvidence(profile, evidence) {
399
+ if (!profile.target.setup_actions?.length) return void 0;
400
+ const actionCount = profile.target.setup_actions.length;
401
+ const failed = [];
402
+ const viewports = evidence.viewports || [];
403
+ for (const viewport of viewports) {
404
+ const results = viewport.setup_action_results || [];
405
+ for (const result of results) {
406
+ if (result.ok === false) {
407
+ failed.push({
408
+ viewport: viewport.name,
409
+ action: result.action ?? result.type ?? null,
410
+ selector: result.selector ?? null,
411
+ reason: result.reason ?? result.error ?? null
412
+ });
413
+ }
414
+ }
415
+ if (results.length < actionCount && results.every((result) => result.ok !== false)) {
416
+ failed.push({
417
+ viewport: viewport.name,
418
+ action: "setup_actions",
419
+ selector: null,
420
+ reason: `missing setup action results: ${results.length}/${actionCount}`
421
+ });
422
+ }
423
+ }
424
+ return {
425
+ type: "setup_actions_succeeded",
426
+ label: "setup actions succeeded",
427
+ status: failed.length ? "failed" : "passed",
428
+ evidence: {
429
+ action_count: actionCount,
430
+ viewports: viewports.map((viewport) => ({
431
+ name: viewport.name,
432
+ ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
433
+ result_count: (viewport.setup_action_results || []).length
434
+ })),
435
+ failed
436
+ },
437
+ message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
438
+ };
439
+ }
355
440
  function profileStatusFromEvidence(evidence, checks) {
356
441
  if (!evidence) return "proof_insufficient";
357
442
  const viewports = evidence.viewports || [];
@@ -363,7 +448,10 @@ function profileStatusFromEvidence(evidence, checks) {
363
448
  }
364
449
  function assessRiddleProofProfileEvidence(profile, evidence, options = {}) {
365
450
  const capturedAt = evidence?.captured_at || (/* @__PURE__ */ new Date()).toISOString();
366
- const checks = evidence ? profile.checks.map((check) => assessCheckFromEvidence(check, evidence)) : [];
451
+ const checks = evidence ? [
452
+ assessSetupActionsFromEvidence(profile, evidence),
453
+ ...profile.checks.map((check) => assessCheckFromEvidence(check, evidence))
454
+ ].filter((check) => Boolean(check)) : [];
367
455
  const status = profileStatusFromEvidence(evidence, checks);
368
456
  const firstViewport = evidence?.viewports?.[0];
369
457
  const screenshots = (evidence?.viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => Boolean(label));
@@ -477,6 +565,47 @@ function textMatches(sample, check) {
477
565
  function assessProfile(profile, evidence) {
478
566
  const checks = [];
479
567
  const viewports = evidence.viewports || [];
568
+ if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
569
+ const actionCount = profile.target.setup_actions.length;
570
+ const failed = [];
571
+ for (const viewport of viewports) {
572
+ const results = viewport.setup_action_results || [];
573
+ for (const result of results) {
574
+ if (result && result.ok === false) {
575
+ failed.push({
576
+ viewport: viewport.name,
577
+ action: result.action || result.type || null,
578
+ selector: result.selector || null,
579
+ reason: result.reason || result.error || null,
580
+ });
581
+ }
582
+ }
583
+ if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
584
+ failed.push({
585
+ viewport: viewport.name,
586
+ action: "setup_actions",
587
+ selector: null,
588
+ reason: "missing setup action results: " + results.length + "/" + actionCount,
589
+ });
590
+ }
591
+ }
592
+ checks.push({
593
+ type: "setup_actions_succeeded",
594
+ label: "setup actions succeeded",
595
+ status: failed.length ? "failed" : "passed",
596
+ evidence: {
597
+ action_count: actionCount,
598
+ viewports: viewports.map((viewport) => ({
599
+ name: viewport.name,
600
+ ok: (viewport.setup_action_results || []).length >= actionCount
601
+ && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
602
+ result_count: (viewport.setup_action_results || []).length,
603
+ })),
604
+ failed,
605
+ },
606
+ message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
607
+ });
608
+ }
480
609
  for (const check of profile.checks || []) {
481
610
  if (check.type === "route_loaded") {
482
611
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
@@ -639,6 +768,92 @@ function textMatches(sample, check) {
639
768
  }
640
769
  return String(sample || "").includes(check.text || "");
641
770
  }
771
+ function setupActionType(action) {
772
+ return String(action && action.type ? action.type : "").replace(/-/g, "_");
773
+ }
774
+ function setupNumber(value, fallback) {
775
+ const number = Number(value);
776
+ return Number.isFinite(number) && number >= 0 ? number : fallback;
777
+ }
778
+ function setupTextMatches(sample, action) {
779
+ if (action.pattern) {
780
+ try { return new RegExp(action.pattern, action.flags || "").test(sample || ""); } catch { return false; }
781
+ }
782
+ return String(sample || "").includes(action.text || "");
783
+ }
784
+ async function setupLocatorText(locator, index) {
785
+ return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
786
+ }
787
+ async function executeSetupAction(action, ordinal) {
788
+ const type = setupActionType(action);
789
+ const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
790
+ const timeout = setupNumber(action.timeout_ms, 5000);
791
+ try {
792
+ if (type === "wait") {
793
+ const ms = setupNumber(action.ms, 500);
794
+ await page.waitForTimeout(ms);
795
+ return { ...base, ok: true, ms };
796
+ }
797
+ if (type === "wait_for_selector") {
798
+ await page.waitForSelector(action.selector, { state: "visible", timeout });
799
+ return { ...base, ok: true, timeout_ms: timeout };
800
+ }
801
+ if (type === "click") {
802
+ const locator = page.locator(action.selector);
803
+ const count = await locator.count();
804
+ if (!count) return { ...base, reason: "selector_not_found", count };
805
+ let targetIndex = Number.isInteger(action.index) ? action.index : 0;
806
+ let matchedText = null;
807
+ if (action.text || action.pattern) {
808
+ targetIndex = -1;
809
+ for (let index = 0; index < count; index += 1) {
810
+ const text = await setupLocatorText(locator, index);
811
+ if (setupTextMatches(text, action)) {
812
+ targetIndex = index;
813
+ matchedText = text;
814
+ break;
815
+ }
816
+ }
817
+ if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
818
+ }
819
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
820
+ await locator.nth(targetIndex).click({ timeout });
821
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
822
+ }
823
+ if (type === "wait_for_text") {
824
+ const locator = page.locator(action.selector);
825
+ const startedAt = Date.now();
826
+ let lastText = "";
827
+ while (Date.now() - startedAt <= timeout) {
828
+ const count = await locator.count().catch(() => 0);
829
+ for (let index = 0; index < count; index += 1) {
830
+ const text = await setupLocatorText(locator, index);
831
+ lastText = text || lastText;
832
+ if (setupTextMatches(text, action)) {
833
+ return { ...base, ok: true, text, target_index: index, timeout_ms: timeout };
834
+ }
835
+ }
836
+ await page.waitForTimeout(100);
837
+ }
838
+ return { ...base, reason: "text_not_found", text: lastText, timeout_ms: timeout };
839
+ }
840
+ return { ...base, reason: "unsupported_action" };
841
+ } catch (error) {
842
+ return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
843
+ }
844
+ }
845
+ async function executeSetupActions(actions) {
846
+ const results = [];
847
+ for (let index = 0; index < (actions || []).length; index += 1) {
848
+ const action = actions[index] || {};
849
+ const result = await executeSetupAction(action, index);
850
+ results.push(result);
851
+ const afterMs = setupNumber(action.after_ms, 0);
852
+ if (afterMs) await page.waitForTimeout(afterMs);
853
+ if (result.ok === false && action.continue_on_failure !== true) break;
854
+ }
855
+ return results;
856
+ }
642
857
  function expectedPathFor(check) {
643
858
  return check.expected_path || new URL(targetUrl).pathname || "/";
644
859
  }
@@ -673,6 +888,9 @@ async function captureViewport(viewport) {
673
888
  if (!navigationError && profile.target.wait_ms) {
674
889
  await page.waitForTimeout(profile.target.wait_ms);
675
890
  }
891
+ const setupActionResults = (!navigationError && !waitError)
892
+ ? await executeSetupActions(profile.target.setup_actions || [])
893
+ : [];
676
894
  const dom = await page.evaluate(() => {
677
895
  const body = document.body;
678
896
  const documentElement = document.documentElement;
@@ -734,6 +952,7 @@ async function captureViewport(viewport) {
734
952
  overflow_px: Math.max(0, (dom.scroll_width || 0) - (dom.client_width || viewport.width)),
735
953
  selectors,
736
954
  text_matches,
955
+ setup_action_results: setupActionResults,
737
956
  screenshot_label: screenshotLabel,
738
957
  navigation_error: navigationError,
739
958
  wait_error: waitError,
@@ -831,6 +1050,7 @@ function extractRiddleProofProfileResult(input) {
831
1050
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
832
1051
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
833
1052
  RIDDLE_PROOF_PROFILE_RESULT_VERSION,
1053
+ RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
834
1054
  RIDDLE_PROOF_PROFILE_STATUSES,
835
1055
  RIDDLE_PROOF_PROFILE_VERSION,
836
1056
  assessRiddleProofProfileEvidence,