@validate.qa/runner 1.0.62 → 1.0.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5770,6 +5770,53 @@ var init_analytics_url = __esm({
5770
5770
  }
5771
5771
  });
5772
5772
 
5773
+ // ../shared/dist/api-endpoint-hygiene.js
5774
+ function isAssetLikePath(path) {
5775
+ return ASSET_SEGMENT_RE.test(path ?? "");
5776
+ }
5777
+ var ASSET_SEGMENT_RE;
5778
+ var init_api_endpoint_hygiene = __esm({
5779
+ "../shared/dist/api-endpoint-hygiene.js"() {
5780
+ "use strict";
5781
+ ASSET_SEGMENT_RE = /(?:^|\/)(?:assets|static|public|img|images|media|fonts|_next|locales)(?:\/|$)/i;
5782
+ }
5783
+ });
5784
+
5785
+ // ../shared/dist/auth-provider-hosts.js
5786
+ function isAuthProviderHost(host) {
5787
+ if (!host)
5788
+ return false;
5789
+ const h = host.toLowerCase();
5790
+ return AUTH_PROVIDER_HOST_SIGNATURES.some((sig) => sig.startsWith(".") ? h.endsWith(sig) : h.includes(sig));
5791
+ }
5792
+ var AUTH_PROVIDER_HOST_SIGNATURES, AUTH_PATH_SIGNATURE;
5793
+ var init_auth_provider_hosts = __esm({
5794
+ "../shared/dist/auth-provider-hosts.js"() {
5795
+ "use strict";
5796
+ AUTH_PROVIDER_HOST_SIGNATURES = [
5797
+ "clerk.",
5798
+ // clerk.<app-domain> — Clerk Frontend API
5799
+ ".auth0.com",
5800
+ ".okta.com",
5801
+ ".oktapreview.com",
5802
+ "cognito-idp.",
5803
+ ".amazoncognito.com",
5804
+ "identitytoolkit.googleapis.com",
5805
+ // Firebase Auth
5806
+ "securetoken.googleapis.com",
5807
+ ".supabase.co",
5808
+ ".stytch.com",
5809
+ ".workos.com",
5810
+ ".frontegg.com",
5811
+ ".kinde.com",
5812
+ "login.microsoftonline.com",
5813
+ ".b2clogin.com",
5814
+ "accounts.google.com"
5815
+ ];
5816
+ AUTH_PATH_SIGNATURE = /(?:sign[_-]?ins?|first_factor|second_factor|prepare_verification|\/oauth\/|\/authorize\b|\/authenticate\b|openid-connect\/token|\/userinfo\b|\/passwordless)/i;
5817
+ }
5818
+ });
5819
+
5773
5820
  // ../shared/dist/index.js
5774
5821
  var dist_exports = {};
5775
5822
  __export(dist_exports, {
@@ -5781,6 +5828,8 @@ __export(dist_exports, {
5781
5828
  API_AUTH_HEADERS_ENV_KEY: () => API_AUTH_HEADERS_ENV_KEY,
5782
5829
  API_PREFIX: () => API_PREFIX,
5783
5830
  AUDIO_CHUNK_DURATION_MS: () => AUDIO_CHUNK_DURATION_MS,
5831
+ AUTH_PATH_SIGNATURE: () => AUTH_PATH_SIGNATURE,
5832
+ AUTH_PROVIDER_HOST_SIGNATURES: () => AUTH_PROVIDER_HOST_SIGNATURES,
5784
5833
  AUTH_STATE_EXPIRY_SKEW_MS: () => AUTH_STATE_EXPIRY_SKEW_MS,
5785
5834
  AUTH_TAG_COOKIE_STATE: () => AUTH_TAG_COOKIE_STATE,
5786
5835
  AUTH_TAG_LOGIN_BEARER: () => AUTH_TAG_LOGIN_BEARER,
@@ -5898,6 +5947,8 @@ __export(dist_exports, {
5898
5947
  isAddonType: () => isAddonType,
5899
5948
  isApiTest: () => isApiTest,
5900
5949
  isAppOriginResolutionEnabled: () => isAppOriginResolutionEnabled,
5950
+ isAssetLikePath: () => isAssetLikePath,
5951
+ isAuthProviderHost: () => isAuthProviderHost,
5901
5952
  isAuthReadinessGuardEnabled: () => isAuthReadinessGuardEnabled,
5902
5953
  isAuthTokenName: () => isAuthTokenName,
5903
5954
  isBlockedEnvVar: () => isBlockedEnvVar,
@@ -5998,6 +6049,8 @@ var init_dist = __esm({
5998
6049
  init_feature_flags();
5999
6050
  init_env_flags();
6000
6051
  init_analytics_url();
6052
+ init_api_endpoint_hygiene();
6053
+ init_auth_provider_hosts();
6001
6054
  }
6002
6055
  });
6003
6056
 
@@ -73455,6 +73508,7 @@ var require_inbox_tools = __commonJS({
73455
73508
  legacyEmail,
73456
73509
  tag,
73457
73510
  usePlusTag: email !== baseEmail,
73511
+ allowPlainFallback: opts.allowPlainFallback ?? true,
73458
73512
  passwordKey: opts.passwordKey ?? "TEST_USER_PASSWORD",
73459
73513
  provisioned: false,
73460
73514
  // Floor reads at run start so a verification email from a PRIOR run (the
@@ -73617,6 +73671,9 @@ var require_inbox_tools = __commonJS({
73617
73671
  const { state: state2 } = ctx;
73618
73672
  const plain = args.plain === true || args.plain === "true";
73619
73673
  const restore = args.plain === false || args.plain === "false";
73674
+ if (plain && !state2.allowPlainFallback) {
73675
+ return err("The bare inbox address is unavailable for this brokered run because it is shared across projects. Keep using the project-scoped +tag address; if the app rejects plus-addressing, report email verification as blocked.");
73676
+ }
73620
73677
  if (plain && state2.usePlusTag) {
73621
73678
  state2.email = state2.baseEmail;
73622
73679
  state2.usePlusTag = false;
@@ -75458,7 +75515,10 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
75458
75515
  } else if (registerRequested && ctx.inboxBroker?.address && ctx.inboxBrokerRead) {
75459
75516
  inboxState = (0, inbox_tools_js_1.createInboxRunState)({ address: ctx.inboxBroker.address }, {
75460
75517
  tagSeed: targetAppId ?? ctx.projectId,
75461
- projectScope: ctx.projectId
75518
+ projectScope: ctx.projectId,
75519
+ // A user-controlled local runner must never read the shared bare inbox:
75520
+ // only the project-scoped +tag is an authorization boundary.
75521
+ allowPlainFallback: false
75462
75522
  });
75463
75523
  inboxReader = new brokered_inbox_reader_js_1.BrokeredInboxReader(ctx.inboxBrokerRead);
75464
75524
  await (0, inbox_tools_js_1.applyAndPersistInboxIdentity)({
@@ -85209,6 +85269,7 @@ var require_api_call_redaction = __commonJS({
85209
85269
  exports2.buildResponseExcerpt = buildResponseExcerpt;
85210
85270
  exports2.isTextExcerptable = isTextExcerptable;
85211
85271
  exports2.buildApiCallSummary = buildApiCallSummary2;
85272
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
85212
85273
  exports2.STATIC_EXTENSIONS = /* @__PURE__ */ new Set([
85213
85274
  ".js",
85214
85275
  ".css",
@@ -85226,7 +85287,9 @@ var require_api_call_redaction = __commonJS({
85226
85287
  ".webp",
85227
85288
  ".avif",
85228
85289
  ".mp4",
85229
- ".webm"
85290
+ ".webm",
85291
+ ".lottie",
85292
+ ".webmanifest"
85230
85293
  ]);
85231
85294
  exports2.SECURITY_HEADER_NAMES = /* @__PURE__ */ new Set([
85232
85295
  // CORS & core security
@@ -85315,6 +85378,8 @@ var require_api_call_redaction = __commonJS({
85315
85378
  return false;
85316
85379
  if (path.includes("/api/") || path.includes("/graphql"))
85317
85380
  return true;
85381
+ if (ext.toLowerCase() === ".json" && (0, shared_1.isAssetLikePath)(path))
85382
+ return false;
85318
85383
  if (contentType?.includes("application/json"))
85319
85384
  return true;
85320
85385
  if (contentType?.includes("application/graphql"))
@@ -86869,6 +86934,7 @@ var require_playwright_native = __commonJS({
86869
86934
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86870
86935
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86871
86936
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86937
+ const configBaseUrl = isApiTest2 && options.apiBaseUrl ? options.apiBaseUrl : baseUrl;
86872
86938
  const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86873
86939
  const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86874
86940
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
@@ -87072,7 +87138,7 @@ test.afterEach(async ({ page }, testInfo) => {
87072
87138
  if (!importMatch) {
87073
87139
  logs2.push("\u26A0 Could not find @playwright/test import - animation disabling NOT injected");
87074
87140
  }
87075
- const useScopedApiHeaders = isApiTest2 && !!resolvedExtraHeaders && !!importMatch && !!baseUrl;
87141
+ const useScopedApiHeaders = isApiTest2 && !!resolvedExtraHeaders && !!importMatch && !!configBaseUrl;
87076
87142
  const authDelivery = { standingHeadersConfigured: !!resolvedExtraHeaders, standingHeadersInjected: useScopedApiHeaders };
87077
87143
  if (resolvedExtraHeaders && !useScopedApiHeaders) {
87078
87144
  logs2.push("\u26A0 Standing API auth headers were configured but could not be installed origin-scoped \u2014 failing closed (no global fallback).");
@@ -87093,10 +87159,10 @@ test.afterEach(async ({ page }, testInfo) => {
87093
87159
  }
87094
87160
  await (0, promises_1.writeFile)((0, path_1.join)(runDir, "test.spec.ts"), instrumentedCode);
87095
87161
  if (useScopedApiHeaders && resolvedExtraHeaders) {
87096
- await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, baseUrl));
87162
+ await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, configBaseUrl));
87097
87163
  }
87098
87164
  const headless = (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production" || IS_CLOUD2;
87099
- logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(baseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}`);
87165
+ logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(configBaseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}${configBaseUrl !== baseUrl ? ` (elected @api origin; app BASE_URL ${JSON.stringify(baseUrl)})` : ""}`);
87100
87166
  const absTestDir = runDir.replace(/\\/g, "/");
87101
87167
  const absResultsFile = (0, path_1.join)(runDir, "results.json").replace(/\\/g, "/");
87102
87168
  const absOutputDir = (0, path_1.join)(runDir, "test-results").replace(/\\/g, "/");
@@ -87120,7 +87186,7 @@ module.exports = {
87120
87186
  timeout: ${usesRealInboxWait ? 24e4 : 6e4},
87121
87187
  retries: 0,
87122
87188
  use: {
87123
- baseURL: ${JSON.stringify(baseUrl)},
87189
+ baseURL: ${JSON.stringify(configBaseUrl)},
87124
87190
  ${storageStateLine}
87125
87191
  ${extraHeadersLine}
87126
87192
  browserName: 'chromium',
@@ -87180,6 +87246,9 @@ module.exports = {
87180
87246
  }
87181
87247
  }
87182
87248
  const childTestVariables = { ...testVariables ?? {} };
87249
+ if (isApiTest2 && options.apiBaseUrl && !childTestVariables["API_BASE_URL"]) {
87250
+ childTestVariables["API_BASE_URL"] = options.apiBaseUrl;
87251
+ }
87183
87252
  const trustedRuntimeEnv = {
87184
87253
  ...isolation.env,
87185
87254
  // Generated callbacks receive only a random loopback capability. The global
@@ -350851,7 +350920,7 @@ var require_package4 = __commonJS({
350851
350920
  "package.json"(exports2, module2) {
350852
350921
  module2.exports = {
350853
350922
  name: "@validate.qa/runner",
350854
- version: "1.0.62",
350923
+ version: "1.0.64",
350855
350924
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350856
350925
  bin: {
350857
350926
  "validate-runner": "dist/cli.js"
@@ -358447,6 +358516,7 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
358447
358516
  const runNativeWithLiveBrowser = (nativeOptions) => (0, import_runner_core.executeTestViaNativePlaywright)({
358448
358517
  authStandingMode: authPlan.standingHeadersMode,
358449
358518
  storageStatePath: wrapperStorageStatePath,
358519
+ apiBaseUrl: run2.apiBaseUrl,
358450
358520
  ...nativeOptions,
358451
358521
  liveBrowserHandle,
358452
358522
  onLiveBrowserSnapshot: requestLiveBrowserHeartbeat
@@ -358857,7 +358927,9 @@ ${finalVerifyResult.logs ?? ""}`;
358857
358927
  } else {
358858
358928
  const xo = resolveCrossOriginConfigOverride({
358859
358929
  appOriginEnabled: isAppOriginResolutionEnabled(),
358860
- baseUrl: run2.baseUrl,
358930
+ // An @api run anchored on an elected execution origin must be judged against THAT
358931
+ // origin, or a correctly-anchored call reads as "wrong origin" (gate-review tweak).
358932
+ baseUrl: run2.apiBaseUrl ?? run2.baseUrl,
358861
358933
  composedError,
358862
358934
  verdicts: enrichedSteps.map((s) => s.verdict),
358863
358935
  apiCalls: rawSteps.flatMap((s) => s.apiCalls ?? []),
package/dist/cli.mjs CHANGED
@@ -5775,6 +5775,53 @@ var init_analytics_url = __esm({
5775
5775
  }
5776
5776
  });
5777
5777
 
5778
+ // ../shared/dist/api-endpoint-hygiene.js
5779
+ function isAssetLikePath(path) {
5780
+ return ASSET_SEGMENT_RE.test(path ?? "");
5781
+ }
5782
+ var ASSET_SEGMENT_RE;
5783
+ var init_api_endpoint_hygiene = __esm({
5784
+ "../shared/dist/api-endpoint-hygiene.js"() {
5785
+ "use strict";
5786
+ ASSET_SEGMENT_RE = /(?:^|\/)(?:assets|static|public|img|images|media|fonts|_next|locales)(?:\/|$)/i;
5787
+ }
5788
+ });
5789
+
5790
+ // ../shared/dist/auth-provider-hosts.js
5791
+ function isAuthProviderHost(host) {
5792
+ if (!host)
5793
+ return false;
5794
+ const h = host.toLowerCase();
5795
+ return AUTH_PROVIDER_HOST_SIGNATURES.some((sig) => sig.startsWith(".") ? h.endsWith(sig) : h.includes(sig));
5796
+ }
5797
+ var AUTH_PROVIDER_HOST_SIGNATURES, AUTH_PATH_SIGNATURE;
5798
+ var init_auth_provider_hosts = __esm({
5799
+ "../shared/dist/auth-provider-hosts.js"() {
5800
+ "use strict";
5801
+ AUTH_PROVIDER_HOST_SIGNATURES = [
5802
+ "clerk.",
5803
+ // clerk.<app-domain> — Clerk Frontend API
5804
+ ".auth0.com",
5805
+ ".okta.com",
5806
+ ".oktapreview.com",
5807
+ "cognito-idp.",
5808
+ ".amazoncognito.com",
5809
+ "identitytoolkit.googleapis.com",
5810
+ // Firebase Auth
5811
+ "securetoken.googleapis.com",
5812
+ ".supabase.co",
5813
+ ".stytch.com",
5814
+ ".workos.com",
5815
+ ".frontegg.com",
5816
+ ".kinde.com",
5817
+ "login.microsoftonline.com",
5818
+ ".b2clogin.com",
5819
+ "accounts.google.com"
5820
+ ];
5821
+ AUTH_PATH_SIGNATURE = /(?:sign[_-]?ins?|first_factor|second_factor|prepare_verification|\/oauth\/|\/authorize\b|\/authenticate\b|openid-connect\/token|\/userinfo\b|\/passwordless)/i;
5822
+ }
5823
+ });
5824
+
5778
5825
  // ../shared/dist/index.js
5779
5826
  var dist_exports = {};
5780
5827
  __export(dist_exports, {
@@ -5786,6 +5833,8 @@ __export(dist_exports, {
5786
5833
  API_AUTH_HEADERS_ENV_KEY: () => API_AUTH_HEADERS_ENV_KEY,
5787
5834
  API_PREFIX: () => API_PREFIX,
5788
5835
  AUDIO_CHUNK_DURATION_MS: () => AUDIO_CHUNK_DURATION_MS,
5836
+ AUTH_PATH_SIGNATURE: () => AUTH_PATH_SIGNATURE,
5837
+ AUTH_PROVIDER_HOST_SIGNATURES: () => AUTH_PROVIDER_HOST_SIGNATURES,
5789
5838
  AUTH_STATE_EXPIRY_SKEW_MS: () => AUTH_STATE_EXPIRY_SKEW_MS,
5790
5839
  AUTH_TAG_COOKIE_STATE: () => AUTH_TAG_COOKIE_STATE,
5791
5840
  AUTH_TAG_LOGIN_BEARER: () => AUTH_TAG_LOGIN_BEARER,
@@ -5903,6 +5952,8 @@ __export(dist_exports, {
5903
5952
  isAddonType: () => isAddonType,
5904
5953
  isApiTest: () => isApiTest,
5905
5954
  isAppOriginResolutionEnabled: () => isAppOriginResolutionEnabled,
5955
+ isAssetLikePath: () => isAssetLikePath,
5956
+ isAuthProviderHost: () => isAuthProviderHost,
5906
5957
  isAuthReadinessGuardEnabled: () => isAuthReadinessGuardEnabled,
5907
5958
  isAuthTokenName: () => isAuthTokenName,
5908
5959
  isBlockedEnvVar: () => isBlockedEnvVar,
@@ -6003,6 +6054,8 @@ var init_dist = __esm({
6003
6054
  init_feature_flags();
6004
6055
  init_env_flags();
6005
6056
  init_analytics_url();
6057
+ init_api_endpoint_hygiene();
6058
+ init_auth_provider_hosts();
6006
6059
  }
6007
6060
  });
6008
6061
 
@@ -73460,6 +73513,7 @@ var require_inbox_tools = __commonJS({
73460
73513
  legacyEmail,
73461
73514
  tag,
73462
73515
  usePlusTag: email !== baseEmail,
73516
+ allowPlainFallback: opts.allowPlainFallback ?? true,
73463
73517
  passwordKey: opts.passwordKey ?? "TEST_USER_PASSWORD",
73464
73518
  provisioned: false,
73465
73519
  // Floor reads at run start so a verification email from a PRIOR run (the
@@ -73622,6 +73676,9 @@ var require_inbox_tools = __commonJS({
73622
73676
  const { state: state2 } = ctx;
73623
73677
  const plain = args.plain === true || args.plain === "true";
73624
73678
  const restore = args.plain === false || args.plain === "false";
73679
+ if (plain && !state2.allowPlainFallback) {
73680
+ return err("The bare inbox address is unavailable for this brokered run because it is shared across projects. Keep using the project-scoped +tag address; if the app rejects plus-addressing, report email verification as blocked.");
73681
+ }
73625
73682
  if (plain && state2.usePlusTag) {
73626
73683
  state2.email = state2.baseEmail;
73627
73684
  state2.usePlusTag = false;
@@ -75463,7 +75520,10 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
75463
75520
  } else if (registerRequested && ctx.inboxBroker?.address && ctx.inboxBrokerRead) {
75464
75521
  inboxState = (0, inbox_tools_js_1.createInboxRunState)({ address: ctx.inboxBroker.address }, {
75465
75522
  tagSeed: targetAppId ?? ctx.projectId,
75466
- projectScope: ctx.projectId
75523
+ projectScope: ctx.projectId,
75524
+ // A user-controlled local runner must never read the shared bare inbox:
75525
+ // only the project-scoped +tag is an authorization boundary.
75526
+ allowPlainFallback: false
75467
75527
  });
75468
75528
  inboxReader = new brokered_inbox_reader_js_1.BrokeredInboxReader(ctx.inboxBrokerRead);
75469
75529
  await (0, inbox_tools_js_1.applyAndPersistInboxIdentity)({
@@ -85214,6 +85274,7 @@ var require_api_call_redaction = __commonJS({
85214
85274
  exports.buildResponseExcerpt = buildResponseExcerpt;
85215
85275
  exports.isTextExcerptable = isTextExcerptable;
85216
85276
  exports.buildApiCallSummary = buildApiCallSummary2;
85277
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
85217
85278
  exports.STATIC_EXTENSIONS = /* @__PURE__ */ new Set([
85218
85279
  ".js",
85219
85280
  ".css",
@@ -85231,7 +85292,9 @@ var require_api_call_redaction = __commonJS({
85231
85292
  ".webp",
85232
85293
  ".avif",
85233
85294
  ".mp4",
85234
- ".webm"
85295
+ ".webm",
85296
+ ".lottie",
85297
+ ".webmanifest"
85235
85298
  ]);
85236
85299
  exports.SECURITY_HEADER_NAMES = /* @__PURE__ */ new Set([
85237
85300
  // CORS & core security
@@ -85320,6 +85383,8 @@ var require_api_call_redaction = __commonJS({
85320
85383
  return false;
85321
85384
  if (path.includes("/api/") || path.includes("/graphql"))
85322
85385
  return true;
85386
+ if (ext.toLowerCase() === ".json" && (0, shared_1.isAssetLikePath)(path))
85387
+ return false;
85323
85388
  if (contentType?.includes("application/json"))
85324
85389
  return true;
85325
85390
  if (contentType?.includes("application/graphql"))
@@ -86874,6 +86939,7 @@ var require_playwright_native = __commonJS({
86874
86939
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86875
86940
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86876
86941
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86942
+ const configBaseUrl = isApiTest2 && options.apiBaseUrl ? options.apiBaseUrl : baseUrl;
86877
86943
  const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86878
86944
  const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86879
86945
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
@@ -87077,7 +87143,7 @@ test.afterEach(async ({ page }, testInfo) => {
87077
87143
  if (!importMatch) {
87078
87144
  logs2.push("\u26A0 Could not find @playwright/test import - animation disabling NOT injected");
87079
87145
  }
87080
- const useScopedApiHeaders = isApiTest2 && !!resolvedExtraHeaders && !!importMatch && !!baseUrl;
87146
+ const useScopedApiHeaders = isApiTest2 && !!resolvedExtraHeaders && !!importMatch && !!configBaseUrl;
87081
87147
  const authDelivery = { standingHeadersConfigured: !!resolvedExtraHeaders, standingHeadersInjected: useScopedApiHeaders };
87082
87148
  if (resolvedExtraHeaders && !useScopedApiHeaders) {
87083
87149
  logs2.push("\u26A0 Standing API auth headers were configured but could not be installed origin-scoped \u2014 failing closed (no global fallback).");
@@ -87098,10 +87164,10 @@ test.afterEach(async ({ page }, testInfo) => {
87098
87164
  }
87099
87165
  await (0, promises_1.writeFile)((0, path_1.join)(runDir, "test.spec.ts"), instrumentedCode);
87100
87166
  if (useScopedApiHeaders && resolvedExtraHeaders) {
87101
- await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, baseUrl));
87167
+ await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, configBaseUrl));
87102
87168
  }
87103
87169
  const headless = (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production" || IS_CLOUD2;
87104
- logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(baseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}`);
87170
+ logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(configBaseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}${configBaseUrl !== baseUrl ? ` (elected @api origin; app BASE_URL ${JSON.stringify(baseUrl)})` : ""}`);
87105
87171
  const absTestDir = runDir.replace(/\\/g, "/");
87106
87172
  const absResultsFile = (0, path_1.join)(runDir, "results.json").replace(/\\/g, "/");
87107
87173
  const absOutputDir = (0, path_1.join)(runDir, "test-results").replace(/\\/g, "/");
@@ -87125,7 +87191,7 @@ module.exports = {
87125
87191
  timeout: ${usesRealInboxWait ? 24e4 : 6e4},
87126
87192
  retries: 0,
87127
87193
  use: {
87128
- baseURL: ${JSON.stringify(baseUrl)},
87194
+ baseURL: ${JSON.stringify(configBaseUrl)},
87129
87195
  ${storageStateLine}
87130
87196
  ${extraHeadersLine}
87131
87197
  browserName: 'chromium',
@@ -87185,6 +87251,9 @@ module.exports = {
87185
87251
  }
87186
87252
  }
87187
87253
  const childTestVariables = { ...testVariables ?? {} };
87254
+ if (isApiTest2 && options.apiBaseUrl && !childTestVariables["API_BASE_URL"]) {
87255
+ childTestVariables["API_BASE_URL"] = options.apiBaseUrl;
87256
+ }
87188
87257
  const trustedRuntimeEnv = {
87189
87258
  ...isolation.env,
87190
87259
  // Generated callbacks receive only a random loopback capability. The global
@@ -350856,7 +350925,7 @@ var require_package4 = __commonJS({
350856
350925
  "package.json"(exports, module) {
350857
350926
  module.exports = {
350858
350927
  name: "@validate.qa/runner",
350859
- version: "1.0.62",
350928
+ version: "1.0.64",
350860
350929
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350861
350930
  bin: {
350862
350931
  "validate-runner": "dist/cli.js"
@@ -358455,6 +358524,7 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
358455
358524
  const runNativeWithLiveBrowser = (nativeOptions) => (0, import_runner_core.executeTestViaNativePlaywright)({
358456
358525
  authStandingMode: authPlan.standingHeadersMode,
358457
358526
  storageStatePath: wrapperStorageStatePath,
358527
+ apiBaseUrl: run2.apiBaseUrl,
358458
358528
  ...nativeOptions,
358459
358529
  liveBrowserHandle,
358460
358530
  onLiveBrowserSnapshot: requestLiveBrowserHeartbeat
@@ -358865,7 +358935,9 @@ ${finalVerifyResult.logs ?? ""}`;
358865
358935
  } else {
358866
358936
  const xo = resolveCrossOriginConfigOverride({
358867
358937
  appOriginEnabled: isAppOriginResolutionEnabled(),
358868
- baseUrl: run2.baseUrl,
358938
+ // An @api run anchored on an elected execution origin must be judged against THAT
358939
+ // origin, or a correctly-anchored call reads as "wrong origin" (gate-review tweak).
358940
+ baseUrl: run2.apiBaseUrl ?? run2.baseUrl,
358869
358941
  composedError,
358870
358942
  verdicts: enrichedSteps.map((s) => s.verdict),
358871
358943
  apiCalls: rawSteps.flatMap((s) => s.apiCalls ?? []),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "description": "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
5
5
  "bin": {
6
6
  "validate-runner": "dist/cli.js"