@validate.qa/runner 1.0.101 → 1.0.103
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 +3 -0
- package/dist/{chunk-SN3PN4G4.mjs → chunk-36AWDKPL.mjs} +6 -2
- package/dist/{chunk-CYWHPXNZ.mjs → chunk-7SH3COMQ.mjs} +1 -1
- package/dist/{chunk-BBTK6OX6.mjs → chunk-BECCGMU4.mjs} +383 -11
- package/dist/{chunk-4SZC5ZX3.mjs → chunk-CG75I3ZZ.mjs} +25477 -5374
- package/dist/{chunk-TPU42VH2.mjs → chunk-CMM4DOXC.mjs} +10 -5
- package/dist/{chunk-M3VZGHZQ.mjs → chunk-NNJYKR3O.mjs} +22 -11
- package/dist/{chunk-IGXGSDE3.mjs → chunk-OTKJZIOD.mjs} +1298 -384
- package/dist/{chunk-CO5KHIVX.mjs → chunk-TK5KEGNW.mjs} +1 -1
- package/dist/{chunk-FQUH2PU2.mjs → chunk-WVLBQDFP.mjs} +140 -7
- package/dist/{chunk-2OKZY3WN.mjs → chunk-YI3ZC2XI.mjs} +2 -2
- package/dist/{chunk-XZUUBMP3.mjs → chunk-YIM746WO.mjs} +1 -1
- package/dist/cli.js +140692 -118903
- package/dist/cli.mjs +362 -108
- package/dist/credential-mcp-server.js +1402 -350
- package/dist/credential-mcp-server.mjs +3 -3
- package/dist/discovery-mcp-server.js +1330 -401
- package/dist/discovery-mcp-server.mjs +4 -4
- package/dist/dist-2G7YTNH5.mjs +17 -0
- package/dist/inbox-mcp-server.js +1676 -629
- package/dist/inbox-mcp-server.mjs +3 -3
- package/dist/route-seed-worker.js +1244 -330
- package/dist/route-seed-worker.mjs +4 -4
- package/dist/run-write-guard-preload.js +1622 -332
- package/dist/run-write-guard-preload.mjs +4 -4
- package/dist/run-write-guard.js +1622 -332
- package/dist/run-write-guard.mjs +3 -3
- package/dist/spec-driver.js +1 -1
- package/dist/spec-driver.mjs +1 -1
- package/package.json +3 -2
- package/dist/dist-VTPBY2C4.mjs +0 -17
package/dist/run-write-guard.js
CHANGED
|
@@ -91,13 +91,13 @@ function isBlockedEnvVar(key) {
|
|
|
91
91
|
function sanitizeTestVariables(vars) {
|
|
92
92
|
if (!vars)
|
|
93
93
|
return {};
|
|
94
|
-
const
|
|
94
|
+
const clean3 = {};
|
|
95
95
|
for (const [key, value] of Object.entries(vars)) {
|
|
96
96
|
if (!isBlockedEnvVar(key)) {
|
|
97
|
-
|
|
97
|
+
clean3[key] = value;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
return
|
|
100
|
+
return clean3;
|
|
101
101
|
}
|
|
102
102
|
function buildSandboxedEnv(processEnv, testVariables) {
|
|
103
103
|
const env = {};
|
|
@@ -1554,9 +1554,40 @@ function semanticTarget(label, platform, base) {
|
|
|
1554
1554
|
}
|
|
1555
1555
|
};
|
|
1556
1556
|
}
|
|
1557
|
+
function androidResourceOwners(value) {
|
|
1558
|
+
const owners = [];
|
|
1559
|
+
for (const match of value.matchAll(ANDROID_RESOURCE_ID_SUFFIX_RE)) {
|
|
1560
|
+
let runStart = match.index;
|
|
1561
|
+
while (runStart > 0 && /[a-z0-9_.]/i.test(value[runStart - 1]))
|
|
1562
|
+
runStart--;
|
|
1563
|
+
const owner = ownerAtEndOfRun(value.slice(runStart, match.index));
|
|
1564
|
+
if (owner !== null)
|
|
1565
|
+
owners.push(owner);
|
|
1566
|
+
}
|
|
1567
|
+
return owners;
|
|
1568
|
+
}
|
|
1569
|
+
function ownerAtEndOfRun(run) {
|
|
1570
|
+
const segments = run.split(".");
|
|
1571
|
+
const last = segments.length - 1;
|
|
1572
|
+
const startsWithLetter = (segment) => /^[a-z]/i.test(segment);
|
|
1573
|
+
if (last < 1 || !startsWithLetter(segments[last]))
|
|
1574
|
+
return null;
|
|
1575
|
+
let first = last;
|
|
1576
|
+
while (first > 0 && startsWithLetter(segments[first - 1]))
|
|
1577
|
+
first--;
|
|
1578
|
+
let offset = 0;
|
|
1579
|
+
for (let i = 0; i < first - 1; i++)
|
|
1580
|
+
offset += segments[i].length + 1;
|
|
1581
|
+
if (first > 0) {
|
|
1582
|
+
const letterAt = segments[first - 1].search(/[a-z]/i);
|
|
1583
|
+
if (letterAt >= 0)
|
|
1584
|
+
return run.slice(offset + letterAt);
|
|
1585
|
+
offset += segments[first - 1].length + 1;
|
|
1586
|
+
}
|
|
1587
|
+
return first < last ? run.slice(offset) : null;
|
|
1588
|
+
}
|
|
1557
1589
|
function containsForeignAppPackage(value, targetAppId) {
|
|
1558
|
-
for (const
|
|
1559
|
-
const owner = match[1];
|
|
1590
|
+
for (const owner of androidResourceOwners(value)) {
|
|
1560
1591
|
if (targetAppId && owner !== targetAppId && !owner.startsWith(`${targetAppId}.`))
|
|
1561
1592
|
return true;
|
|
1562
1593
|
}
|
|
@@ -1693,7 +1724,7 @@ function healMobileTestSteps(input) {
|
|
|
1693
1724
|
summary: changed ? uniq(summary).slice(0, 12) : []
|
|
1694
1725
|
};
|
|
1695
1726
|
}
|
|
1696
|
-
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE,
|
|
1727
|
+
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE, ANDROID_RESOURCE_ID_SUFFIX_RE, COMMON_EXTERNAL_PREFIXES;
|
|
1697
1728
|
var init_mobile_step_healer = __esm({
|
|
1698
1729
|
"../shared/dist/mobile-step-healer.js"() {
|
|
1699
1730
|
"use strict";
|
|
@@ -1714,7 +1745,7 @@ var init_mobile_step_healer = __esm({
|
|
|
1714
1745
|
"assertStateDelta"
|
|
1715
1746
|
]);
|
|
1716
1747
|
FOREIGN_PACKAGE_RE = /\b[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*){2,}\b/gi;
|
|
1717
|
-
|
|
1748
|
+
ANDROID_RESOURCE_ID_SUFFIX_RE = /:id\//gi;
|
|
1718
1749
|
COMMON_EXTERNAL_PREFIXES = [
|
|
1719
1750
|
"com.android.",
|
|
1720
1751
|
"com.google.",
|
|
@@ -3424,7 +3455,7 @@ var init_assertion_classifier = __esm({
|
|
|
3424
3455
|
// toHaveCount(0) stays tier 4 (absence proof) via TIER4_PATTERNS.
|
|
3425
3456
|
[/\.toHaveCount\s*\(\s*[1-9]\d*\s*\)/, "non-zero toHaveCount asserts a record count that changes between runs"],
|
|
3426
3457
|
// parenthesised counts like "(3)" or "[12]" in text - but not Playwright method args
|
|
3427
|
-
[
|
|
3458
|
+
[/\((?<!\.\w{3,20}\s*\()\s*\d+\s*\)(?!\s*(?:[,;]\s*)?\))/i, "parenthesised count is session-specific"],
|
|
3428
3459
|
// bare email addresses in assertion content
|
|
3429
3460
|
[/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i, "email address is user-specific"],
|
|
3430
3461
|
// currency/balance amounts (dynamic account data)
|
|
@@ -3670,7 +3701,7 @@ var init_assertion_proof = __esm({
|
|
|
3670
3701
|
PRESENCE_MATCHER = /\.(?:toBeVisible|toBeAttached|toBeEnabled|toBeInViewport|toBeEditable|toBeFocused)\s*\(|\.toHaveCount\s*\(\s*1\s*\)/;
|
|
3671
3702
|
TEXT_MATCHER = /\.(?:toHaveText|toContainText)\s*\(/;
|
|
3672
3703
|
ANY_VALUE_SOURCE = /^(?:\.|\\S|\\w|\\d|\[\^\\s\]|\[0-9\]|\[\\d\]|\[\\w\]|\[\\s\\S\])[+*]?\??$/;
|
|
3673
|
-
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s
|
|
3704
|
+
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s*[,)]/;
|
|
3674
3705
|
EMPTY_NOT_VALUE = /\.not\s*\.\s*toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/;
|
|
3675
3706
|
TEXT_MATCHER_LITERAL = /\.(?:toHaveText|toContainText)\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
3676
3707
|
GET_BY_TEXT_LITERAL = /getByText\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
@@ -3687,7 +3718,7 @@ var init_assertion_proof = __esm({
|
|
|
3687
3718
|
DATA_ROLE = /getByRole\s*\(\s*['"`](?:dialog|alertdialog|alert|cell|gridcell|row|rowheader|columnheader|listitem|article|option|status|note|tooltip|paragraph|term|definition|log|marquee|timer|meter)['"`]/gi;
|
|
3688
3719
|
TEXT_LOCATOR = /\.getByText\s*\(|\.filter\s*\(\s*\{\s*hasText\s*:/g;
|
|
3689
3720
|
CSS_LOCATOR = /\.locator\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/g;
|
|
3690
|
-
SPECIFIC_CSS = /\[[^\]]*=|#[\w-]|has-text|:text/;
|
|
3721
|
+
SPECIFIC_CSS = /\[[^\][=]*=|#[\w-]|has-text|:text/;
|
|
3691
3722
|
}
|
|
3692
3723
|
});
|
|
3693
3724
|
|
|
@@ -4651,22 +4682,37 @@ function classifyAuthHandoffIntent(text) {
|
|
|
4651
4682
|
function withoutIdpUrlAsserts(code) {
|
|
4652
4683
|
return code.replace(/\.(?:toHaveURL|waitForURL)\s*\((?:[^)(]|\([^)]*\))*\)/g, (match) => /accountchooser|accounts\.google|appleid\.apple|login\.microsoftonline|\/v\d+\/signin|oauth/i.test(match) ? "" : match);
|
|
4653
4684
|
}
|
|
4685
|
+
function stripLineComment(line) {
|
|
4686
|
+
let from = line.length;
|
|
4687
|
+
while (from > 0) {
|
|
4688
|
+
const c = line.charCodeAt(from - 1);
|
|
4689
|
+
if (c === 10 || c === 13 || c === 8232 || c === 8233)
|
|
4690
|
+
break;
|
|
4691
|
+
from--;
|
|
4692
|
+
}
|
|
4693
|
+
const at = line.indexOf("//", from);
|
|
4694
|
+
return at < 0 ? line : line.slice(0, at);
|
|
4695
|
+
}
|
|
4654
4696
|
function stripComments(code) {
|
|
4655
|
-
return replaceBlockComments(code, () => "").split("\n").map(
|
|
4697
|
+
return replaceBlockComments(code, () => "").split("\n").map(stripLineComment).join("\n");
|
|
4656
4698
|
}
|
|
4657
|
-
function
|
|
4658
|
-
const
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
let depth = 0;
|
|
4662
|
-
for (let i = open; i < code.length; i++) {
|
|
4699
|
+
function closingParens(code) {
|
|
4700
|
+
const close = new Int32Array(code.length).fill(-1);
|
|
4701
|
+
const open = [];
|
|
4702
|
+
for (let i = 0; i < code.length; i++) {
|
|
4663
4703
|
const c = code[i];
|
|
4664
4704
|
if (c === "(")
|
|
4665
|
-
|
|
4666
|
-
else if (c === ")" &&
|
|
4667
|
-
|
|
4705
|
+
open.push(i);
|
|
4706
|
+
else if (c === ")" && open.length > 0)
|
|
4707
|
+
close[open.pop()] = i;
|
|
4668
4708
|
}
|
|
4669
|
-
return
|
|
4709
|
+
return close;
|
|
4710
|
+
}
|
|
4711
|
+
function balancedCall(code, close, start) {
|
|
4712
|
+
const open = code.indexOf("(", start);
|
|
4713
|
+
if (open < 0 || close[open] < 0)
|
|
4714
|
+
return null;
|
|
4715
|
+
return { inner: code.slice(open + 1, close[open]), end: close[open] };
|
|
4670
4716
|
}
|
|
4671
4717
|
function resolveLocator(code, subject) {
|
|
4672
4718
|
const id = subject.trim().match(/^([A-Za-z_$][\w$]*)$/);
|
|
@@ -4714,8 +4760,10 @@ function isAuthHandoffDismissCode(code) {
|
|
|
4714
4760
|
const expects = [];
|
|
4715
4761
|
const re = new RegExp(EXPECT_CALL_RE.source, "g");
|
|
4716
4762
|
let match;
|
|
4763
|
+
let close = null;
|
|
4717
4764
|
while (match = re.exec(body)) {
|
|
4718
|
-
|
|
4765
|
+
close ??= closingParens(body);
|
|
4766
|
+
const found = balancedCall(body, close, match.index);
|
|
4719
4767
|
if (found)
|
|
4720
4768
|
expects.push({ inner: found.inner, tail: body.slice(found.end, found.end + 48) });
|
|
4721
4769
|
}
|
|
@@ -4760,12 +4808,209 @@ var init_auth_handoff_coverage = __esm({
|
|
|
4760
4808
|
}
|
|
4761
4809
|
});
|
|
4762
4810
|
|
|
4811
|
+
// ../shared/dist/auth-plan.js
|
|
4812
|
+
function hasInlineLoginSteps(playwrightCode) {
|
|
4813
|
+
if (!playwrightCode)
|
|
4814
|
+
return false;
|
|
4815
|
+
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
4816
|
+
}
|
|
4817
|
+
function hasGeneratedAuthGuard(playwrightCode) {
|
|
4818
|
+
if (!playwrightCode)
|
|
4819
|
+
return false;
|
|
4820
|
+
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
4821
|
+
}
|
|
4822
|
+
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
4823
|
+
if (!sharedAuthInjectEnabled)
|
|
4824
|
+
return false;
|
|
4825
|
+
if (tags.includes("@auth"))
|
|
4826
|
+
return false;
|
|
4827
|
+
if (tags.includes("@api"))
|
|
4828
|
+
return true;
|
|
4829
|
+
if (!tags.includes("@needs-auth"))
|
|
4830
|
+
return false;
|
|
4831
|
+
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
4832
|
+
return true;
|
|
4833
|
+
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
4834
|
+
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
4835
|
+
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
4836
|
+
}
|
|
4837
|
+
function codeReadsStoredCredentials(code) {
|
|
4838
|
+
if (!code)
|
|
4839
|
+
return false;
|
|
4840
|
+
if (/__vqaLogin\b/.test(code))
|
|
4841
|
+
return true;
|
|
4842
|
+
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
4843
|
+
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
4844
|
+
return true;
|
|
4845
|
+
}
|
|
4846
|
+
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
4847
|
+
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
4848
|
+
return true;
|
|
4849
|
+
}
|
|
4850
|
+
return false;
|
|
4851
|
+
}
|
|
4852
|
+
function explicitAuthTypeTags(t) {
|
|
4853
|
+
const found = /* @__PURE__ */ new Set();
|
|
4854
|
+
for (const tag of t) {
|
|
4855
|
+
if (AUTH_TYPE_TAGS.includes(tag))
|
|
4856
|
+
found.add(tag);
|
|
4857
|
+
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
4858
|
+
found.add(AUTH_TAG_ALIASES[tag]);
|
|
4859
|
+
}
|
|
4860
|
+
return [...found];
|
|
4861
|
+
}
|
|
4862
|
+
function invalidPlan(configurationError) {
|
|
4863
|
+
return {
|
|
4864
|
+
version: 1,
|
|
4865
|
+
source: "invalid",
|
|
4866
|
+
acquisition: "unsupported",
|
|
4867
|
+
presentation: "none",
|
|
4868
|
+
needsCookieState: false,
|
|
4869
|
+
needsStandingHeaders: false,
|
|
4870
|
+
standingHeadersMode: "none",
|
|
4871
|
+
needsLoginCreds: false,
|
|
4872
|
+
requiredEnvKeys: [],
|
|
4873
|
+
configurationError
|
|
4874
|
+
};
|
|
4875
|
+
}
|
|
4876
|
+
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
4877
|
+
return {
|
|
4878
|
+
version: 1,
|
|
4879
|
+
source: "explicit",
|
|
4880
|
+
authTypeTag: authTypeTag2,
|
|
4881
|
+
acquisition,
|
|
4882
|
+
presentation,
|
|
4883
|
+
needsCookieState: opts.cookie,
|
|
4884
|
+
needsStandingHeaders: opts.standingMode === "required",
|
|
4885
|
+
standingHeadersMode: opts.standingMode,
|
|
4886
|
+
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
4887
|
+
requiredEnvKeys: opts.requiredEnvKeys
|
|
4888
|
+
};
|
|
4889
|
+
}
|
|
4890
|
+
function deriveAuthPlan(tags, code, opts) {
|
|
4891
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
4892
|
+
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
4893
|
+
const isApi = t.includes("@api");
|
|
4894
|
+
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
4895
|
+
if (explicit.length > 0) {
|
|
4896
|
+
if (t.includes("@auth")) {
|
|
4897
|
+
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
4898
|
+
}
|
|
4899
|
+
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
4900
|
+
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
4901
|
+
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
4902
|
+
switch (loginCompose[0]) {
|
|
4903
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
4904
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
4905
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
4906
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
4907
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
4908
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
if (explicit.length > 1) {
|
|
4912
|
+
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
4913
|
+
}
|
|
4914
|
+
switch (explicit[0]) {
|
|
4915
|
+
case AUTH_TAG_UNSUPPORTED:
|
|
4916
|
+
return {
|
|
4917
|
+
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
4918
|
+
};
|
|
4919
|
+
case AUTH_TAG_NONE:
|
|
4920
|
+
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
4921
|
+
case AUTH_TAG_STANDING:
|
|
4922
|
+
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
4923
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
4924
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
4925
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
4926
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
4927
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
4928
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
4932
|
+
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
4933
|
+
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
4934
|
+
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
4935
|
+
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
4936
|
+
return {
|
|
4937
|
+
version: 1,
|
|
4938
|
+
source: "legacy",
|
|
4939
|
+
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
4940
|
+
presentation: authedLegacy ? "cookie" : "none",
|
|
4941
|
+
needsCookieState: cookie,
|
|
4942
|
+
needsStandingHeaders: false,
|
|
4943
|
+
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
4944
|
+
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
4945
|
+
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
4946
|
+
needsLoginCreds,
|
|
4947
|
+
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4950
|
+
function authTypeTag(tags) {
|
|
4951
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
4952
|
+
const explicit = explicitAuthTypeTags(t);
|
|
4953
|
+
return explicit.length === 1 ? explicit[0] : void 0;
|
|
4954
|
+
}
|
|
4955
|
+
var AUTH_TAG_COOKIE_STATE, AUTH_TAG_LOGIN_COOKIE, AUTH_TAG_LOGIN_BEARER, AUTH_TAG_STANDING, AUTH_TAG_NONE, AUTH_TAG_UNSUPPORTED, AUTH_TYPE_TAGS, AUTH_TAG_ALIASES, TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY;
|
|
4956
|
+
var init_auth_plan = __esm({
|
|
4957
|
+
"../shared/dist/auth-plan.js"() {
|
|
4958
|
+
"use strict";
|
|
4959
|
+
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
4960
|
+
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
4961
|
+
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
4962
|
+
AUTH_TAG_STANDING = "@auth-standing";
|
|
4963
|
+
AUTH_TAG_NONE = "@auth-none";
|
|
4964
|
+
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
4965
|
+
AUTH_TYPE_TAGS = [
|
|
4966
|
+
AUTH_TAG_COOKIE_STATE,
|
|
4967
|
+
AUTH_TAG_LOGIN_COOKIE,
|
|
4968
|
+
AUTH_TAG_LOGIN_BEARER,
|
|
4969
|
+
AUTH_TAG_STANDING,
|
|
4970
|
+
AUTH_TAG_NONE,
|
|
4971
|
+
AUTH_TAG_UNSUPPORTED
|
|
4972
|
+
];
|
|
4973
|
+
AUTH_TAG_ALIASES = {
|
|
4974
|
+
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
4975
|
+
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
4976
|
+
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
4977
|
+
"@auth-api-key": AUTH_TAG_STANDING,
|
|
4978
|
+
"@auth-standing-header": AUTH_TAG_STANDING
|
|
4979
|
+
};
|
|
4980
|
+
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
4981
|
+
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
4982
|
+
}
|
|
4983
|
+
});
|
|
4984
|
+
|
|
4763
4985
|
// ../shared/dist/assertion-strength.js
|
|
4986
|
+
function parseLastActionProofMode(raw) {
|
|
4987
|
+
const v = (raw ?? "").trim().toLowerCase();
|
|
4988
|
+
return v === "on" || v === "shadow" ? v : "off";
|
|
4989
|
+
}
|
|
4990
|
+
function isUrlProof(stmt) {
|
|
4991
|
+
if (URL_PROOF.test(stmt))
|
|
4992
|
+
return true;
|
|
4993
|
+
let calls = 0;
|
|
4994
|
+
for (const open of stmt.matchAll(POLL_OPEN)) {
|
|
4995
|
+
if (++calls > POLL_CALLS_MAX)
|
|
4996
|
+
break;
|
|
4997
|
+
const from = open.index + open[0].length;
|
|
4998
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
4999
|
+
if (args === null)
|
|
5000
|
+
continue;
|
|
5001
|
+
const subject = pollSubject(args);
|
|
5002
|
+
if (!POLL_PAGE_URL.test(subject))
|
|
5003
|
+
continue;
|
|
5004
|
+
if (!POLL_PAGE_URL_ONLY.test(subject) || PAGE_VALUE_MATCHER.test(stmt.slice(from + args.length)))
|
|
5005
|
+
return true;
|
|
5006
|
+
}
|
|
5007
|
+
return false;
|
|
5008
|
+
}
|
|
4764
5009
|
function liveExpectStatements(uncommented) {
|
|
4765
5010
|
const masked = maskedOutsideStrings(uncommented).split("\n");
|
|
4766
5011
|
return accumulateStatements(uncommented.split("\n")).filter((s) => EXPECT_STMT.test(s.stmt) && EXPECT_STMT.test(masked[s.startLine - 1] ?? ""));
|
|
4767
5012
|
}
|
|
4768
|
-
function
|
|
5013
|
+
function stripLineComment2(ln) {
|
|
4769
5014
|
let quote = null;
|
|
4770
5015
|
for (let i = 0; i < ln.length; i++) {
|
|
4771
5016
|
const c = ln[i];
|
|
@@ -4788,7 +5033,7 @@ function splitInteractionStatementsWithLines(lines) {
|
|
|
4788
5033
|
let depth = 0;
|
|
4789
5034
|
let scaffold = false;
|
|
4790
5035
|
for (let i = 0; i < lines.length; i++) {
|
|
4791
|
-
const ln =
|
|
5036
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
4792
5037
|
if (!ln)
|
|
4793
5038
|
continue;
|
|
4794
5039
|
const isContinuation = out.length > 0 && (ln.startsWith(".") || depth > 0 && !scaffold);
|
|
@@ -4812,7 +5057,7 @@ function testBlockIds(lines) {
|
|
|
4812
5057
|
let any = false;
|
|
4813
5058
|
let block = 0;
|
|
4814
5059
|
for (let i = 0; i < lines.length; i++) {
|
|
4815
|
-
const ln =
|
|
5060
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
4816
5061
|
if (!open) {
|
|
4817
5062
|
if (!TEST_BLOCK_OPEN.test(ln))
|
|
4818
5063
|
continue;
|
|
@@ -4896,7 +5141,7 @@ function expectSubjectSpan(stmt) {
|
|
|
4896
5141
|
}
|
|
4897
5142
|
return null;
|
|
4898
5143
|
}
|
|
4899
|
-
function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
5144
|
+
function resolveSubjectBindings(stmts, bindings, blockOfLine, boundAt) {
|
|
4900
5145
|
if (bindings.length === 0)
|
|
4901
5146
|
return [...stmts];
|
|
4902
5147
|
return stmts.map((item) => {
|
|
@@ -4919,14 +5164,22 @@ function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
|
4919
5164
|
subject = `${lead[1]}${found.expr.replace(/;\s*$/, "")}${subject.slice(lead[0].length)}`;
|
|
4920
5165
|
line = found.line;
|
|
4921
5166
|
}
|
|
4922
|
-
|
|
5167
|
+
const out = { ...item, stmt: `${item.stmt.slice(0, span.from)}${subject}${item.stmt.slice(span.to)}` };
|
|
5168
|
+
if (boundAt !== void 0 && line !== item.startLine)
|
|
5169
|
+
boundAt.set(out, line);
|
|
5170
|
+
return out;
|
|
4923
5171
|
});
|
|
4924
5172
|
}
|
|
4925
5173
|
function stripLoginScaffolding(code) {
|
|
4926
|
-
const
|
|
5174
|
+
const lines = code.split("\n");
|
|
5175
|
+
return keptScaffoldingLines(lines).map((i) => lines[i]).join("\n");
|
|
5176
|
+
}
|
|
5177
|
+
function keptScaffoldingLines(lines) {
|
|
5178
|
+
const kept = [];
|
|
4927
5179
|
let inAuth = false;
|
|
4928
5180
|
let inInbox = false;
|
|
4929
|
-
for (
|
|
5181
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5182
|
+
const ln = lines[i];
|
|
4930
5183
|
if (!inAuth && !inInbox && AUTH_START.test(ln)) {
|
|
4931
5184
|
inAuth = true;
|
|
4932
5185
|
continue;
|
|
@@ -4947,9 +5200,9 @@ function stripLoginScaffolding(code) {
|
|
|
4947
5200
|
}
|
|
4948
5201
|
if (LOGIN_CALL_LINE.test(ln))
|
|
4949
5202
|
continue;
|
|
4950
|
-
|
|
5203
|
+
kept.push(i);
|
|
4951
5204
|
}
|
|
4952
|
-
return
|
|
5205
|
+
return kept;
|
|
4953
5206
|
}
|
|
4954
5207
|
function stripCommentsAndLogs(code) {
|
|
4955
5208
|
return stripCoverageComments(code).split("\n").filter((ln) => !/^\s*console\./.test(ln)).join("\n");
|
|
@@ -5101,6 +5354,41 @@ function isVacuousErrorAbsence(stmt, presence) {
|
|
|
5101
5354
|
return false;
|
|
5102
5355
|
return !presence().includes(m[1]);
|
|
5103
5356
|
}
|
|
5357
|
+
function isVacuousAccountAbsence(stmt, shown, account) {
|
|
5358
|
+
if (!claimsAbsence(stmt))
|
|
5359
|
+
return false;
|
|
5360
|
+
if (!ABSENCE_MATCHER.test(stmt)) {
|
|
5361
|
+
const negated = NEGATED_TEXT.exec(stmt);
|
|
5362
|
+
if (!negated)
|
|
5363
|
+
return false;
|
|
5364
|
+
const read = account.exec(stmt.slice(negated.index));
|
|
5365
|
+
return read !== null && !shown().has(read[0]);
|
|
5366
|
+
}
|
|
5367
|
+
const m = account.exec(stmt);
|
|
5368
|
+
if (!m || shown().has(m[0]))
|
|
5369
|
+
return false;
|
|
5370
|
+
for (let at = endOfEnclosingCall(stmt, m.index + m[0].length); at < stmt.length; at = endOfEnclosingCall(stmt, at)) {
|
|
5371
|
+
SCOPING_STEP.lastIndex = at;
|
|
5372
|
+
if (SCOPING_STEP.test(stmt))
|
|
5373
|
+
return false;
|
|
5374
|
+
}
|
|
5375
|
+
return true;
|
|
5376
|
+
}
|
|
5377
|
+
function endOfEnclosingCall(stmt, from) {
|
|
5378
|
+
let depth = 0;
|
|
5379
|
+
for (let i = from; i < stmt.length; i++) {
|
|
5380
|
+
const c = stmt[i];
|
|
5381
|
+
if (c === "'" || c === '"') {
|
|
5382
|
+
for (i++; i < stmt.length && stmt[i] !== c; i++)
|
|
5383
|
+
if (stmt[i] === "\\")
|
|
5384
|
+
i++;
|
|
5385
|
+
} else if (c === "(")
|
|
5386
|
+
depth++;
|
|
5387
|
+
else if (c === ")" && depth-- === 0)
|
|
5388
|
+
return i + 1;
|
|
5389
|
+
}
|
|
5390
|
+
return stmt.length;
|
|
5391
|
+
}
|
|
5104
5392
|
function isBareContainerVisibility(stmt) {
|
|
5105
5393
|
return BARE_CONTAINER_ROLE.test(stmt) && !GET_BY_TEXT.test(stmt) && !HAS_TEXT_FILTER.test(stmt) && !TEXT_CONTENT_MATCHER.test(stmt);
|
|
5106
5394
|
}
|
|
@@ -5182,7 +5470,7 @@ function roleNames(s) {
|
|
|
5182
5470
|
function interactedControlNames(lines) {
|
|
5183
5471
|
const names = /* @__PURE__ */ new Set();
|
|
5184
5472
|
for (const raw of lines) {
|
|
5185
|
-
const ln =
|
|
5473
|
+
const ln = stripLineComment2(raw);
|
|
5186
5474
|
if (!INTERACT_VERB.test(ln))
|
|
5187
5475
|
continue;
|
|
5188
5476
|
for (const n of roleNames(ln))
|
|
@@ -5378,6 +5666,14 @@ function balancedArguments(code, from, limit = code.length) {
|
|
|
5378
5666
|
}
|
|
5379
5667
|
return null;
|
|
5380
5668
|
}
|
|
5669
|
+
function expectCallTail(stmt) {
|
|
5670
|
+
const at = stmt.search(EXPECT_CALL_RE);
|
|
5671
|
+
if (at < 0)
|
|
5672
|
+
return null;
|
|
5673
|
+
const from = stmt.indexOf("(", at) + 1;
|
|
5674
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
5675
|
+
return args === null ? null : stmt.slice(from + args.length).trimStart();
|
|
5676
|
+
}
|
|
5381
5677
|
function matcherArgumentsAreConstant(body, from) {
|
|
5382
5678
|
MATCHER_OPEN.lastIndex = from;
|
|
5383
5679
|
const opened = MATCHER_OPEN.exec(body);
|
|
@@ -5419,9 +5715,12 @@ function envValueKey(name) {
|
|
|
5419
5715
|
function enteredValues(stmts) {
|
|
5420
5716
|
const values = /* @__PURE__ */ new Map();
|
|
5421
5717
|
const navLines = [];
|
|
5718
|
+
const accountConsts = /* @__PURE__ */ new Set();
|
|
5422
5719
|
for (const { stmt, startLine } of stmts) {
|
|
5423
5720
|
if (PAGE_NAV.test(stmt))
|
|
5424
5721
|
navLines.push(startLine);
|
|
5722
|
+
for (const c of stmt.matchAll(ACCOUNT_CONST))
|
|
5723
|
+
accountConsts.add(c[1].replace(/\$/g, "\\$"));
|
|
5425
5724
|
let m;
|
|
5426
5725
|
ENTERED_VALUE.lastIndex = 0;
|
|
5427
5726
|
const add = (value) => {
|
|
@@ -5437,7 +5736,8 @@ function enteredValues(stmts) {
|
|
|
5437
5736
|
while (m = ENTERED_ENV.exec(stmt))
|
|
5438
5737
|
add(envValueKey(m[1] ?? m[2] ?? m[3] ?? m[4]));
|
|
5439
5738
|
}
|
|
5440
|
-
|
|
5739
|
+
const consts = accountConsts.size > 0 ? `|(?<![\\w$.])(?:${[...accountConsts].join("|")})(?![\\w$])` : "";
|
|
5740
|
+
return { values, navLines, account: new RegExp(`${ACCOUNT_ENV}${consts}`) };
|
|
5441
5741
|
}
|
|
5442
5742
|
function countBelow(lines, line) {
|
|
5443
5743
|
let lo = 0;
|
|
@@ -5574,6 +5874,9 @@ function comparesWithItself(subject, tail) {
|
|
|
5574
5874
|
return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
|
|
5575
5875
|
}
|
|
5576
5876
|
function asPlainAssertion(s) {
|
|
5877
|
+
return plainAssertion(s, false);
|
|
5878
|
+
}
|
|
5879
|
+
function plainAssertion(s, keepSelfCompare) {
|
|
5577
5880
|
const { stmt } = s;
|
|
5578
5881
|
if (COUNT_AT_LEAST_ZERO.test(stmt))
|
|
5579
5882
|
return [];
|
|
@@ -5582,13 +5885,13 @@ function asPlainAssertion(s) {
|
|
|
5582
5885
|
return [s];
|
|
5583
5886
|
const plain = subject.replace(/^await\s+/, "").trim();
|
|
5584
5887
|
const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
|
|
5585
|
-
const tail = stmt.slice(subjectAt + subject.length).trimStart();
|
|
5888
|
+
const tail = (stmt.startsWith("expect.poll", stmt.search(EXPECT_CALL_RE)) ? expectCallTail(stmt) : null) ?? stmt.slice(subjectAt + subject.length).trimStart();
|
|
5586
5889
|
const as = (rewritten) => [{ ...s, stmt: rewritten }];
|
|
5587
5890
|
if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
|
|
5588
5891
|
return [];
|
|
5589
5892
|
if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
|
|
5590
5893
|
return [];
|
|
5591
|
-
if (comparesWithItself(plain, tail))
|
|
5894
|
+
if (!keepSelfCompare && comparesWithItself(plain, tail))
|
|
5592
5895
|
return [];
|
|
5593
5896
|
const visible = /^(.+)\.\s*isVisible\s*\(\s*\)$/s.exec(plain);
|
|
5594
5897
|
if (visible && IS_VISIBLE_TRUE.test(tail))
|
|
@@ -5599,6 +5902,9 @@ function asPlainAssertion(s) {
|
|
|
5599
5902
|
}
|
|
5600
5903
|
return [s];
|
|
5601
5904
|
}
|
|
5905
|
+
function assertionStrengthHoistedReadsOn(value = typeof process !== "undefined" ? process.env?.ASSERTION_STRENGTH_HOISTED_READS : void 0) {
|
|
5906
|
+
return /^(1|true|on)$/i.test((value ?? "").trim());
|
|
5907
|
+
}
|
|
5602
5908
|
function creditsOutcomeAlways(stmt, entered, startLine) {
|
|
5603
5909
|
if (!OUTCOME_ALWAYS.some((re) => re.test(stmt)))
|
|
5604
5910
|
return false;
|
|
@@ -5631,6 +5937,22 @@ function successNoticeQuote(stmt) {
|
|
|
5631
5937
|
}
|
|
5632
5938
|
return null;
|
|
5633
5939
|
}
|
|
5940
|
+
function namedPagePath(arg) {
|
|
5941
|
+
const text = arg.trim();
|
|
5942
|
+
let path;
|
|
5943
|
+
const quoted = /^(['"`])([^'"`]*)\1$/.exec(text);
|
|
5944
|
+
const regex = quoted ? null : /^\/((?:\\.|[^/\\])+)\/[a-z]*$/.exec(text);
|
|
5945
|
+
if (quoted) {
|
|
5946
|
+
path = quoted[2].replace(/^\$\{[^}]*\}/, "").replace(/^\*\*/, "").replace(/^[a-z][a-z\d+.-]*:\/\/[^/]*/i, "").replace(/\/\*\*$/, "/");
|
|
5947
|
+
} else if (regex) {
|
|
5948
|
+
path = regex[1].replace(/^\^/, "").replace(/^\.\*/, "").replace(/\$$/, "").replace(/\\([/.-])/g, "$1");
|
|
5949
|
+
} else {
|
|
5950
|
+
return null;
|
|
5951
|
+
}
|
|
5952
|
+
if (!PLAIN_PAGE_PATH.test(path))
|
|
5953
|
+
return null;
|
|
5954
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
5955
|
+
}
|
|
5634
5956
|
function provesStoredControlValue(stmt, startLine, persistence) {
|
|
5635
5957
|
if (!persistence || startLine === void 0)
|
|
5636
5958
|
return false;
|
|
@@ -5657,7 +5979,64 @@ function reopenedAfterSave(startLine, persistence, reopens = persistence.reloadL
|
|
|
5657
5979
|
}
|
|
5658
5980
|
return lo < reopens.length && reopens[lo] < startLine;
|
|
5659
5981
|
}
|
|
5660
|
-
function
|
|
5982
|
+
function actsBetween(withLines, from, to) {
|
|
5983
|
+
let acts = actLinesOf.get(withLines);
|
|
5984
|
+
if (acts === void 0) {
|
|
5985
|
+
acts = withLines.filter((s) => ACTS.test(s.stmt)).map((s) => s.startLine).sort((a, b) => a - b);
|
|
5986
|
+
actLinesOf.set(withLines, acts);
|
|
5987
|
+
}
|
|
5988
|
+
let lo = 0;
|
|
5989
|
+
let hi = acts.length;
|
|
5990
|
+
while (lo < hi) {
|
|
5991
|
+
const mid = lo + hi >> 1;
|
|
5992
|
+
if (acts[mid] <= from)
|
|
5993
|
+
lo = mid + 1;
|
|
5994
|
+
else
|
|
5995
|
+
hi = mid;
|
|
5996
|
+
}
|
|
5997
|
+
return lo < acts.length && acts[lo] < to;
|
|
5998
|
+
}
|
|
5999
|
+
function signInProofWindow(stmts, withLines, lines, blockIds) {
|
|
6000
|
+
if (blockIds === null)
|
|
6001
|
+
return void 0;
|
|
6002
|
+
const testBodies2 = /* @__PURE__ */ new Set();
|
|
6003
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6004
|
+
const id = blockIds[i];
|
|
6005
|
+
if (id > 0 && (i === 0 || blockIds[i - 1] !== id) && TEST_BODY_OPEN.test(stripLineComment2(lines[i]).trim()))
|
|
6006
|
+
testBodies2.add(id);
|
|
6007
|
+
}
|
|
6008
|
+
const blockOf = (i) => blockIds[withLines[i].startLine - 1];
|
|
6009
|
+
const passwordAt = stmts.findIndex((stmt, i) => testBodies2.has(blockOf(i)) && ENV_PASSWORD_ENTRY.test(stmt));
|
|
6010
|
+
if (passwordAt < 0)
|
|
6011
|
+
return void 0;
|
|
6012
|
+
const body = blockOf(passwordAt);
|
|
6013
|
+
let clickAt = passwordAt + 1;
|
|
6014
|
+
while (clickAt < stmts.length && FORM_INPUT.test(stmts[clickAt]) && !ANY_CLICK.test(stmts[clickAt]))
|
|
6015
|
+
clickAt++;
|
|
6016
|
+
if (clickAt >= stmts.length || blockOf(clickAt) !== body || !ANY_CLICK.test(stmts[clickAt]) || NAV_LOCATOR.test(stmts[clickAt]))
|
|
6017
|
+
return void 0;
|
|
6018
|
+
let end = clickAt + 1;
|
|
6019
|
+
for (; end < stmts.length && blockOf(end) === body; end++) {
|
|
6020
|
+
if (CLOSERS_ONLY.test(stmts[end]))
|
|
6021
|
+
continue;
|
|
6022
|
+
if (!ASSERT_OR_WAIT.test(stmts[end]) || ACTS.test(stmts[end]))
|
|
6023
|
+
return void 0;
|
|
6024
|
+
}
|
|
6025
|
+
return { after: withLines[clickAt].startLine, until: end < stmts.length ? withLines[end].startLine : Number.POSITIVE_INFINITY };
|
|
6026
|
+
}
|
|
6027
|
+
function isAccountControlCheck(stmt) {
|
|
6028
|
+
if (!VISIBILITY_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt) || OPTION_ABSENCE.test(stmt))
|
|
6029
|
+
return false;
|
|
6030
|
+
const role = ACCOUNT_CONTROL_ROLE.exec(stmt);
|
|
6031
|
+
if (!role)
|
|
6032
|
+
return false;
|
|
6033
|
+
const rest = stmt.slice(role.index + role[0].length, role.index + role[0].length + 300);
|
|
6034
|
+
const close = rest.indexOf("}");
|
|
6035
|
+
const options = close < 0 ? rest : rest.slice(0, close);
|
|
6036
|
+
const name = options.match(/(?:^|[\s,])name\s*:\s*/);
|
|
6037
|
+
return name !== null && ACCOUNT_EMAIL_ENV.test(options.slice(name.index + name[0].length));
|
|
6038
|
+
}
|
|
6039
|
+
function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine, persistence, signedIn) {
|
|
5661
6040
|
if (mutated && hasAttributeTransition(stmts))
|
|
5662
6041
|
return { kind: "durable" };
|
|
5663
6042
|
const notices = [];
|
|
@@ -5667,6 +6046,13 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
5667
6046
|
};
|
|
5668
6047
|
let presenceText;
|
|
5669
6048
|
const presence = () => presenceText ??= stmts.filter((o) => !ABSENCE_MATCHER.test(o.stmt) && !NEGATED_ASSERT.test(o.stmt)).map((o) => o.stmt).join("\n");
|
|
6049
|
+
let shownAccounts;
|
|
6050
|
+
const shown = () => {
|
|
6051
|
+
if (shownAccounts)
|
|
6052
|
+
return shownAccounts;
|
|
6053
|
+
const ref = new RegExp(entered.account.source, "g");
|
|
6054
|
+
return shownAccounts = new Set(stmts.filter((o) => !claimsAbsence(o.stmt)).flatMap((o) => Array.from(o.stmt.matchAll(ref), (m) => m[0])));
|
|
6055
|
+
};
|
|
5670
6056
|
for (const { stmt, startLine } of stmts) {
|
|
5671
6057
|
if (firstMutLine !== void 0 && startLine !== void 0 && startLine < firstMutLine)
|
|
5672
6058
|
continue;
|
|
@@ -5674,6 +6060,11 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
5674
6060
|
continue;
|
|
5675
6061
|
if (COUNT_ONE.test(stmt) && quotedAssertedStrings(stmt).some((t) => clicked.has(t.toLowerCase())))
|
|
5676
6062
|
continue;
|
|
6063
|
+
if (isVacuousAccountAbsence(stmt, shown, entered.account))
|
|
6064
|
+
continue;
|
|
6065
|
+
if (signedIn && startLine !== void 0 && startLine > signedIn.after && startLine < signedIn.until && isAccountControlCheck(stmt)) {
|
|
6066
|
+
return { kind: "durable" };
|
|
6067
|
+
}
|
|
5677
6068
|
if (creditsOutcomeAlways(stmt, entered, startLine))
|
|
5678
6069
|
return { kind: "durable" };
|
|
5679
6070
|
if (mutated && !NEGATED_ASSERT.test(stmt) && MESSAGE_SURFACE.test(stmt) && OUTCOME_TEXT.test(assertedText(stmt))) {
|
|
@@ -5755,6 +6146,53 @@ function noticeOnlyExemption(clicked, noticeText, interactionStmts) {
|
|
|
5755
6146
|
function detectOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine) {
|
|
5756
6147
|
return classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine).kind !== "none";
|
|
5757
6148
|
}
|
|
6149
|
+
function clickLabel(stmt) {
|
|
6150
|
+
let label = null;
|
|
6151
|
+
for (const m of stmt.matchAll(CONTROL_LABEL))
|
|
6152
|
+
label = m[2] ?? m[3] ?? null;
|
|
6153
|
+
return label;
|
|
6154
|
+
}
|
|
6155
|
+
function teardownLines(lines) {
|
|
6156
|
+
const out = new Array(lines.length).fill(false);
|
|
6157
|
+
let open = false;
|
|
6158
|
+
let depth = 0;
|
|
6159
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6160
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
6161
|
+
let from = 0;
|
|
6162
|
+
if (!open) {
|
|
6163
|
+
const m = TEARDOWN_OPEN.exec(ln);
|
|
6164
|
+
if (!m)
|
|
6165
|
+
continue;
|
|
6166
|
+
open = true;
|
|
6167
|
+
depth = 0;
|
|
6168
|
+
from = m.index;
|
|
6169
|
+
}
|
|
6170
|
+
out[i] = true;
|
|
6171
|
+
let closed = false;
|
|
6172
|
+
let quote = null;
|
|
6173
|
+
for (let k = from; k < ln.length; k++) {
|
|
6174
|
+
const ch = ln[k];
|
|
6175
|
+
if (quote !== null) {
|
|
6176
|
+
if (ch === "\\")
|
|
6177
|
+
k++;
|
|
6178
|
+
else if (ch === quote)
|
|
6179
|
+
quote = null;
|
|
6180
|
+
continue;
|
|
6181
|
+
}
|
|
6182
|
+
if (ch === "'" || ch === '"' || ch === "`")
|
|
6183
|
+
quote = ch;
|
|
6184
|
+
else if (ch === "{")
|
|
6185
|
+
depth++;
|
|
6186
|
+
else if (ch === "}") {
|
|
6187
|
+
depth--;
|
|
6188
|
+
closed = true;
|
|
6189
|
+
}
|
|
6190
|
+
}
|
|
6191
|
+
if (depth <= 0 && closed)
|
|
6192
|
+
open = false;
|
|
6193
|
+
}
|
|
6194
|
+
return out;
|
|
6195
|
+
}
|
|
5758
6196
|
function validateAssertionStrength(code, opts = {}) {
|
|
5759
6197
|
const body = stripLoginScaffolding(code);
|
|
5760
6198
|
const lines = body.split("\n");
|
|
@@ -5798,7 +6236,13 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5798
6236
|
const interactionStmts = inlineLocatorBindings(interactionStmtsRaw);
|
|
5799
6237
|
const blockIds = testBlockIds(lines);
|
|
5800
6238
|
const blockOfLine = (line) => blockIds?.[line - 1] ?? 0;
|
|
5801
|
-
const
|
|
6239
|
+
const hoistedReads = assertionStrengthHoistedReadsOn();
|
|
6240
|
+
const boundAt = hoistedReads ? /* @__PURE__ */ new Map() : void 0;
|
|
6241
|
+
const resolved = resolveSubjectBindings(stmts, scopedLocatorBindings(interactionStmtsWithLines, blockOfLine), blockOfLine, boundAt);
|
|
6242
|
+
const checks = boundAt === void 0 ? resolved : resolved.flatMap((s) => {
|
|
6243
|
+
const from = boundAt.get(s);
|
|
6244
|
+
return plainAssertion(s, from !== void 0 && actsBetween(interactionStmtsWithLines, from, s.startLine));
|
|
6245
|
+
});
|
|
5802
6246
|
const insideTest = linesInsideTestBlocks(lines);
|
|
5803
6247
|
const inTestOrder = (i) => insideTest === null || insideTest[interactionStmtsWithLines[i].startLine - 1] === true;
|
|
5804
6248
|
let mutated = opts.interactionPerformed === true;
|
|
@@ -5808,9 +6252,34 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5808
6252
|
let navClicks = 0;
|
|
5809
6253
|
const persistence = { mutLines: [], reloadLines: [], reloadCalls: [] };
|
|
5810
6254
|
const openedPages = /* @__PURE__ */ new Set();
|
|
6255
|
+
let checkedPage = null;
|
|
6256
|
+
const savedOnCheckedPage = /* @__PURE__ */ new Set();
|
|
6257
|
+
const saveAt = (i, at) => {
|
|
6258
|
+
lastMutIdx = i;
|
|
6259
|
+
if (!inTestOrder(i))
|
|
6260
|
+
return;
|
|
6261
|
+
persistence.mutLines.push(at);
|
|
6262
|
+
if (firstMutIdx < 0)
|
|
6263
|
+
firstMutIdx = i;
|
|
6264
|
+
if (checkedPage !== null)
|
|
6265
|
+
savedOnCheckedPage.add(checkedPage);
|
|
6266
|
+
};
|
|
6267
|
+
const lastActionProof = opts.lastActionProof ?? "off";
|
|
6268
|
+
const teardown = lastActionProof === "off" ? null : teardownLines(lines);
|
|
6269
|
+
const acts = { last: null, prev: null, count: 0 };
|
|
6270
|
+
const noteAct = (i, at, kind) => {
|
|
6271
|
+
if (teardown === null || teardown[at - 1] || !inTestOrder(i))
|
|
6272
|
+
return;
|
|
6273
|
+
if (kind !== "enter")
|
|
6274
|
+
acts.count++;
|
|
6275
|
+
acts.prev = acts.last;
|
|
6276
|
+
acts.last = { i, kind };
|
|
6277
|
+
};
|
|
5811
6278
|
for (let i = 0; i < interactionStmts.length; i++) {
|
|
5812
6279
|
const ln = interactionStmts[i];
|
|
5813
6280
|
const at = interactionStmtsWithLines[i].startLine;
|
|
6281
|
+
if (teardown !== null && acts.last?.kind === "fill" && ENTER_PRESS.test(ln))
|
|
6282
|
+
noteAct(i, at, "enter");
|
|
5814
6283
|
if (RELOAD.test(ln)) {
|
|
5815
6284
|
persistence.reloadLines.push(at);
|
|
5816
6285
|
persistence.reloadCalls.push(at);
|
|
@@ -5818,32 +6287,31 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5818
6287
|
const opened = ln.match(/\.goto\s*\(\s*([^,)]+)/);
|
|
5819
6288
|
if (opened) {
|
|
5820
6289
|
const page = opened[1].trim();
|
|
5821
|
-
|
|
6290
|
+
const path = namedPagePath(page);
|
|
6291
|
+
if (openedPages.has(page) || path !== null && savedOnCheckedPage.has(path))
|
|
5822
6292
|
persistence.reloadLines.push(at);
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
}
|
|
6293
|
+
openedPages.add(page);
|
|
6294
|
+
checkedPage = null;
|
|
6295
|
+
}
|
|
6296
|
+
if (/\bpage\s*\.\s*go(?:Back|Forward)\s*\(/.test(ln))
|
|
6297
|
+
checkedPage = null;
|
|
6298
|
+
const checked = URL_CHECK_ARG.exec(ln);
|
|
6299
|
+
if (checked)
|
|
6300
|
+
checkedPage = namedPagePath(checked[1] ?? checked[2]);
|
|
5826
6301
|
if (FORM_INPUT.test(ln)) {
|
|
5827
6302
|
mutated = true;
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
persistence.mutLines.push(at);
|
|
5831
|
-
if (firstMutIdx < 0)
|
|
5832
|
-
firstMutIdx = i;
|
|
5833
|
-
}
|
|
6303
|
+
saveAt(i, at);
|
|
6304
|
+
noteAct(i, at, "fill");
|
|
5834
6305
|
continue;
|
|
5835
6306
|
}
|
|
5836
6307
|
if (ANY_CLICK.test(ln)) {
|
|
5837
6308
|
if (NAV_LOCATOR.test(ln)) {
|
|
5838
6309
|
navClicks++;
|
|
6310
|
+
checkedPage = null;
|
|
5839
6311
|
} else {
|
|
5840
6312
|
mutated = true;
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
persistence.mutLines.push(at);
|
|
5844
|
-
if (firstMutIdx < 0)
|
|
5845
|
-
firstMutIdx = i;
|
|
5846
|
-
}
|
|
6313
|
+
saveAt(i, at);
|
|
6314
|
+
noteAct(i, at, "click");
|
|
5847
6315
|
}
|
|
5848
6316
|
}
|
|
5849
6317
|
}
|
|
@@ -5876,9 +6344,28 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5876
6344
|
};
|
|
5877
6345
|
}
|
|
5878
6346
|
const orderedPersistence = firstMutLine !== void 0 ? persistence : void 0;
|
|
5879
|
-
const
|
|
6347
|
+
const signedIn = signInProofWindow(interactionStmts, interactionStmtsWithLines, lines, blockIds);
|
|
6348
|
+
const proof = classifyOutcomeProof(checks, mutated, reloaded, clickedControlNames(interactionStmts), entered, firstMutLine, orderedPersistence, signedIn);
|
|
5880
6349
|
if (proof.kind === "durable") {
|
|
5881
6350
|
const signals2 = base({ interacted, mutated, navOnly, hasOutcomeProof: true, terminal });
|
|
6351
|
+
const { last, prev } = acts;
|
|
6352
|
+
if (teardown !== null && last !== null && acts.count >= 2 && last.kind !== "fill" && (last.kind === "enter" || isCommitClick(interactionStmts[last.i]) && !(prev?.kind === "click" && isDestructiveClick(interactionStmts[prev.i])))) {
|
|
6353
|
+
const lastLine = interactionStmtsWithLines[last.i].startLine;
|
|
6354
|
+
const clicked = clickedControlNames(interactionStmts);
|
|
6355
|
+
const after = classifyOutcomeProof(checks, mutated, reloaded, clicked, entered, lastLine, orderedPersistence, signedIn);
|
|
6356
|
+
const unproven = after.kind === "none" || after.kind === "notice" && noticeOnlyExemption(clicked, after.noticeText, interactionStmts) === null;
|
|
6357
|
+
if (unproven && lastActionProof === "on") {
|
|
6358
|
+
const line = (keptScaffoldingLines(code.split("\n"))[lastLine - 1] ?? lastLine - 1) + 1;
|
|
6359
|
+
return {
|
|
6360
|
+
ok: false,
|
|
6361
|
+
severity: "block",
|
|
6362
|
+
reason: `the last save (line ${line}) has no outcome check after it (the earlier check proves only the earlier action)`,
|
|
6363
|
+
signals: { ...signals2, lastActionUnproven: true }
|
|
6364
|
+
};
|
|
6365
|
+
}
|
|
6366
|
+
if (unproven)
|
|
6367
|
+
signals2.lastActionUnproven = true;
|
|
6368
|
+
}
|
|
5882
6369
|
return { ok: true, severity: "none", reason: "proves an outcome (count / diff / value / revealed content)", signals: signals2 };
|
|
5883
6370
|
}
|
|
5884
6371
|
if (mutated && proof.kind === "notice") {
|
|
@@ -5927,7 +6414,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5927
6414
|
signals
|
|
5928
6415
|
};
|
|
5929
6416
|
}
|
|
5930
|
-
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx &&
|
|
6417
|
+
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx && isUrlProof(s));
|
|
5931
6418
|
if (urlProofAfter) {
|
|
5932
6419
|
return {
|
|
5933
6420
|
ok: false,
|
|
@@ -5964,7 +6451,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
5964
6451
|
signals
|
|
5965
6452
|
};
|
|
5966
6453
|
}
|
|
5967
|
-
var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, NEGATED_ASSERT_NOT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, VALUE_ABSENCE, OPTION_ABSENCE, NOT_BEFORE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, NEGATED_TEXT, ASYNC_DESTRUCTURE_OPEN, REQUEST_WORD, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, ENV_READ, ENTERED_ENV, HAVE_VALUE_ENV, IN_FLIGHT_TEXT, LOCATOR_VALUE_READ, LOCATOR_EXPR, ALWAYS_TRUE_ON_OBJECT, COUNT_AT_LEAST_ZERO, DEFINED_VALUE_READ, ALWAYS_DEFINED, SELF_COMPARE_MATCHER, IS_VISIBLE_TRUE, PAGE_VALUE_MATCHER, COUNT_ONE, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD;
|
|
6454
|
+
var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, POLL_OPEN, POLL_PAGE_URL, POLL_PAGE_URL_ONLY, POLL_CALLS_MAX, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, NEGATED_ASSERT_NOT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, VALUE_ABSENCE, OPTION_ABSENCE, NOT_BEFORE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, SCOPING_STEP, NEGATED_TEXT, ASYNC_DESTRUCTURE_OPEN, REQUEST_WORD, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, ENV_READ, ENTERED_ENV, HAVE_VALUE_ENV, ACCOUNT_KEYS, ACCOUNT_ENV, ACCOUNT_CONST, IN_FLIGHT_TEXT, LOCATOR_VALUE_READ, LOCATOR_EXPR, ALWAYS_TRUE_ON_OBJECT, COUNT_AT_LEAST_ZERO, DEFINED_VALUE_READ, ALWAYS_DEFINED, SELF_COMPARE_MATCHER, IS_VISIBLE_TRUE, PAGE_VALUE_MATCHER, COUNT_ONE, URL_CHECK_ARG, PLAIN_PAGE_PATH, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, ACCOUNT_EMAIL_ENV, ENV_PASSWORD_ENTRY, ACCOUNT_CONTROL_ROLE, ASSERT_OR_WAIT, ACTS, actLinesOf, CLOSERS_ONLY, TEST_BODY_OPEN, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD, COMMIT_CONTROL, NOT_COMMIT_CONTROL, DESTRUCTIVE_CONTROL, ENTER_PRESS, CONTROL_LABEL, isCommitClick, isDestructiveClick, TEARDOWN_OPEN;
|
|
5968
6455
|
var init_assertion_strength = __esm({
|
|
5969
6456
|
"../shared/dist/assertion-strength.js"() {
|
|
5970
6457
|
"use strict";
|
|
@@ -5973,6 +6460,7 @@ var init_assertion_strength = __esm({
|
|
|
5973
6460
|
init_assertion_proof();
|
|
5974
6461
|
init_auth_handoff_coverage();
|
|
5975
6462
|
init_expect_call();
|
|
6463
|
+
init_auth_plan();
|
|
5976
6464
|
ERROR_BANNER = /(client-side exception|application error|something (?:went wrong|broke)|unhandled (?:exception|error|rejection)|runtime error|error boundary|an unexpected error|internal server error|\b5\d\d\s+(?:internal\s+)?server error|stack trace|chunkloaderror|hydration failed|maximum update depth exceeded)/i;
|
|
5977
6465
|
OUTCOME_ALWAYS = [
|
|
5978
6466
|
/\.toHaveCount\s*\(/,
|
|
@@ -5989,7 +6477,7 @@ var init_assertion_strength = __esm({
|
|
|
5989
6477
|
// form field value
|
|
5990
6478
|
/\.toMatch\s*\(/,
|
|
5991
6479
|
// string/regex content match (e.g. textContent() vs /[2-9] selected/)
|
|
5992
|
-
|
|
6480
|
+
/\.(?<!\.not\s*\.)\s*toBeDisabled\s*\(/,
|
|
5993
6481
|
// a control became DISABLED — a gating/validation outcome (not.toBeDisabled is the toBeEnabled twin)
|
|
5994
6482
|
/\.not\.toBeVisible\s*\(/,
|
|
5995
6483
|
/\.toBeHidden\s*\(/
|
|
@@ -5998,12 +6486,16 @@ var init_assertion_strength = __esm({
|
|
|
5998
6486
|
FORM_INPUT = /\.(fill|selectOption|setInputFiles|check|uncheck|setChecked|pressSequentially)\s*\(|keyboard\.type\s*\(/;
|
|
5999
6487
|
ANY_CLICK = /\.click\s*\(/;
|
|
6000
6488
|
NAV_LOCATOR = /getByRole\s*\(\s*['"`](?:link|menuitem)['"`]/i;
|
|
6001
|
-
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(|\bexpect\s*\(\s*(?:await\s+)?page\s*\.\s*url\s*\(\s*\)\s*\)
|
|
6489
|
+
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(|\bexpect\s*\(\s*(?:await\s+)?page\s*\.\s*url\s*\(\s*\)\s*\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
6490
|
+
POLL_OPEN = /\bexpect\s*\.\s*poll\s*\(/g;
|
|
6491
|
+
POLL_PAGE_URL = /^page\s*\.\s*url\s*\(\s*\)/;
|
|
6492
|
+
POLL_PAGE_URL_ONLY = /^page\s*\.\s*url\s*\(\s*\)$/;
|
|
6493
|
+
POLL_CALLS_MAX = 8;
|
|
6002
6494
|
RELOAD = /\.reload\s*\(/;
|
|
6003
6495
|
EXPECT_STMT = /\bexpect\s*[.(]/;
|
|
6004
6496
|
BLOCK_SCAFFOLD2 = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
6005
6497
|
TEST_BLOCK_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow|serial|describe\.serial))?\s*\(|^(?:test\.)?(?:beforeEach|beforeAll)\s*\(/;
|
|
6006
|
-
LOCATOR_BINDING = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s
|
|
6498
|
+
LOCATOR_BINDING = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=(?:\s*(?!\s)|\s*(?=\s(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|getByAltText|getByTitle|locator)\s*\())(.+?(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|getByAltText|getByTitle|locator)\s*\(.+)$/;
|
|
6007
6499
|
EXPECT_OPEN = /\bexpect(?:\.soft)?\s*\(/;
|
|
6008
6500
|
STATE_MATCHER = /\.(toBeChecked|toBeVisible|toHaveValue|toBeDisabled|toBeEnabled)\s*\(/;
|
|
6009
6501
|
CHROME_LOCATOR = /getByRole\s*\(\s*['"`](?:heading|navigation|banner|main|contentinfo|complementary|region|search|tablist|tab|button|link|menuitem|textbox|searchbox|combobox|spinbutton)['"`]/i;
|
|
@@ -6023,7 +6515,7 @@ var init_assertion_strength = __esm({
|
|
|
6023
6515
|
EMPTY_STATE_TEXT = /\bno\b[\s\S]{0,24}?\b(yet|found|results?|items?|favou?rites?|entries|records?|matches|posts?|comments?)\b|nothing (?:here|yet|to show|found)|\bempty\b|\(\s*0\s*\)|\b0\s+(?:favou?rites?|results?|items?|entries|records?|matches|posts?|comments?)\b/i;
|
|
6024
6516
|
AUTH_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_AUTH/;
|
|
6025
6517
|
AUTH_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_AUTH/;
|
|
6026
|
-
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s
|
|
6518
|
+
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s*(?:;\s*)?$/;
|
|
6027
6519
|
INBOX_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_INBOX/;
|
|
6028
6520
|
INBOX_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_INBOX/;
|
|
6029
6521
|
NEGATED_ASSERT = /\.not\s*\.\s*to[A-Z]\w*|\.toBeHidden\s*\(/;
|
|
@@ -6033,7 +6525,7 @@ var init_assertion_strength = __esm({
|
|
|
6033
6525
|
TITLE_LINE = /^\s*(?:test|describe)(?:\.\w+)?\s*\(/;
|
|
6034
6526
|
FAILURE_STATUS_ASSERT = [
|
|
6035
6527
|
/\.status\s*\(\s*\)[^;]{0,200}\.(?:toBeGreaterThanOrEqual|toBeGreaterThan)\s*\(\s*(?:399|[45]\d\d)\b/,
|
|
6036
|
-
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\))
|
|
6528
|
+
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\)\s*)?>=?\s*(?:399|[45]\d\d)\b[^;]{0,200}\)\s*\.\s*(?:toBe\s*\(\s*true|toBeTruthy)/,
|
|
6037
6529
|
/\bexpect\s*\([^;]{0,200}\.ok\s*\(\s*\)\s*\)\s*\.\s*(?:toBe\s*\(\s*false\s*\)|toBeFalsy\s*\()/
|
|
6038
6530
|
];
|
|
6039
6531
|
FAILED_LIST_ASSERT = /\bexpect\s*\(\s*[^;]{0,200}(?:fail|abort|error)\w{0,40}(?:\.length)?\s*\)\s*\.\s*(?:toBeGreaterThan\s*\(\s*0|toHaveLength\s*\(\s*[1-9]|not\s*\.\s*toHaveLength\s*\(\s*0|not\s*\.\s*toEqual\s*\(\s*\[\s*\])/i;
|
|
@@ -6048,6 +6540,7 @@ var init_assertion_strength = __esm({
|
|
|
6048
6540
|
NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
|
|
6049
6541
|
ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
|
|
6050
6542
|
TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
|
|
6543
|
+
SCOPING_STEP = /(?:\s*\.\s*(?:first|last|nth)\s*\([^()]*\))*\s*\.\s*(?:getBy[A-Z]\w*|locator|filter)\s*\(/y;
|
|
6051
6544
|
NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
|
|
6052
6545
|
ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
|
|
6053
6546
|
REQUEST_WORD = /\brequest\b/;
|
|
@@ -6074,6 +6567,9 @@ var init_assertion_strength = __esm({
|
|
|
6074
6567
|
ENV_READ = String.raw`process\.env(?:(?:\?\.|\.)([A-Za-z_]\w*)|(?:\?\.)?\[\s*['"]([A-Za-z_]\w*)['"]\s*\])`;
|
|
6075
6568
|
ENTERED_ENV = new RegExp(String.raw`\.(?:fill|pressSequentially)\s*\(\s*${ENV_READ}|keyboard\.type\s*\(\s*${ENV_READ}`, "g");
|
|
6076
6569
|
HAVE_VALUE_ENV = new RegExp(String.raw`\.toHaveValue\s*\(\s*${ENV_READ}`);
|
|
6570
|
+
ACCOUNT_KEYS = TEST_USER_ENV_KEYS.join("|");
|
|
6571
|
+
ACCOUNT_ENV = `process\\.env(?:\\??\\.(?:${ACCOUNT_KEYS})\\b|(?:\\?\\.)?\\[\\s*['"\`](?:${ACCOUNT_KEYS})['"\`]\\s*\\])`;
|
|
6572
|
+
ACCOUNT_CONST = new RegExp(`\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*(?::\\s*string\\s*)?=\\s*${ACCOUNT_ENV}`, "g");
|
|
6077
6573
|
IN_FLIGHT_TEXT = /^(?:(?:sending|saving|loading|searching|checking|processing|submitting|preparing|updating|please wait|working|one moment)\b[^.]{0,40}\.{2,3}|\.{3}|…)$/i;
|
|
6078
6574
|
LOCATOR_VALUE_READ = /\.(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts|evaluate|evaluateAll|boundingBox|all)\s*\(/;
|
|
6079
6575
|
LOCATOR_EXPR = /^(?:this\.)?page\s*\.\s*(?:getBy\w+|locator)\s*\(/;
|
|
@@ -6085,20 +6581,47 @@ var init_assertion_strength = __esm({
|
|
|
6085
6581
|
IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
|
|
6086
6582
|
PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
6087
6583
|
COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
|
|
6584
|
+
URL_CHECK_ARG = /\bpage\s*\.\s*waitForURL\s*\(\s*([^,)]+)|\bexpect(?:\s*\.\s*soft)?\s*\(\s*page\s*\)\s*\.\s*toHaveURL\s*\(\s*([^,)]+)/;
|
|
6585
|
+
PLAIN_PAGE_PATH = /^\/[\w\-./~%]*(?:[?#][^\s]*)?$/;
|
|
6088
6586
|
FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
|
|
6089
6587
|
CONTROL_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(|\.toHaveAttribute\s*\(\s*['"`]aria-checked['"`]/;
|
|
6588
|
+
ACCOUNT_EMAIL_ENV = /^process\.env(?:(?:\?\.|\.)TEST_USER_EMAIL\b|(?:\?\.)?\[\s*['"]TEST_USER_EMAIL['"]\s*\])/;
|
|
6589
|
+
ENV_PASSWORD_ENTRY = /\.(?:fill|pressSequentially)\s*\(\s*process\.env(?:(?:\?\.|\.)TEST_USER_PASSWORD\b|(?:\?\.)?\[\s*['"]TEST_USER_PASSWORD['"]\s*\])/;
|
|
6590
|
+
ACCOUNT_CONTROL_ROLE = /getByRole\s*\(\s*['"`](?:button|link|menuitem)['"`]\s*,\s*\{/;
|
|
6591
|
+
ASSERT_OR_WAIT = /^(?:await\s+)?(?:expect(?:\.soft|\.poll)?\s*\(|[\w$]+(?:\.[\w$]+)*\.waitFor[A-Za-z]*\s*\()/;
|
|
6592
|
+
ACTS = /\.(?:click|dblclick|tap|press|pressSequentially|fill|clear|type|check|uncheck|setChecked|selectOption|setInputFiles|dispatchEvent|hover|focus|dragTo|goto|reload|goBack|goForward|evaluate|evaluateHandle)\s*\(|\b(?:keyboard|mouse|touchscreen)\s*\.|\.toPass\s*\(/;
|
|
6593
|
+
actLinesOf = /* @__PURE__ */ new WeakMap();
|
|
6594
|
+
CLOSERS_ONLY = /^[})\];,\s]+$/;
|
|
6595
|
+
TEST_BODY_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/;
|
|
6090
6596
|
COPY_CONTROL = /\bcopy\b/i;
|
|
6091
6597
|
COPIED_NOTICE = /\bcopied\b/i;
|
|
6092
6598
|
SEND_CONTROL = /\b(send|submit|subscribe|sign up for|contact|feedback|join (the )?waitlist)\b/i;
|
|
6093
6599
|
SEND_NOTICE = /\b(thank|thanks|sent|subscribed|received|in touch)\b/i;
|
|
6094
6600
|
MARK_READ_CONTROL = /\bmark(?:ed)? as read\b|\bmark all(?: as)? read\b/i;
|
|
6095
6601
|
APP_DATA_FIELD = /\b(title|name of|amount|price|quantity|sku|status|due|assignee|project|ticket|invoice|order)\b/i;
|
|
6602
|
+
COMMIT_CONTROL = /\b(?:save|submit|update|apply|add|create|post|send|publish)\b|\bconfirm\s+changes\b/i;
|
|
6603
|
+
NOT_COMMIT_CONTROL = /\b(?:delete|remove|cancel|close|dismiss|discard|back|sign\s*out|log\s*out|logout|done|ok|got\s+it|export|download)\b/i;
|
|
6604
|
+
DESTRUCTIVE_CONTROL = /\b(?:delete|remove|discard)\b/i;
|
|
6605
|
+
ENTER_PRESS = /\.press\s*\(\s*['"`]Enter['"`]/;
|
|
6606
|
+
CONTROL_LABEL = /(?:name\s*:\s*|getBy(?:Text|Label|Title|TestId)\s*\(\s*|has-text\(\s*)(?:(['"`])((?:(?!\1).)*)\1|\/((?:\\.|[^/\\])+)\/)/g;
|
|
6607
|
+
isCommitClick = (stmt) => {
|
|
6608
|
+
const label = clickLabel(stmt);
|
|
6609
|
+
return label !== null && COMMIT_CONTROL.test(label) && !NOT_COMMIT_CONTROL.test(label) && !EXCLUDE_AFFORDANCE.test(label);
|
|
6610
|
+
};
|
|
6611
|
+
isDestructiveClick = (stmt) => {
|
|
6612
|
+
const label = clickLabel(stmt);
|
|
6613
|
+
return label !== null && DESTRUCTIVE_CONTROL.test(label);
|
|
6614
|
+
};
|
|
6615
|
+
TEARDOWN_OPEN = /\bfinally\s*\{|^(?:test\.)?(?:after|before)(?:Each|All)\s*\(/;
|
|
6096
6616
|
}
|
|
6097
6617
|
});
|
|
6098
6618
|
|
|
6099
6619
|
// ../shared/dist/run-classification.js
|
|
6100
|
-
function
|
|
6101
|
-
|
|
6620
|
+
function isCancelledReason(error) {
|
|
6621
|
+
if (typeof error !== "string")
|
|
6622
|
+
return false;
|
|
6623
|
+
const text = error.trim();
|
|
6624
|
+
return CANCELLED_REASON_PREFIXES.some((prefix) => text.startsWith(prefix));
|
|
6102
6625
|
}
|
|
6103
6626
|
function isHeldHealRun(run) {
|
|
6104
6627
|
return run?.status === "PASSED" && typeof run.error === "string" && run.error.startsWith(HEAL_PATCH_HELD_RUN_ERROR_PREFIX);
|
|
@@ -6131,7 +6654,7 @@ function pickLatestHealthRun(runs) {
|
|
|
6131
6654
|
for (const run of runs) {
|
|
6132
6655
|
if (run.mode === "auth-setup")
|
|
6133
6656
|
continue;
|
|
6134
|
-
if (run.status === "ERROR" &&
|
|
6657
|
+
if (run.status === "ERROR" && isCancelledReason(run.error))
|
|
6135
6658
|
continue;
|
|
6136
6659
|
if (isHeldHealRun(run))
|
|
6137
6660
|
continue;
|
|
@@ -6149,6 +6672,15 @@ function pickDisplayRun(runs) {
|
|
|
6149
6672
|
return latest;
|
|
6150
6673
|
return pickLatestHealthRun(runs) ?? latest;
|
|
6151
6674
|
}
|
|
6675
|
+
function featureRowRunStatus(runs) {
|
|
6676
|
+
const latest = runs.find((run) => run.mode !== "auth-setup");
|
|
6677
|
+
if (!latest)
|
|
6678
|
+
return null;
|
|
6679
|
+
const decisive = pickLatestHealthRun(runs.filter((run) => !isEnvironmentalError(run)));
|
|
6680
|
+
if (decisive)
|
|
6681
|
+
return decisive.status;
|
|
6682
|
+
return latest.status === "PENDING" || latest.status === "RUNNING" ? latest.status : null;
|
|
6683
|
+
}
|
|
6152
6684
|
function isEnvironmentalError(run) {
|
|
6153
6685
|
if (!run)
|
|
6154
6686
|
return false;
|
|
@@ -6180,7 +6712,7 @@ function classifyErrorMessage(error) {
|
|
|
6180
6712
|
return "config_issue";
|
|
6181
6713
|
if (EMAIL_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix)))
|
|
6182
6714
|
return "email_not_received";
|
|
6183
|
-
if (
|
|
6715
|
+
if (isCancelledReason(error))
|
|
6184
6716
|
return "cancelled";
|
|
6185
6717
|
if (isRetriedRunInterruption(error))
|
|
6186
6718
|
return "interrupted";
|
|
@@ -6215,7 +6747,7 @@ function heldHealRunWhere() {
|
|
|
6215
6747
|
function excludeCancelledRunsWhere() {
|
|
6216
6748
|
return {
|
|
6217
6749
|
NOT: [
|
|
6218
|
-
{ status: "ERROR", error: { not: null, startsWith:
|
|
6750
|
+
{ status: "ERROR", OR: CANCELLED_REASON_PREFIXES.map((prefix) => ({ error: { not: null, startsWith: prefix } })) },
|
|
6219
6751
|
heldHealRunWhere()
|
|
6220
6752
|
]
|
|
6221
6753
|
};
|
|
@@ -6293,11 +6825,25 @@ function reportedBugWhere() {
|
|
|
6293
6825
|
function bugReviewStatus(status) {
|
|
6294
6826
|
return status === "QUARANTINED" ? "confirmed" : "needs-review";
|
|
6295
6827
|
}
|
|
6296
|
-
var USER_CANCELLED_RUN_ERROR, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, TEST_DID_NOT_RUN_ERROR, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
|
|
6828
|
+
var USER_CANCELLED_RUN_ERROR, PLATFORM_SUPPORT_CANCELLED_RUN_ERROR, PLATFORM_ADMIN_CANCELLED_RUN_ERROR, ADMIN_FORCE_CANCELLED_RUN_ERROR, CHAIN_CANCELLED_RUN_ERROR, RETRY_HELD_RUN_ERROR, CANCELLED_REASON_PREFIXES, isUserCancelledError, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, TEST_DID_NOT_RUN_ERROR, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, FEATURE_ROW_RUN_WINDOW, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
|
|
6297
6829
|
var init_run_classification = __esm({
|
|
6298
6830
|
"../shared/dist/run-classification.js"() {
|
|
6299
6831
|
"use strict";
|
|
6300
6832
|
USER_CANCELLED_RUN_ERROR = "Cancelled by user";
|
|
6833
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR = "Cancelled by platform support";
|
|
6834
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR = "Cancelled by platform admin";
|
|
6835
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR = "Admin force-cancelled all active runs";
|
|
6836
|
+
CHAIN_CANCELLED_RUN_ERROR = "Cancelled: parent run cancelled";
|
|
6837
|
+
RETRY_HELD_RUN_ERROR = "Cancelled: auto generation paused";
|
|
6838
|
+
CANCELLED_REASON_PREFIXES = [
|
|
6839
|
+
USER_CANCELLED_RUN_ERROR,
|
|
6840
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
6841
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
6842
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
6843
|
+
CHAIN_CANCELLED_RUN_ERROR,
|
|
6844
|
+
RETRY_HELD_RUN_ERROR
|
|
6845
|
+
];
|
|
6846
|
+
isUserCancelledError = isCancelledReason;
|
|
6301
6847
|
HEAL_PATCH_HELD_RUN_ERROR_PREFIX = "Heal patch held";
|
|
6302
6848
|
RUNNER_INTERRUPT_ERROR_PREFIX = "Runner shutting down";
|
|
6303
6849
|
SERVER_INTERRUPT_ERROR_PREFIX = "Run interrupted by server restart";
|
|
@@ -6326,9 +6872,10 @@ var init_run_classification = __esm({
|
|
|
6326
6872
|
];
|
|
6327
6873
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES = [
|
|
6328
6874
|
...ENVIRONMENTAL_ERROR_PREFIXES.flatMap((prefix) => [prefix, `Error: ${prefix}`]),
|
|
6329
|
-
// Written by the
|
|
6330
|
-
|
|
6875
|
+
// Written by the cancels as is, with no prefix wrapper.
|
|
6876
|
+
...CANCELLED_REASON_PREFIXES
|
|
6331
6877
|
];
|
|
6878
|
+
FEATURE_ROW_RUN_WINDOW = 10;
|
|
6332
6879
|
BUG_SURFACE_SUPPRESSING_TAGS = ["@rate-limit-blocked", "@quota-exceeded", "@auth-lost"];
|
|
6333
6880
|
QUARANTINE_CLOSE_TAGS = [
|
|
6334
6881
|
"@bug-found",
|
|
@@ -8761,180 +9308,6 @@ var init_admin_view_return_to = __esm({
|
|
|
8761
9308
|
}
|
|
8762
9309
|
});
|
|
8763
9310
|
|
|
8764
|
-
// ../shared/dist/auth-plan.js
|
|
8765
|
-
function hasInlineLoginSteps(playwrightCode) {
|
|
8766
|
-
if (!playwrightCode)
|
|
8767
|
-
return false;
|
|
8768
|
-
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
8769
|
-
}
|
|
8770
|
-
function hasGeneratedAuthGuard(playwrightCode) {
|
|
8771
|
-
if (!playwrightCode)
|
|
8772
|
-
return false;
|
|
8773
|
-
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
8774
|
-
}
|
|
8775
|
-
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
8776
|
-
if (!sharedAuthInjectEnabled)
|
|
8777
|
-
return false;
|
|
8778
|
-
if (tags.includes("@auth"))
|
|
8779
|
-
return false;
|
|
8780
|
-
if (tags.includes("@api"))
|
|
8781
|
-
return true;
|
|
8782
|
-
if (!tags.includes("@needs-auth"))
|
|
8783
|
-
return false;
|
|
8784
|
-
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
8785
|
-
return true;
|
|
8786
|
-
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
8787
|
-
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
8788
|
-
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
8789
|
-
}
|
|
8790
|
-
function codeReadsStoredCredentials(code) {
|
|
8791
|
-
if (!code)
|
|
8792
|
-
return false;
|
|
8793
|
-
if (/__vqaLogin\b/.test(code))
|
|
8794
|
-
return true;
|
|
8795
|
-
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
8796
|
-
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
8797
|
-
return true;
|
|
8798
|
-
}
|
|
8799
|
-
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
8800
|
-
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
8801
|
-
return true;
|
|
8802
|
-
}
|
|
8803
|
-
return false;
|
|
8804
|
-
}
|
|
8805
|
-
function explicitAuthTypeTags(t) {
|
|
8806
|
-
const found = /* @__PURE__ */ new Set();
|
|
8807
|
-
for (const tag of t) {
|
|
8808
|
-
if (AUTH_TYPE_TAGS.includes(tag))
|
|
8809
|
-
found.add(tag);
|
|
8810
|
-
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
8811
|
-
found.add(AUTH_TAG_ALIASES[tag]);
|
|
8812
|
-
}
|
|
8813
|
-
return [...found];
|
|
8814
|
-
}
|
|
8815
|
-
function invalidPlan(configurationError) {
|
|
8816
|
-
return {
|
|
8817
|
-
version: 1,
|
|
8818
|
-
source: "invalid",
|
|
8819
|
-
acquisition: "unsupported",
|
|
8820
|
-
presentation: "none",
|
|
8821
|
-
needsCookieState: false,
|
|
8822
|
-
needsStandingHeaders: false,
|
|
8823
|
-
standingHeadersMode: "none",
|
|
8824
|
-
needsLoginCreds: false,
|
|
8825
|
-
requiredEnvKeys: [],
|
|
8826
|
-
configurationError
|
|
8827
|
-
};
|
|
8828
|
-
}
|
|
8829
|
-
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
8830
|
-
return {
|
|
8831
|
-
version: 1,
|
|
8832
|
-
source: "explicit",
|
|
8833
|
-
authTypeTag: authTypeTag2,
|
|
8834
|
-
acquisition,
|
|
8835
|
-
presentation,
|
|
8836
|
-
needsCookieState: opts.cookie,
|
|
8837
|
-
needsStandingHeaders: opts.standingMode === "required",
|
|
8838
|
-
standingHeadersMode: opts.standingMode,
|
|
8839
|
-
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
8840
|
-
requiredEnvKeys: opts.requiredEnvKeys
|
|
8841
|
-
};
|
|
8842
|
-
}
|
|
8843
|
-
function deriveAuthPlan(tags, code, opts) {
|
|
8844
|
-
const t = Array.isArray(tags) ? tags : [];
|
|
8845
|
-
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
8846
|
-
const isApi = t.includes("@api");
|
|
8847
|
-
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
8848
|
-
if (explicit.length > 0) {
|
|
8849
|
-
if (t.includes("@auth")) {
|
|
8850
|
-
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
8851
|
-
}
|
|
8852
|
-
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
8853
|
-
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
8854
|
-
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
8855
|
-
switch (loginCompose[0]) {
|
|
8856
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
8857
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8858
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
8859
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8860
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
8861
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8862
|
-
}
|
|
8863
|
-
}
|
|
8864
|
-
if (explicit.length > 1) {
|
|
8865
|
-
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
8866
|
-
}
|
|
8867
|
-
switch (explicit[0]) {
|
|
8868
|
-
case AUTH_TAG_UNSUPPORTED:
|
|
8869
|
-
return {
|
|
8870
|
-
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
8871
|
-
};
|
|
8872
|
-
case AUTH_TAG_NONE:
|
|
8873
|
-
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
8874
|
-
case AUTH_TAG_STANDING:
|
|
8875
|
-
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
8876
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
8877
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8878
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
8879
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8880
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
8881
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8882
|
-
}
|
|
8883
|
-
}
|
|
8884
|
-
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
8885
|
-
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
8886
|
-
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
8887
|
-
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
8888
|
-
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
8889
|
-
return {
|
|
8890
|
-
version: 1,
|
|
8891
|
-
source: "legacy",
|
|
8892
|
-
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
8893
|
-
presentation: authedLegacy ? "cookie" : "none",
|
|
8894
|
-
needsCookieState: cookie,
|
|
8895
|
-
needsStandingHeaders: false,
|
|
8896
|
-
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
8897
|
-
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
8898
|
-
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
8899
|
-
needsLoginCreds,
|
|
8900
|
-
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
8901
|
-
};
|
|
8902
|
-
}
|
|
8903
|
-
function authTypeTag(tags) {
|
|
8904
|
-
const t = Array.isArray(tags) ? tags : [];
|
|
8905
|
-
const explicit = explicitAuthTypeTags(t);
|
|
8906
|
-
return explicit.length === 1 ? explicit[0] : void 0;
|
|
8907
|
-
}
|
|
8908
|
-
var AUTH_TAG_COOKIE_STATE, AUTH_TAG_LOGIN_COOKIE, AUTH_TAG_LOGIN_BEARER, AUTH_TAG_STANDING, AUTH_TAG_NONE, AUTH_TAG_UNSUPPORTED, AUTH_TYPE_TAGS, AUTH_TAG_ALIASES, TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY;
|
|
8909
|
-
var init_auth_plan = __esm({
|
|
8910
|
-
"../shared/dist/auth-plan.js"() {
|
|
8911
|
-
"use strict";
|
|
8912
|
-
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
8913
|
-
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
8914
|
-
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
8915
|
-
AUTH_TAG_STANDING = "@auth-standing";
|
|
8916
|
-
AUTH_TAG_NONE = "@auth-none";
|
|
8917
|
-
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
8918
|
-
AUTH_TYPE_TAGS = [
|
|
8919
|
-
AUTH_TAG_COOKIE_STATE,
|
|
8920
|
-
AUTH_TAG_LOGIN_COOKIE,
|
|
8921
|
-
AUTH_TAG_LOGIN_BEARER,
|
|
8922
|
-
AUTH_TAG_STANDING,
|
|
8923
|
-
AUTH_TAG_NONE,
|
|
8924
|
-
AUTH_TAG_UNSUPPORTED
|
|
8925
|
-
];
|
|
8926
|
-
AUTH_TAG_ALIASES = {
|
|
8927
|
-
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
8928
|
-
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
8929
|
-
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
8930
|
-
"@auth-api-key": AUTH_TAG_STANDING,
|
|
8931
|
-
"@auth-standing-header": AUTH_TAG_STANDING
|
|
8932
|
-
};
|
|
8933
|
-
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
8934
|
-
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
8935
|
-
}
|
|
8936
|
-
});
|
|
8937
|
-
|
|
8938
9311
|
// ../shared/dist/auth-block-detector.js
|
|
8939
9312
|
function stripEchoLines(text) {
|
|
8940
9313
|
return text.split("\n").filter((line) => !ECHO_LINE_RE.test(line)).join("\n");
|
|
@@ -8942,13 +9315,16 @@ function stripEchoLines(text) {
|
|
|
8942
9315
|
function matchesAny(text, patterns) {
|
|
8943
9316
|
return patterns.some((p) => p.test(text));
|
|
8944
9317
|
}
|
|
9318
|
+
function isIntentionalNegativeAuthTest(input) {
|
|
9319
|
+
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
9320
|
+
return matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH);
|
|
9321
|
+
}
|
|
8945
9322
|
function detectAuthBlock(input) {
|
|
8946
9323
|
const tags = input.tags ?? [];
|
|
8947
9324
|
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
8948
9325
|
if (!isAuthed)
|
|
8949
9326
|
return NO_DETECTION;
|
|
8950
|
-
|
|
8951
|
-
if (matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH))
|
|
9327
|
+
if (isIntentionalNegativeAuthTest(input))
|
|
8952
9328
|
return NO_DETECTION;
|
|
8953
9329
|
const sources = [];
|
|
8954
9330
|
if (input.error)
|
|
@@ -9051,7 +9427,7 @@ var init_auth_block_detector = __esm({
|
|
|
9051
9427
|
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
9052
9428
|
];
|
|
9053
9429
|
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
9054
|
-
UNAUTHORIZED_TEXT_RE = /(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|gives?|sends?|yield(?:s|ed|ing)?|results?\s+in)\s+(?:a\s+|an\s+|the\s+)?(?:401|403)\b|\bstatus(?:\s+code)?\s
|
|
9430
|
+
UNAUTHORIZED_TEXT_RE = /(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|gives?|sends?|yield(?:s|ed|ing)?|results?\s+in)\s+(?:a\s+|an\s+|the\s+)?(?:401|403)\b|\bstatus(?:\s+code)?\s*(?::\s*)?(?:401|403)\b|\bHTTP\/[\d.]+\s+(?:401|403)\b|(?:401|403)['’]d\b|(?:[→⇒]|->)\s*(?:401|403)\b|(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|threw|throws?)\s+(?:a\s+|an\s+)?(?:unauthorized|forbidden)\b|\bnot\s+authenticated\b/i;
|
|
9055
9431
|
}
|
|
9056
9432
|
});
|
|
9057
9433
|
|
|
@@ -9992,12 +10368,70 @@ function isSharedAuthInjectEnabled(value = process.env.SHARED_AUTH_INJECT) {
|
|
|
9992
10368
|
function isAuthReadinessGuardEnabled(value = process.env.AUTH_READINESS_GUARD) {
|
|
9993
10369
|
return value?.trim().toLowerCase() !== "false";
|
|
9994
10370
|
}
|
|
10371
|
+
function visualBaselinesEnabled(projectId, raw = process.env.VISUAL_BASELINES_PROJECTS) {
|
|
10372
|
+
if (typeof projectId !== "string" || projectId.trim() === "")
|
|
10373
|
+
return false;
|
|
10374
|
+
const listed = (raw ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
10375
|
+
return listed.includes("*") || listed.includes(projectId);
|
|
10376
|
+
}
|
|
9995
10377
|
var init_feature_flags = __esm({
|
|
9996
10378
|
"../shared/dist/feature-flags.js"() {
|
|
9997
10379
|
"use strict";
|
|
9998
10380
|
}
|
|
9999
10381
|
});
|
|
10000
10382
|
|
|
10383
|
+
// ../shared/dist/visual-compare-limits.js
|
|
10384
|
+
function isSafeMaskSelector(selector) {
|
|
10385
|
+
if (typeof selector !== "string")
|
|
10386
|
+
return false;
|
|
10387
|
+
if (selector.trim().length === 0)
|
|
10388
|
+
return false;
|
|
10389
|
+
if (selector.length > VISUAL_MASK_SELECTOR_MAX_LENGTH)
|
|
10390
|
+
return false;
|
|
10391
|
+
return !VISUAL_MASK_SELECTOR_FORBIDDEN.test(selector);
|
|
10392
|
+
}
|
|
10393
|
+
var VISUAL_MASK_SELECTORS_MAX, VISUAL_MASK_SELECTOR_MAX_LENGTH, VISUAL_MASK_SELECTOR_FORBIDDEN;
|
|
10394
|
+
var init_visual_compare_limits = __esm({
|
|
10395
|
+
"../shared/dist/visual-compare-limits.js"() {
|
|
10396
|
+
"use strict";
|
|
10397
|
+
VISUAL_MASK_SELECTORS_MAX = 50;
|
|
10398
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH = 300;
|
|
10399
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN = /[{};@<\r\n]/;
|
|
10400
|
+
}
|
|
10401
|
+
});
|
|
10402
|
+
|
|
10403
|
+
// ../shared/dist/visual-baseline-identity.js
|
|
10404
|
+
function isBrowserVersion(value) {
|
|
10405
|
+
return typeof value === "string" && value.length <= 32 && BROWSER_VERSION.test(value);
|
|
10406
|
+
}
|
|
10407
|
+
function renderIdentity(flavour, version, image) {
|
|
10408
|
+
if (!/^[a-z][a-z-]{0,31}$/.test(flavour) || !/^[a-z][a-z-]{0,31}$/.test(image) || !isBrowserVersion(version))
|
|
10409
|
+
return null;
|
|
10410
|
+
const identity = `${flavour}/${version}/${image}`;
|
|
10411
|
+
return identity.length <= RENDER_IDENTITY_MAX_LENGTH ? identity : null;
|
|
10412
|
+
}
|
|
10413
|
+
function v1RenderIdentity(version) {
|
|
10414
|
+
return renderIdentity(VISUAL_V1_IDENTITY.flavour, version, VISUAL_V1_IDENTITY.image);
|
|
10415
|
+
}
|
|
10416
|
+
function parseRenderIdentity(value) {
|
|
10417
|
+
if (typeof value !== "string" || value.length > RENDER_IDENTITY_MAX_LENGTH)
|
|
10418
|
+
return null;
|
|
10419
|
+
const parts = value.split("/");
|
|
10420
|
+
if (parts.length !== 3)
|
|
10421
|
+
return null;
|
|
10422
|
+
const [flavour, version, image] = parts;
|
|
10423
|
+
return renderIdentity(flavour, version, image) === value ? { flavour, version, image } : null;
|
|
10424
|
+
}
|
|
10425
|
+
var VISUAL_V1_IDENTITY, RENDER_IDENTITY_MAX_LENGTH, BROWSER_VERSION;
|
|
10426
|
+
var init_visual_baseline_identity = __esm({
|
|
10427
|
+
"../shared/dist/visual-baseline-identity.js"() {
|
|
10428
|
+
"use strict";
|
|
10429
|
+
VISUAL_V1_IDENTITY = { platform: "linux", image: "runner-fast", flavour: "headless-shell" };
|
|
10430
|
+
RENDER_IDENTITY_MAX_LENGTH = 64;
|
|
10431
|
+
BROWSER_VERSION = /^\d{1,4}(\.\d{1,6}){0,3}$/;
|
|
10432
|
+
}
|
|
10433
|
+
});
|
|
10434
|
+
|
|
10001
10435
|
// ../shared/dist/analytics-url.js
|
|
10002
10436
|
function isSensitiveQueryKey(key) {
|
|
10003
10437
|
return SENSITIVE_QUERY_KEY_RE.test(key);
|
|
@@ -10351,14 +10785,9 @@ function isOpenCodeGoModelId(id) {
|
|
|
10351
10785
|
function hasOpenCodeGoPrefix(id) {
|
|
10352
10786
|
return (id?.trim() ?? "").startsWith(OPENCODE_GO_PREFIX);
|
|
10353
10787
|
}
|
|
10354
|
-
function hasOpenCodeGo2Prefix(id) {
|
|
10355
|
-
return (id?.trim() ?? "").startsWith(OPENCODE_GO_2_PREFIX);
|
|
10356
|
-
}
|
|
10357
10788
|
function openCodeGoWireModel(id) {
|
|
10358
10789
|
const trimmed = id?.trim() ?? "";
|
|
10359
|
-
|
|
10360
|
-
return null;
|
|
10361
|
-
return trimmed.slice((hasOpenCodeGo2Prefix(trimmed) ? OPENCODE_GO_2_PREFIX : OPENCODE_GO_PREFIX).length);
|
|
10790
|
+
return isOpenCodeGoModelId(trimmed) ? trimmed.slice(OPENCODE_GO_PREFIX.length) : null;
|
|
10362
10791
|
}
|
|
10363
10792
|
function isZaiModelId(id) {
|
|
10364
10793
|
const trimmed = id?.trim() ?? "";
|
|
@@ -10467,7 +10896,7 @@ function museCliContributorMode(env = process.env) {
|
|
|
10467
10896
|
const raw = (env.MUSE_CLI_CONTRIBUTOR_MODE ?? "").trim().toLowerCase();
|
|
10468
10897
|
return raw === "off" || raw === "false" || raw === "0" || raw === "no" ? "off" : "on";
|
|
10469
10898
|
}
|
|
10470
|
-
var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX,
|
|
10899
|
+
var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX, OPENCODE_GO_MODEL_PATTERN, ZAI_PREFIX, ZAI_MODEL_PATTERN;
|
|
10471
10900
|
var init_engine_spec = __esm({
|
|
10472
10901
|
"../shared/dist/engine-spec.js"() {
|
|
10473
10902
|
"use strict";
|
|
@@ -10526,8 +10955,7 @@ var init_engine_spec = __esm({
|
|
|
10526
10955
|
OPENROUTER_PREFIX = "openrouter:";
|
|
10527
10956
|
OPENROUTER_MODEL_PATTERN = /^openrouter:[a-z0-9][a-z0-9._-]{0,40}\/[A-Za-z0-9._:-]{1,100}$/;
|
|
10528
10957
|
OPENCODE_GO_PREFIX = "opencode-go:";
|
|
10529
|
-
|
|
10530
|
-
OPENCODE_GO_MODEL_PATTERN = /^opencode-go(?:-2)?:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
10958
|
+
OPENCODE_GO_MODEL_PATTERN = /^opencode-go:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
10531
10959
|
ZAI_PREFIX = "zai:";
|
|
10532
10960
|
ZAI_MODEL_PATTERN = /^zai:glm-[a-z0-9][a-z0-9._-]{0,60}$/;
|
|
10533
10961
|
}
|
|
@@ -10852,14 +11280,19 @@ function has(map, key) {
|
|
|
10852
11280
|
}
|
|
10853
11281
|
function providerChainFor(modelId) {
|
|
10854
11282
|
const key = chainKey(modelId);
|
|
11283
|
+
if (key && has(_overrideHops, key))
|
|
11284
|
+
return _overrideHops[key];
|
|
10855
11285
|
return key && has(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
|
|
10856
11286
|
}
|
|
10857
11287
|
function providerChainLeadsFor(modelId) {
|
|
10858
11288
|
const key = chainKey(modelId);
|
|
11289
|
+
if (key && has(_overrideLeads, key))
|
|
11290
|
+
return _overrideLeads[key];
|
|
10859
11291
|
return key && has(PROVIDER_CHAIN_LEADS, key) ? PROVIDER_CHAIN_LEADS[key] : [];
|
|
10860
11292
|
}
|
|
10861
11293
|
function allChains() {
|
|
10862
|
-
|
|
11294
|
+
const ordered = (map, override) => [...Object.entries(map).filter(([key]) => !has(override, key)), ...Object.entries(override)];
|
|
11295
|
+
return [...ordered(PROVIDER_CHAINS, _overrideHops), ...ordered(PROVIDER_CHAIN_LEADS, _overrideLeads)];
|
|
10863
11296
|
}
|
|
10864
11297
|
function isProviderChainHopId(modelId) {
|
|
10865
11298
|
const id = modelId ?? "";
|
|
@@ -10876,14 +11309,24 @@ function providerChainHostOf(value, modelValue) {
|
|
|
10876
11309
|
return "own";
|
|
10877
11310
|
if (hasZaiPrefix(value))
|
|
10878
11311
|
return "zai";
|
|
10879
|
-
if (hasOpenCodeGo2Prefix(value))
|
|
10880
|
-
return "opencode-go-2";
|
|
10881
11312
|
if (hasOpenCodeGoPrefix(value))
|
|
10882
11313
|
return "opencode-go";
|
|
10883
11314
|
if (hasOpenRouterPrefix(value))
|
|
10884
11315
|
return "openrouter";
|
|
10885
11316
|
return "own";
|
|
10886
11317
|
}
|
|
11318
|
+
function providerChainHostProvider(value) {
|
|
11319
|
+
if (typeof value !== "string" || !value)
|
|
11320
|
+
return null;
|
|
11321
|
+
if (hasOpenRouterPrefix(value))
|
|
11322
|
+
return "openrouter";
|
|
11323
|
+
if (hasOpenCodeGoPrefix(value))
|
|
11324
|
+
return "opencode-go";
|
|
11325
|
+
if (hasZaiPrefix(value))
|
|
11326
|
+
return "zai";
|
|
11327
|
+
const key = chainKey(value);
|
|
11328
|
+
return API_MODEL_CATALOG.find((m) => m.id === key)?.provider ?? GEMINI_ASSISTANT_MODELS.find((m) => m.id === key)?.provider ?? null;
|
|
11329
|
+
}
|
|
10887
11330
|
function providerHostPlan(modelId) {
|
|
10888
11331
|
const key = chainKey(modelId);
|
|
10889
11332
|
if (!key)
|
|
@@ -10901,7 +11344,140 @@ function providerHostPlan(modelId) {
|
|
|
10901
11344
|
}
|
|
10902
11345
|
return steps;
|
|
10903
11346
|
}
|
|
10904
|
-
|
|
11347
|
+
function providerChainModelKey(modelId) {
|
|
11348
|
+
return chainKey(modelId);
|
|
11349
|
+
}
|
|
11350
|
+
function hasProviderChainLeadsByDefault(modelId) {
|
|
11351
|
+
const key = chainKey(modelId);
|
|
11352
|
+
return key !== null && has(PROVIDER_CHAIN_LEADS, key);
|
|
11353
|
+
}
|
|
11354
|
+
function isChainablePrimary(id) {
|
|
11355
|
+
return typeof id === "string" && id !== "" && (has(PROVIDER_CHAINS, id) || has(PROVIDER_CHAIN_LEADS, id));
|
|
11356
|
+
}
|
|
11357
|
+
function defaultProviderChainEntries(primary) {
|
|
11358
|
+
if (!isChainablePrimary(primary))
|
|
11359
|
+
return [];
|
|
11360
|
+
const leads = has(PROVIDER_CHAIN_LEADS, primary) ? PROVIDER_CHAIN_LEADS[primary] : [];
|
|
11361
|
+
const hops = has(PROVIDER_CHAINS, primary) ? PROVIDER_CHAINS[primary] : [];
|
|
11362
|
+
return [...leads, primary, ...hops].map((hop) => ({ hop, enabled: true }));
|
|
11363
|
+
}
|
|
11364
|
+
function allowedProviderChainHosts(primary) {
|
|
11365
|
+
return defaultProviderChainEntries(primary).map((entry) => entry.hop);
|
|
11366
|
+
}
|
|
11367
|
+
function isPlainObject2(value) {
|
|
11368
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
11369
|
+
}
|
|
11370
|
+
function validateProviderChainEntries(primary, entries) {
|
|
11371
|
+
if (!isChainablePrimary(primary))
|
|
11372
|
+
return `${String(primary).slice(0, 80)} has no provider chain to order`;
|
|
11373
|
+
if (!Array.isArray(entries))
|
|
11374
|
+
return `${primary}: the chain must be a list`;
|
|
11375
|
+
if (entries.length > PROVIDER_CHAIN_MAX_ENTRIES)
|
|
11376
|
+
return `${primary}: at most ${PROVIDER_CHAIN_MAX_ENTRIES} hosts`;
|
|
11377
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
11378
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11379
|
+
for (const entry of entries) {
|
|
11380
|
+
if (!isPlainObject2(entry))
|
|
11381
|
+
return `${primary}: each host must be { hop, enabled }`;
|
|
11382
|
+
const keys = Object.keys(entry);
|
|
11383
|
+
if (keys.length !== 2 || !keys.includes("hop") || !keys.includes("enabled"))
|
|
11384
|
+
return `${primary}: each host must be { hop, enabled } and nothing else`;
|
|
11385
|
+
const { hop, enabled } = entry;
|
|
11386
|
+
if (typeof enabled !== "boolean")
|
|
11387
|
+
return `${primary}: enabled must be true or false`;
|
|
11388
|
+
if (typeof hop !== "string" || !hop)
|
|
11389
|
+
return `${primary}: hop must be a model value`;
|
|
11390
|
+
if (!allowed.includes(hop))
|
|
11391
|
+
return `${primary}: ${hop.slice(0, 80)} is not a host of this model`;
|
|
11392
|
+
if (seen.has(hop))
|
|
11393
|
+
return `${primary}: ${hop} is listed twice`;
|
|
11394
|
+
if (hop === primary && !enabled)
|
|
11395
|
+
return `${primary}: the model's own value stays on (pick another model on AI Models instead)`;
|
|
11396
|
+
seen.add(hop);
|
|
11397
|
+
}
|
|
11398
|
+
if (!seen.has(primary))
|
|
11399
|
+
return `${primary}: list the model's own value once, where its own host sits`;
|
|
11400
|
+
return null;
|
|
11401
|
+
}
|
|
11402
|
+
function decodeProviderChains(raw) {
|
|
11403
|
+
let value = raw;
|
|
11404
|
+
if (typeof raw === "string") {
|
|
11405
|
+
if (raw.length > PROVIDER_CHAINS_SETTING_MAX_CHARS)
|
|
11406
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
11407
|
+
try {
|
|
11408
|
+
value = JSON.parse(raw);
|
|
11409
|
+
} catch {
|
|
11410
|
+
return { ok: false, error: "AI_PROVIDER_CHAINS must be valid JSON" };
|
|
11411
|
+
}
|
|
11412
|
+
} else if (JSON.stringify(raw ?? null).length > PROVIDER_CHAINS_SETTING_MAX_CHARS) {
|
|
11413
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
11414
|
+
}
|
|
11415
|
+
if (!isPlainObject2(value))
|
|
11416
|
+
return { ok: false, error: 'AI_PROVIDER_CHAINS must be an object: { "<model>": [ { "hop": "<model value>", "enabled": true } ] }' };
|
|
11417
|
+
if (Object.keys(value).length > PROVIDER_CHAIN_MAX_PRIMARIES)
|
|
11418
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS names at most ${PROVIDER_CHAIN_MAX_PRIMARIES} models` };
|
|
11419
|
+
return { ok: true, value };
|
|
11420
|
+
}
|
|
11421
|
+
function checkedProviderChains(value) {
|
|
11422
|
+
const out = {};
|
|
11423
|
+
for (const [primary, entries] of Object.entries(value)) {
|
|
11424
|
+
const problem = validateProviderChainEntries(primary, entries);
|
|
11425
|
+
if (problem)
|
|
11426
|
+
return { ok: false, error: problem };
|
|
11427
|
+
out[primary] = entries.map(({ hop, enabled }) => ({ hop, enabled }));
|
|
11428
|
+
}
|
|
11429
|
+
return { ok: true, value: out };
|
|
11430
|
+
}
|
|
11431
|
+
function parseProviderChainOverrides(raw) {
|
|
11432
|
+
const decoded = decodeProviderChains(raw);
|
|
11433
|
+
return decoded.ok ? checkedProviderChains(decoded.value) : decoded;
|
|
11434
|
+
}
|
|
11435
|
+
function parseStoredProviderChainOverrides(raw) {
|
|
11436
|
+
const decoded = decodeProviderChains(raw);
|
|
11437
|
+
if (!decoded.ok)
|
|
11438
|
+
return decoded;
|
|
11439
|
+
const dropped = [];
|
|
11440
|
+
const kept = {};
|
|
11441
|
+
for (const [primary, entries] of Object.entries(decoded.value)) {
|
|
11442
|
+
if (!isChainablePrimary(primary) || !Array.isArray(entries)) {
|
|
11443
|
+
kept[primary] = entries;
|
|
11444
|
+
continue;
|
|
11445
|
+
}
|
|
11446
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
11447
|
+
kept[primary] = entries.filter((entry) => {
|
|
11448
|
+
const hop = isPlainObject2(entry) ? entry.hop : void 0;
|
|
11449
|
+
if (typeof hop !== "string" || hop === "" || allowed.includes(hop))
|
|
11450
|
+
return true;
|
|
11451
|
+
dropped.push({ primary, hop: hop.slice(0, 80) });
|
|
11452
|
+
return false;
|
|
11453
|
+
});
|
|
11454
|
+
}
|
|
11455
|
+
const checked = checkedProviderChains(kept);
|
|
11456
|
+
return checked.ok ? { ...checked, dropped } : checked;
|
|
11457
|
+
}
|
|
11458
|
+
function validateProviderChainsSetting(raw) {
|
|
11459
|
+
const parsed = parseProviderChainOverrides(raw);
|
|
11460
|
+
return parsed.ok ? null : parsed.error;
|
|
11461
|
+
}
|
|
11462
|
+
function setProviderChainOverrides(value, onDropped) {
|
|
11463
|
+
const parsed = value === null || value === void 0 || value === "" ? null : parseStoredProviderChainOverrides(value);
|
|
11464
|
+
if (parsed?.ok && parsed.dropped.length > 0)
|
|
11465
|
+
onDropped?.(parsed.dropped);
|
|
11466
|
+
_overrides = parsed?.ok ? parsed.value : null;
|
|
11467
|
+
_overrideLeads = {};
|
|
11468
|
+
_overrideHops = {};
|
|
11469
|
+
for (const [primary, entries] of Object.entries(_overrides ?? {})) {
|
|
11470
|
+
const at = entries.findIndex((entry) => entry.hop === primary);
|
|
11471
|
+
const on = (list) => list.filter((entry) => entry.enabled).map((entry) => entry.hop);
|
|
11472
|
+
_overrideLeads[primary] = on(entries.slice(0, at));
|
|
11473
|
+
_overrideHops[primary] = on(entries.slice(at + 1));
|
|
11474
|
+
}
|
|
11475
|
+
return parsed === null || parsed.ok;
|
|
11476
|
+
}
|
|
11477
|
+
function getProviderChainOverrides() {
|
|
11478
|
+
return _overrides;
|
|
11479
|
+
}
|
|
11480
|
+
var PROVIDER_CHAINS, PROVIDER_CHAIN_LEADS, PROVIDER_HOST_NOT_OFFERED, PROVIDER_CHAIN_MAX_ENTRIES, PROVIDER_CHAINS_SETTING_MAX_CHARS, PROVIDER_CHAIN_MAX_PRIMARIES, ALLOWED_PROVIDER_CHAIN_HOPS, _overrides, _overrideLeads, _overrideHops;
|
|
10905
11481
|
var init_provider_chains = __esm({
|
|
10906
11482
|
"../shared/dist/provider-chains.js"() {
|
|
10907
11483
|
"use strict";
|
|
@@ -10913,18 +11489,120 @@ var init_provider_chains = __esm({
|
|
|
10913
11489
|
"muse-spark-1.3-contributor": ["openrouter:meta/muse-spark-1.3-contributor"],
|
|
10914
11490
|
"claude-haiku-5-5": ["opencode-go:claude-haiku-5-5", "openrouter:anthropic/claude-haiku-5.5"],
|
|
10915
11491
|
"gemini-3.1-pro-preview": ["openrouter:google/gemini-3.1-pro-preview"],
|
|
10916
|
-
"deepseek-flash": ["opencode-go
|
|
10917
|
-
"deepseek-v4-pro": ["opencode-go
|
|
11492
|
+
"deepseek-flash": ["opencode-go:deepseek-v4.1-flash", "openrouter:deepseek/deepseek-v4.1-flash"],
|
|
11493
|
+
"deepseek-v4-pro": ["opencode-go:deepseek-v4-pro", "openrouter:deepseek/deepseek-v4-pro"]
|
|
10918
11494
|
};
|
|
10919
11495
|
PROVIDER_CHAIN_LEADS = {
|
|
10920
|
-
"openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go
|
|
10921
|
-
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go
|
|
10922
|
-
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go
|
|
11496
|
+
"openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go:glm-5.3-flash"],
|
|
11497
|
+
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go:glm-5.3"],
|
|
11498
|
+
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go:glm-5.2"]
|
|
10923
11499
|
};
|
|
10924
11500
|
PROVIDER_HOST_NOT_OFFERED = {
|
|
10925
11501
|
"muse-spark-1.3-contributor": { "opencode-go": "OpenCode Go serves Muse only on its Responses API" },
|
|
10926
11502
|
"gemini-3.1-pro-preview": { "opencode-go": "OpenCode Go does not serve Gemini" }
|
|
10927
11503
|
};
|
|
11504
|
+
PROVIDER_CHAIN_MAX_ENTRIES = 8;
|
|
11505
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS = 16e3;
|
|
11506
|
+
PROVIDER_CHAIN_MAX_PRIMARIES = 32;
|
|
11507
|
+
ALLOWED_PROVIDER_CHAIN_HOPS = /* @__PURE__ */ new Set([
|
|
11508
|
+
...Object.values(PROVIDER_CHAINS).flat(),
|
|
11509
|
+
...Object.values(PROVIDER_CHAIN_LEADS).flat()
|
|
11510
|
+
]);
|
|
11511
|
+
_overrides = null;
|
|
11512
|
+
_overrideLeads = {};
|
|
11513
|
+
_overrideHops = {};
|
|
11514
|
+
}
|
|
11515
|
+
});
|
|
11516
|
+
|
|
11517
|
+
// ../shared/dist/provider-accounts.js
|
|
11518
|
+
function modelNames(modelId) {
|
|
11519
|
+
const value = modelId.trim();
|
|
11520
|
+
const names = /* @__PURE__ */ new Set([value]);
|
|
11521
|
+
for (const prefix of HOST_PREFIXES) {
|
|
11522
|
+
if (!value.startsWith(prefix))
|
|
11523
|
+
continue;
|
|
11524
|
+
const bare = value.slice(prefix.length);
|
|
11525
|
+
names.add(bare);
|
|
11526
|
+
const slash = bare.lastIndexOf("/");
|
|
11527
|
+
if (slash >= 0)
|
|
11528
|
+
names.add(bare.slice(slash + 1));
|
|
11529
|
+
}
|
|
11530
|
+
const canonical = canonicalModelId(value);
|
|
11531
|
+
if (canonical) {
|
|
11532
|
+
names.add(canonical);
|
|
11533
|
+
const entry = API_MODEL_CATALOG.find((m) => m.id === canonical || m.apiModel === canonical);
|
|
11534
|
+
if (entry) {
|
|
11535
|
+
names.add(entry.id);
|
|
11536
|
+
if (entry.apiModel)
|
|
11537
|
+
names.add(entry.apiModel);
|
|
11538
|
+
}
|
|
11539
|
+
}
|
|
11540
|
+
return names;
|
|
11541
|
+
}
|
|
11542
|
+
function accountServesModel(models, modelId) {
|
|
11543
|
+
if (!models || models.length === 0)
|
|
11544
|
+
return true;
|
|
11545
|
+
if (!modelId)
|
|
11546
|
+
return false;
|
|
11547
|
+
const names = modelNames(modelId);
|
|
11548
|
+
return models.some((model) => names.has(model.trim()));
|
|
11549
|
+
}
|
|
11550
|
+
function normalizeProviderAccountModels(models) {
|
|
11551
|
+
if (!Array.isArray(models))
|
|
11552
|
+
return null;
|
|
11553
|
+
const out = [];
|
|
11554
|
+
for (const model of models) {
|
|
11555
|
+
if (typeof model !== "string")
|
|
11556
|
+
return null;
|
|
11557
|
+
const trimmed = model.trim();
|
|
11558
|
+
if (!PROVIDER_ACCOUNT_MODEL_PATTERN.test(trimmed) || trimmed.includes(".."))
|
|
11559
|
+
return null;
|
|
11560
|
+
if (!out.includes(trimmed))
|
|
11561
|
+
out.push(trimmed);
|
|
11562
|
+
}
|
|
11563
|
+
return out.length > MAX_PROVIDER_ACCOUNT_MODELS ? null : out;
|
|
11564
|
+
}
|
|
11565
|
+
function parseProviderAccountLists(value, providers) {
|
|
11566
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
11567
|
+
return null;
|
|
11568
|
+
const parsed = {};
|
|
11569
|
+
for (const provider of providers) {
|
|
11570
|
+
const list = value[provider];
|
|
11571
|
+
if (!Array.isArray(list))
|
|
11572
|
+
continue;
|
|
11573
|
+
const accounts = [];
|
|
11574
|
+
for (const raw of list) {
|
|
11575
|
+
if (!raw || typeof raw !== "object")
|
|
11576
|
+
continue;
|
|
11577
|
+
const { id, label, key, models } = raw;
|
|
11578
|
+
if (typeof id !== "string" || !id.trim() || typeof key !== "string" || !key.trim())
|
|
11579
|
+
continue;
|
|
11580
|
+
const modelList = Array.isArray(models) ? models.filter((m) => typeof m === "string" && m.trim() !== "").map((m) => m.trim()) : [];
|
|
11581
|
+
accounts.push({ id: id.trim(), label: typeof label === "string" && label.trim() ? label.trim() : null, key: key.trim(), models: modelList });
|
|
11582
|
+
}
|
|
11583
|
+
if (accounts.length > 0)
|
|
11584
|
+
parsed[provider] = accounts;
|
|
11585
|
+
}
|
|
11586
|
+
return parsed;
|
|
11587
|
+
}
|
|
11588
|
+
var DEFAULT_PROVIDER_ACCOUNT_ID, PROVIDER_ACCOUNT_ID_PATTERN, MAX_PROVIDER_ACCOUNTS, MAX_PROVIDER_ACCOUNT_MODELS, PROVIDER_ACCOUNT_MODEL_PATTERN, OPENCODE_GO_DEEPSEEK_GLM_MODELS, HOST_PREFIXES;
|
|
11589
|
+
var init_provider_accounts = __esm({
|
|
11590
|
+
"../shared/dist/provider-accounts.js"() {
|
|
11591
|
+
"use strict";
|
|
11592
|
+
init_api_model_catalog();
|
|
11593
|
+
DEFAULT_PROVIDER_ACCOUNT_ID = "primary";
|
|
11594
|
+
PROVIDER_ACCOUNT_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
11595
|
+
MAX_PROVIDER_ACCOUNTS = 10;
|
|
11596
|
+
MAX_PROVIDER_ACCOUNT_MODELS = 50;
|
|
11597
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,120}$/;
|
|
11598
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS = [
|
|
11599
|
+
"deepseek-v4.1-flash",
|
|
11600
|
+
"deepseek-v4-pro",
|
|
11601
|
+
"glm-5.3-flash",
|
|
11602
|
+
"glm-5.3",
|
|
11603
|
+
"glm-5.2"
|
|
11604
|
+
];
|
|
11605
|
+
HOST_PREFIXES = ["opencode-go:", "zai:", "openrouter:"];
|
|
10928
11606
|
}
|
|
10929
11607
|
});
|
|
10930
11608
|
|
|
@@ -11043,6 +11721,25 @@ var init_project_engine_overrides = __esm({
|
|
|
11043
11721
|
}
|
|
11044
11722
|
});
|
|
11045
11723
|
|
|
11724
|
+
// ../shared/dist/trailing-slashes.js
|
|
11725
|
+
function stripTrailingSlashes(value) {
|
|
11726
|
+
let end = value.length;
|
|
11727
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
11728
|
+
end--;
|
|
11729
|
+
return end === value.length ? value : value.slice(0, end);
|
|
11730
|
+
}
|
|
11731
|
+
function stripTrailingChars(value, isTrailing) {
|
|
11732
|
+
let end = value.length;
|
|
11733
|
+
while (end > 0 && isTrailing.test(value[end - 1]))
|
|
11734
|
+
end--;
|
|
11735
|
+
return end === value.length ? value : value.slice(0, end);
|
|
11736
|
+
}
|
|
11737
|
+
var init_trailing_slashes = __esm({
|
|
11738
|
+
"../shared/dist/trailing-slashes.js"() {
|
|
11739
|
+
"use strict";
|
|
11740
|
+
}
|
|
11741
|
+
});
|
|
11742
|
+
|
|
11046
11743
|
// ../shared/dist/gemini-visual.js
|
|
11047
11744
|
function visualProDailyBudget(raw) {
|
|
11048
11745
|
const parsed = raw && /^\s*\d{1,6}\s*$/.test(raw) ? Number(raw.trim()) : NaN;
|
|
@@ -11056,7 +11753,7 @@ function isRetiredGeminiModel(id) {
|
|
|
11056
11753
|
}
|
|
11057
11754
|
function geminiNativeModelsUrl(base = process.env.GEMINI_API_BASE) {
|
|
11058
11755
|
const raw = base && base.trim() || GEMINI_OPENAI_BASE;
|
|
11059
|
-
const native = raw.replace(/\/openai\/?$/, "/")
|
|
11756
|
+
const native = stripTrailingSlashes(raw.replace(/\/openai\/?$/, "/"));
|
|
11060
11757
|
return `${native}/models?pageSize=1000`;
|
|
11061
11758
|
}
|
|
11062
11759
|
function asRecord(value) {
|
|
@@ -11176,6 +11873,7 @@ var KNOWN_INPUT_USD_PER_M, GEMINI_OPENAI_BASE, DEFAULT_GEMINI_SCREEN_MODEL, DEFA
|
|
|
11176
11873
|
var init_gemini_visual = __esm({
|
|
11177
11874
|
"../shared/dist/gemini-visual.js"() {
|
|
11178
11875
|
"use strict";
|
|
11876
|
+
init_trailing_slashes();
|
|
11179
11877
|
KNOWN_INPUT_USD_PER_M = {
|
|
11180
11878
|
"gemini-2.5-flash-lite": 0.1,
|
|
11181
11879
|
"gemini-3.1-flash-lite": 0.25,
|
|
@@ -12539,12 +13237,13 @@ function truncateAtWord(text, max) {
|
|
|
12539
13237
|
const slice = trimmed.slice(0, room + 1);
|
|
12540
13238
|
const lastSpace = slice.lastIndexOf(" ");
|
|
12541
13239
|
const cut = lastSpace > room * 0.5 ? slice.slice(0, lastSpace) : trimmed.slice(0, room);
|
|
12542
|
-
return `${cut
|
|
13240
|
+
return `${stripTrailingChars(cut, TRAILING_PUNCTUATION)}\u2026`;
|
|
12543
13241
|
}
|
|
12544
|
-
var CANVAS_UNSUPPORTED_CODE, CANVAS_UNSUPPORTED_TITLE, CANVAS_UNSUPPORTED_BODY, CANVAS_UNSUPPORTED_NOT_CHARGED, CANVAS_UNSUPPORTED_OVERRIDE_HINT, GAME_ENGINES, RENDERER_ENGINES, ENGINE_TEXT_SIGNATURES, GAME_LIBRARY_TEXT_PATTERNS, ENGINE_PACKAGES, GAME_HINT_PACKAGES, MAX_TAG_CHARS, MAX_CSS_SELECTOR_CHARS, MAX_CSS_BLOCK_CHARS, TAG_NAME_RE, ATTR_RE, INTERACTIVE_TAGS, INTERACTIVE_ROLES, ROOT_SELECTOR_RE, OVERFLOW_HIDDEN_RE, TOUCH_NONE_RE, CODE_TAGS, STATIC_STANDARD_MIN_INTERACTIVE;
|
|
13242
|
+
var CANVAS_UNSUPPORTED_CODE, CANVAS_UNSUPPORTED_TITLE, CANVAS_UNSUPPORTED_BODY, CANVAS_UNSUPPORTED_NOT_CHARGED, CANVAS_UNSUPPORTED_OVERRIDE_HINT, GAME_ENGINES, RENDERER_ENGINES, ENGINE_TEXT_SIGNATURES, GAME_LIBRARY_TEXT_PATTERNS, ENGINE_PACKAGES, GAME_HINT_PACKAGES, MAX_TAG_CHARS, MAX_CSS_SELECTOR_CHARS, MAX_CSS_BLOCK_CHARS, TAG_NAME_RE, ATTR_RE, INTERACTIVE_TAGS, INTERACTIVE_ROLES, ROOT_SELECTOR_RE, OVERFLOW_HIDDEN_RE, TOUCH_NONE_RE, CODE_TAGS, STATIC_STANDARD_MIN_INTERACTIVE, TRAILING_PUNCTUATION;
|
|
12545
13243
|
var init_canvas_support = __esm({
|
|
12546
13244
|
"../shared/dist/canvas-support.js"() {
|
|
12547
13245
|
"use strict";
|
|
13246
|
+
init_trailing_slashes();
|
|
12548
13247
|
CANVAS_UNSUPPORTED_CODE = "canvas_unsupported";
|
|
12549
13248
|
CANVAS_UNSUPPORTED_TITLE = "Games and canvas apps aren't supported yet";
|
|
12550
13249
|
CANVAS_UNSUPPORTED_BODY = "This app draws its screen on a canvas (like a game), so there are no page elements for Validate.QA to read and test. Support for games and canvas apps is coming.";
|
|
@@ -12669,6 +13368,7 @@ var init_canvas_support = __esm({
|
|
|
12669
13368
|
TOUCH_NONE_RE = /touch-action\s{0,8}:\s{0,8}none/;
|
|
12670
13369
|
CODE_TAGS = /* @__PURE__ */ new Set(["script", "link", "flt-glass-pane", "flutter-view", "flt-scene-host"]);
|
|
12671
13370
|
STATIC_STANDARD_MIN_INTERACTIVE = 3;
|
|
13371
|
+
TRAILING_PUNCTUATION = /[\s,;:.\-–—]/u;
|
|
12672
13372
|
}
|
|
12673
13373
|
});
|
|
12674
13374
|
|
|
@@ -12851,22 +13551,22 @@ function joinChainedLines(code) {
|
|
|
12851
13551
|
const trimmed = lines[i].trimStart();
|
|
12852
13552
|
if (last !== -1 && trimmed.startsWith(".") && !trimmed.startsWith("...")) {
|
|
12853
13553
|
if (!lastStripped) {
|
|
12854
|
-
lines[last] =
|
|
13554
|
+
lines[last] = stripLineComment3(lines[last]).trimEnd();
|
|
12855
13555
|
lastStripped = true;
|
|
12856
13556
|
}
|
|
12857
13557
|
if (lines[last].length <= MAX_LINE_CHARS)
|
|
12858
|
-
lines[last] = `${lines[last]} ${
|
|
13558
|
+
lines[last] = `${lines[last]} ${stripLineComment3(trimmed).trimEnd()}`;
|
|
12859
13559
|
lines[i] = "";
|
|
12860
13560
|
continue;
|
|
12861
13561
|
}
|
|
12862
|
-
if (
|
|
13562
|
+
if (stripLineComment3(lines[i]).trim()) {
|
|
12863
13563
|
last = i;
|
|
12864
13564
|
lastStripped = false;
|
|
12865
13565
|
}
|
|
12866
13566
|
}
|
|
12867
13567
|
return lines.join("\n");
|
|
12868
13568
|
}
|
|
12869
|
-
function
|
|
13569
|
+
function stripLineComment3(rawLine) {
|
|
12870
13570
|
if (rawLine.trimStart().startsWith("//"))
|
|
12871
13571
|
return "";
|
|
12872
13572
|
const at = rawLine.indexOf(" // ");
|
|
@@ -12915,7 +13615,7 @@ function analyzeReadinessPolling(rawCode) {
|
|
|
12915
13615
|
offset += rawLine.length + 1;
|
|
12916
13616
|
if (rawLine.length > MAX_LINE_CHARS)
|
|
12917
13617
|
continue;
|
|
12918
|
-
const line =
|
|
13618
|
+
const line = stripLineComment3(rawLine);
|
|
12919
13619
|
if (!line.trim())
|
|
12920
13620
|
continue;
|
|
12921
13621
|
const literals = literalsOf(line);
|
|
@@ -13027,7 +13727,7 @@ function blankBlockComments2(code) {
|
|
|
13027
13727
|
from = close + 2;
|
|
13028
13728
|
}
|
|
13029
13729
|
}
|
|
13030
|
-
function
|
|
13730
|
+
function stripLineComment4(rawLine) {
|
|
13031
13731
|
if (rawLine.trimStart().startsWith("//"))
|
|
13032
13732
|
return "";
|
|
13033
13733
|
const at = rawLine.indexOf(" // ");
|
|
@@ -13038,7 +13738,7 @@ function logicalLines(code) {
|
|
|
13038
13738
|
for (const raw of code.split("\n")) {
|
|
13039
13739
|
if (raw.length > MAX_LINE_CHARS2)
|
|
13040
13740
|
continue;
|
|
13041
|
-
const line =
|
|
13741
|
+
const line = stripLineComment4(raw).trimEnd();
|
|
13042
13742
|
if (!line.trim())
|
|
13043
13743
|
continue;
|
|
13044
13744
|
const trimmed = line.trimStart();
|
|
@@ -13400,8 +14100,19 @@ function short4(text, max) {
|
|
|
13400
14100
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
13401
14101
|
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
13402
14102
|
}
|
|
14103
|
+
function stripFractionZeros(s) {
|
|
14104
|
+
let end = s.length;
|
|
14105
|
+
while (end > 0 && s[end - 1] === "0")
|
|
14106
|
+
end--;
|
|
14107
|
+
if (end === s.length)
|
|
14108
|
+
return s;
|
|
14109
|
+
const dot = s.lastIndexOf(".");
|
|
14110
|
+
if (dot < 0)
|
|
14111
|
+
return s;
|
|
14112
|
+
return s.slice(0, end === dot + 1 ? dot : end);
|
|
14113
|
+
}
|
|
13403
14114
|
function digitsOf(token) {
|
|
13404
|
-
return token.replace(/[^\d.]/g, "")
|
|
14115
|
+
return stripFractionZeros(token.replace(/[^\d.]/g, "")).replace(/^0+(?=\d)/, "");
|
|
13405
14116
|
}
|
|
13406
14117
|
function computes(line) {
|
|
13407
14118
|
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX").replace(LITERAL_ARITH_RE, "N");
|
|
@@ -13619,7 +14330,7 @@ function findExpectCalls(code) {
|
|
|
13619
14330
|
if (!subj)
|
|
13620
14331
|
continue;
|
|
13621
14332
|
const rest = code.slice(subj.end + 1, subj.end + 1 + 80);
|
|
13622
|
-
const mm = /^\s*((?:\.\s*not)
|
|
14333
|
+
const mm = /^\s*((?:\.\s*not\s*)?\.\s*(\w+))\s{0,20}\(/.exec(rest);
|
|
13623
14334
|
if (!mm)
|
|
13624
14335
|
continue;
|
|
13625
14336
|
const argStart = subj.end + 1 + mm[0].length;
|
|
@@ -15569,6 +16280,28 @@ function startsWithRegexLiteral(text) {
|
|
|
15569
16280
|
const t = text.trimStart();
|
|
15570
16281
|
return t[0] === "/" && t[1] !== "/" && t[1] !== "*" && regexLiteralEnd4(t, 0) !== -1;
|
|
15571
16282
|
}
|
|
16283
|
+
function isBareRegexLiteral(text) {
|
|
16284
|
+
const t = text.trimStart();
|
|
16285
|
+
if (t[0] !== "/" || t[1] === "/" || t[1] === "*")
|
|
16286
|
+
return false;
|
|
16287
|
+
const end = regexLiteralEnd4(t, 0);
|
|
16288
|
+
if (end === -1)
|
|
16289
|
+
return false;
|
|
16290
|
+
let i = end;
|
|
16291
|
+
while (i < t.length && /[a-z]/.test(t[i]))
|
|
16292
|
+
i++;
|
|
16293
|
+
while (i < t.length && /\s/.test(t[i]))
|
|
16294
|
+
i++;
|
|
16295
|
+
return i >= t.length || t[i] === ",";
|
|
16296
|
+
}
|
|
16297
|
+
function regexDeclaredNames(code) {
|
|
16298
|
+
const names = /* @__PURE__ */ new Set();
|
|
16299
|
+
const decl = /\b(?:const|let|var)\s{1,20}([A-Za-z_$][\w$]{0,80})\s{0,20}=\s{0,20}(?:\/(?![/*])|new\s{1,20}RegExp\b)/g;
|
|
16300
|
+
let m;
|
|
16301
|
+
while ((m = decl.exec(code)) !== null)
|
|
16302
|
+
names.add(m[1]);
|
|
16303
|
+
return names;
|
|
16304
|
+
}
|
|
15572
16305
|
function afterFirstArg(args) {
|
|
15573
16306
|
let depth = 0;
|
|
15574
16307
|
let quote = null;
|
|
@@ -15606,6 +16339,7 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15606
16339
|
let examined = 0;
|
|
15607
16340
|
let line = 1;
|
|
15608
16341
|
let lineAt2 = 0;
|
|
16342
|
+
let regexNames;
|
|
15609
16343
|
while ((m = re.exec(code)) !== null && examined++ < MAX_CALLS && out.length < MAX_REGEX_MATCHER_FINDINGS) {
|
|
15610
16344
|
const subj = readBalanced(code, m.index + m[0].length);
|
|
15611
16345
|
if (!subj)
|
|
@@ -15617,10 +16351,18 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15617
16351
|
if (!args)
|
|
15618
16352
|
continue;
|
|
15619
16353
|
const expected = mm[2] === "toHaveJSProperty" ? afterFirstArg(args.text) : args.text;
|
|
15620
|
-
if (!
|
|
15621
|
-
continue;
|
|
15622
|
-
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain" && (startsWithRegexLiteral(subj.text) || /^new\s+RegExp\b/.test(subj.text.trim())))
|
|
16354
|
+
if (!isBareRegexLiteral(expected))
|
|
15623
16355
|
continue;
|
|
16356
|
+
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain") {
|
|
16357
|
+
const subject = subj.text.trim();
|
|
16358
|
+
if (startsWithRegexLiteral(subject) || /^new\s+RegExp\b/.test(subject))
|
|
16359
|
+
continue;
|
|
16360
|
+
if (/^[A-Za-z_$][\w$]{0,80}$/.test(subject)) {
|
|
16361
|
+
regexNames ??= regexDeclaredNames(code);
|
|
16362
|
+
if (regexNames.has(subject))
|
|
16363
|
+
continue;
|
|
16364
|
+
}
|
|
16365
|
+
}
|
|
15624
16366
|
for (let i = code.indexOf("\n", lineAt2); i !== -1 && i < m.index; i = code.indexOf("\n", i + 1)) {
|
|
15625
16367
|
line++;
|
|
15626
16368
|
lineAt2 = i + 1;
|
|
@@ -15630,9 +16372,12 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15630
16372
|
return out;
|
|
15631
16373
|
}
|
|
15632
16374
|
function formatRegexMatcherNote(findings) {
|
|
15633
|
-
const lines = findings.map((f) =>
|
|
16375
|
+
const lines = findings.map((f) => {
|
|
16376
|
+
const negated = f.matcher === "toContain" ? "throws on a string and otherwise always passes (a regex never equals an item), so it checks nothing" : "always passes (a regex never equals the value), so it checks nothing";
|
|
16377
|
+
return `Line ${f.line}: .${f.negated ? "not." : ""}${f.matcher}(\u2026 /regex/ \u2026) ${f.negated ? negated : "can never pass: this matcher compares by equality and a regex never equals a value"}.`;
|
|
16378
|
+
});
|
|
15634
16379
|
return `${lines.join("\n")}
|
|
15635
|
-
A regex only works in toMatch, toHaveText, toContainText, toHaveValue and similar text matchers. For
|
|
16380
|
+
A regex only works in toMatch, toHaveText, toContainText, toHaveValue and similar text matchers. For the \`value\` of an input, textarea or select, use await expect(loc).toHaveValue(/re/). For any other DOM property (or element), poll it so the check still retries: await expect.poll(() => loc.evaluate((n) => n.<prop>)).toMatch(/re/). Never read it once with expect(await loc.evaluate(\u2026)), which sees the value before the page updates it. Or give toHaveJSProperty the exact string (or boolean) the page shows. Keep every other line as-is.`;
|
|
15636
16381
|
}
|
|
15637
16382
|
function lintTestQuality(rawCode, opts = {}) {
|
|
15638
16383
|
if (!rawCode || typeof rawCode !== "string")
|
|
@@ -16381,19 +17126,6 @@ var init_fence_runs = __esm({
|
|
|
16381
17126
|
}
|
|
16382
17127
|
});
|
|
16383
17128
|
|
|
16384
|
-
// ../shared/dist/trailing-slashes.js
|
|
16385
|
-
function stripTrailingSlashes(value) {
|
|
16386
|
-
let end = value.length;
|
|
16387
|
-
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
16388
|
-
end--;
|
|
16389
|
-
return end === value.length ? value : value.slice(0, end);
|
|
16390
|
-
}
|
|
16391
|
-
var init_trailing_slashes = __esm({
|
|
16392
|
-
"../shared/dist/trailing-slashes.js"() {
|
|
16393
|
-
"use strict";
|
|
16394
|
-
}
|
|
16395
|
-
});
|
|
16396
|
-
|
|
16397
17129
|
// ../shared/dist/survey-bug-signature.js
|
|
16398
17130
|
function normalizeWords(text) {
|
|
16399
17131
|
return text.toLowerCase().replace(UUID, " id ").replace(PREFIXED_ID, " id ").replace(HEX_RUN, (run) => /\d/.test(run) ? " id " : run).replace(NUMBER_RUN, " # ").replace(/[^\p{L}\p{N}#]+/gu, " ").replace(/\s+/g, " ").trim();
|
|
@@ -16417,14 +17149,17 @@ function requestSignatures(text) {
|
|
|
16417
17149
|
const statuses = [...text.matchAll(HTTP_STATUS)].map((m) => ({ status: m[1], at: m.index ?? 0, end: (m.index ?? 0) + m[0].length }));
|
|
16418
17150
|
if (statuses.length === 0)
|
|
16419
17151
|
return [];
|
|
16420
|
-
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) =>
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
17152
|
+
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) => {
|
|
17153
|
+
const rawPath = stripTrailingChars(m[2] ?? m[3] ?? "", PATH_TRAILING_PUNCTUATION);
|
|
17154
|
+
return {
|
|
17155
|
+
method: m[1] ?? null,
|
|
17156
|
+
path: normalizeBugPath(rawPath),
|
|
17157
|
+
// Before normalisation, which turns a segment with a digit (favicon-32x32.png) into :id.
|
|
17158
|
+
incidental: isIncidentalAssetPath(rawPath.split(/[?#]/, 1)[0].toLowerCase()),
|
|
17159
|
+
at: m.index ?? 0,
|
|
17160
|
+
end: (m.index ?? 0) + m[0].length
|
|
17161
|
+
};
|
|
17162
|
+
}).filter((p) => p.path.length > 1);
|
|
16428
17163
|
const out = /* @__PURE__ */ new Map();
|
|
16429
17164
|
for (const { status, at, end } of statuses) {
|
|
16430
17165
|
const lead = STATUS_TO_PATH.exec(text.slice(end, end + 40));
|
|
@@ -16534,11 +17269,12 @@ function dedupeSiteWideSuspectedBugs(drafts) {
|
|
|
16534
17269
|
delete plans.suspectedBugs;
|
|
16535
17270
|
}
|
|
16536
17271
|
}
|
|
16537
|
-
var SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_JS_MESSAGES, GENERIC_JS_PREFIXES, JS_ERROR, MESSAGE_CLAUSE_END, HTTP_STATUS, PATH_IN_TEXT, STATUS_TO_PATH, INCIDENTAL_ASSET;
|
|
17272
|
+
var PATH_TRAILING_PUNCTUATION, SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_JS_MESSAGES, GENERIC_JS_PREFIXES, JS_ERROR, MESSAGE_CLAUSE_END, HTTP_STATUS, PATH_IN_TEXT, STATUS_TO_PATH, INCIDENTAL_ASSET;
|
|
16538
17273
|
var init_survey_bug_signature = __esm({
|
|
16539
17274
|
"../shared/dist/survey-bug-signature.js"() {
|
|
16540
17275
|
"use strict";
|
|
16541
17276
|
init_trailing_slashes();
|
|
17277
|
+
PATH_TRAILING_PUNCTUATION = /[.,;:]/;
|
|
16542
17278
|
SIGNATURE_SOURCE_MAX_CHARS = 800;
|
|
16543
17279
|
UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g;
|
|
16544
17280
|
PREFIXED_ID = /\b[a-z]{1,8}[-_]\d+\b/g;
|
|
@@ -17869,7 +18605,7 @@ function pathIdsIn(text) {
|
|
|
17869
18605
|
function findCounterIdPins(code) {
|
|
17870
18606
|
if (code.length > CLOCK_MAX_CODE_CHARS)
|
|
17871
18607
|
return [];
|
|
17872
|
-
const
|
|
18608
|
+
const clean3 = stripLineComments(blankBlockComments3(code));
|
|
17873
18609
|
const fillValues = [];
|
|
17874
18610
|
const candidates = [];
|
|
17875
18611
|
let seenWrite = false;
|
|
@@ -17877,24 +18613,24 @@ function findCounterIdPins(code) {
|
|
|
17877
18613
|
CALL_RE.lastIndex = 0;
|
|
17878
18614
|
let m;
|
|
17879
18615
|
let calls = 0;
|
|
17880
|
-
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(
|
|
18616
|
+
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(clean3)) !== null) {
|
|
17881
18617
|
const name = m[1];
|
|
17882
18618
|
const open = m.index + m[0].length - 1;
|
|
17883
18619
|
if (VALUE_WRITES.has(name)) {
|
|
17884
18620
|
seenWrite = true;
|
|
17885
|
-
const args2 = argsAt(
|
|
18621
|
+
const args2 = argsAt(clean3, open);
|
|
17886
18622
|
if (args2 !== null)
|
|
17887
18623
|
fillValues.push(...staticStrings(args2));
|
|
17888
18624
|
continue;
|
|
17889
18625
|
}
|
|
17890
18626
|
if (createIndex === -1) {
|
|
17891
|
-
if (name === "click" && seenWrite && isCreateClick(
|
|
18627
|
+
if (name === "click" && seenWrite && isCreateClick(clean3, m.index))
|
|
17892
18628
|
createIndex = m.index;
|
|
17893
18629
|
continue;
|
|
17894
18630
|
}
|
|
17895
18631
|
if (name === "click")
|
|
17896
18632
|
continue;
|
|
17897
|
-
const args = argsAt(
|
|
18633
|
+
const args = argsAt(clean3, open);
|
|
17898
18634
|
if (args === null)
|
|
17899
18635
|
continue;
|
|
17900
18636
|
const isUrl = URL_SINKS.has(name);
|
|
@@ -17913,7 +18649,7 @@ function findCounterIdPins(code) {
|
|
|
17913
18649
|
}
|
|
17914
18650
|
if (createIndex === -1)
|
|
17915
18651
|
return [];
|
|
17916
|
-
const before =
|
|
18652
|
+
const before = clean3.slice(0, createIndex);
|
|
17917
18653
|
let pathIdsBefore = null;
|
|
17918
18654
|
const findings = [];
|
|
17919
18655
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -17937,7 +18673,7 @@ function findCounterIdPins(code) {
|
|
|
17937
18673
|
continue;
|
|
17938
18674
|
}
|
|
17939
18675
|
}
|
|
17940
|
-
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(
|
|
18676
|
+
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(clean3, c.index) });
|
|
17941
18677
|
}
|
|
17942
18678
|
return findings;
|
|
17943
18679
|
}
|
|
@@ -18232,7 +18968,7 @@ var init_suspicious_expectation = __esm({
|
|
|
18232
18968
|
NOT_STUCK_RE = /\b(?:not|never|no longer|isn't|doesn't|don't|without)\s+(?:\w+\s+){0,2}?(?:stuck|hang|hangs|hung|freeze|freezes|frozen|spin|spins|spinning)\b/i;
|
|
18233
18969
|
LISTS_STUCK_RE = /\b(?:appears? in (?:the )?[\w ]{0,25}(?:report|list|dashboard|queue)|(?:lists?|monitors?|shows?|reports?) (?:\w+ ){0,2}(?:that|which|whose) (?:are |is )?(?:stuck|hangs?|hung|frozen)|can (?:retry|re-?run) (?:\w+ ){0,2}(?:that (?:are )?)?stuck)\b/i;
|
|
18234
18970
|
STUCK_VETO_RE = new RegExp(`${NOT_STUCK_RE.source}|${LISTS_STUCK_RE.source}`, "i");
|
|
18235
|
-
NOT_SILENT_RE = /\b(?:not|never|\w+n't|instead of|rather than|avoids?|prevents?)\s+(?:\w+\s+){0,1}?(?:fail(?:s|ing|ed)?|ignor\w*)
|
|
18971
|
+
NOT_SILENT_RE = /\b(?:not|never|\w+n't|instead of|rather than|avoids?|prevents?)\s+(?:\w+\s+){0,1}?(?:(?:fail(?:s|ing|ed)?|ignor\w*)\s*)?silent(?:ly)?\b/i;
|
|
18236
18972
|
PENDING_WORD = "(?:sending|loading|saving|searching|checking(?!\\s+(?:account|balance|out|in)\\b)|syncing|refreshing|fetching|validating|processing|submitting|uploading|posting|publishing|creating|updating|deleting|connecting|verifying|signing in|logging in)";
|
|
18237
18973
|
ELLIPSIS = "(?:\\.{3}|\u2026)";
|
|
18238
18974
|
NOT_STAY_RE = /\b(?:not|never|no longer|without|n't|cannot)\s+(?:\w+\s+){0,2}?(?:stay|stays|stayed|remain|remains|remained|leave|leaves|left)\b/i;
|
|
@@ -18388,7 +19124,7 @@ function outcomeNamedByAssertion(outcome, code) {
|
|
|
18388
19124
|
function namedByStatements(outcome, statements) {
|
|
18389
19125
|
const text = outcomeText(outcome);
|
|
18390
19126
|
if (outcome.type === "url") {
|
|
18391
|
-
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => r
|
|
19127
|
+
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => stripTrailingChars(r, ROUTE_TRAILING_PUNCTUATION)).filter((r) => r.length > 1);
|
|
18392
19128
|
return statements.some((stmt) => {
|
|
18393
19129
|
if (!/\.(?:waitForURL|toHaveURL)\s{0,20}\(/.test(stmt))
|
|
18394
19130
|
return false;
|
|
@@ -18560,7 +19296,7 @@ function evaluatePromotionGate(input, checks = PROMOTION_QUALITY_CHECKS) {
|
|
|
18560
19296
|
...suspiciousTagged ? { suspiciousPass: { mode: suspicious, covered: suspiciousCovered, wouldHold: suspiciousHold } } : {}
|
|
18561
19297
|
};
|
|
18562
19298
|
}
|
|
18563
|
-
var SOURCE_RANK, strengthCheck, STRING_CONST, TYPED_VALUE, TYPED_CONSTANT, MAX_STATEMENTS, MAX_STATEMENT_CHARS, LITERAL_OR_IDENTIFIER, MUTATING_ACTION, FEEDBACK_REGION, ONE_SHOT_MESSAGE_REASON, FEEDBACK_REGION_ALL, dynamicAssertionCheck, OUTCOME_KIND_MATCHER, ROUTE_TERM, QUOTED_LITERAL, GENERIC_LITERAL, MAX_OUTCOME_STATEMENTS, MAX_OUTCOMES, MAX_OUTCOME_TEXT_CHARS, expectedOutcomeCheck, testDataCheck, sharedAccountCheck, clockLiteralCheck, readinessPollCheck, knownBugTestCheck, bugClaimContractCheck, suspiciousExpectationCheck, bugCandidateCheck, conventionOutcomesCheck, pendingHook, locatorFragmentCheck, FILTER_STEP, NEXT_ACTION, REDUCTION_PROOF, MAX_FILTER_LINES, MAX_FILTER_LINE_CHARS, filterPositiveOnlyCheck, PROMOTION_QUALITY_CHECKS, PROMOTION_GATE_MAX_CODE_CHARS, NOT_EVALUATED, SUSPICIOUS_PASS_TAG, NOT_CONTENT_MATCHER, CONTENT_PROOF, NAMED_ELEMENT, NEEDS_REVIEW_TAG, count2, RECHECKED_NOTES, EVIDENCE_NOTE_PREFIXES, PENDING_RECHECK_NOTE_PREFIXES, STRENGTH_RANK;
|
|
19299
|
+
var SOURCE_RANK, strengthCheck, STRING_CONST, TYPED_VALUE, TYPED_CONSTANT, MAX_STATEMENTS, MAX_STATEMENT_CHARS, LITERAL_OR_IDENTIFIER, MUTATING_ACTION, FEEDBACK_REGION, ONE_SHOT_MESSAGE_REASON, FEEDBACK_REGION_ALL, dynamicAssertionCheck, OUTCOME_KIND_MATCHER, ROUTE_TERM, ROUTE_TRAILING_PUNCTUATION, QUOTED_LITERAL, GENERIC_LITERAL, MAX_OUTCOME_STATEMENTS, MAX_OUTCOMES, MAX_OUTCOME_TEXT_CHARS, expectedOutcomeCheck, testDataCheck, sharedAccountCheck, clockLiteralCheck, readinessPollCheck, knownBugTestCheck, bugClaimContractCheck, suspiciousExpectationCheck, bugCandidateCheck, conventionOutcomesCheck, pendingHook, locatorFragmentCheck, FILTER_STEP, NEXT_ACTION, REDUCTION_PROOF, MAX_FILTER_LINES, MAX_FILTER_LINE_CHARS, filterPositiveOnlyCheck, PROMOTION_QUALITY_CHECKS, PROMOTION_GATE_MAX_CODE_CHARS, NOT_EVALUATED, SUSPICIOUS_PASS_TAG, NOT_CONTENT_MATCHER, CONTENT_PROOF, NAMED_ELEMENT, NEEDS_REVIEW_TAG, count2, RECHECKED_NOTES, EVIDENCE_NOTE_PREFIXES, PENDING_RECHECK_NOTE_PREFIXES, STRENGTH_RANK;
|
|
18564
19300
|
var init_promotion_quality_gate = __esm({
|
|
18565
19301
|
"../shared/dist/promotion-quality-gate.js"() {
|
|
18566
19302
|
"use strict";
|
|
@@ -18575,11 +19311,12 @@ var init_promotion_quality_gate = __esm({
|
|
|
18575
19311
|
init_run_classification();
|
|
18576
19312
|
init_expected_outcome_coverage();
|
|
18577
19313
|
init_expect_call();
|
|
19314
|
+
init_trailing_slashes();
|
|
18578
19315
|
SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
|
|
18579
19316
|
strengthCheck = {
|
|
18580
19317
|
id: "assertion-strength",
|
|
18581
|
-
run({ code, tags, strengthGate, flagContradictedAdditions }) {
|
|
18582
|
-
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true });
|
|
19318
|
+
run({ code, tags, strengthGate, flagContradictedAdditions, lastActionProof }) {
|
|
19319
|
+
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true, lastActionProof });
|
|
18583
19320
|
if (verdict.severity === "route-bug")
|
|
18584
19321
|
return [{ check: "route-bug" }];
|
|
18585
19322
|
const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
|
|
@@ -18597,7 +19334,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
18597
19334
|
MAX_STATEMENTS = 500;
|
|
18598
19335
|
MAX_STATEMENT_CHARS = 400;
|
|
18599
19336
|
LITERAL_OR_IDENTIFIER = /'(?:[^'\\\n]|\\.){0,500}'|"(?:[^"\\\n]|\\.){0,500}"|`(?:[^`\\]|\\.){0,2000}`|(?<![\w$.])[A-Za-z_$][\w$]{0,60}/g;
|
|
18600
|
-
MUTATING_ACTION = /\.(?:click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|selectOption|setInputFiles|dragTo|clear)\s{0,20}\(|\brequest\s{0,20}\.\s{0,20}(?:post|put|patch|delete|fetch)\s{0,20}\(/;
|
|
19337
|
+
MUTATING_ACTION = /\.(?:click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|dragAndDrop|clear)\s{0,20}\(|\brequest\s{0,20}\.\s{0,20}(?:post|put|patch|delete|fetch)\s{0,20}\(/;
|
|
18601
19338
|
FEEDBACK_REGION = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/i;
|
|
18602
19339
|
ONE_SHOT_MESSAGE_REASON = "one-shot success/error banner text";
|
|
18603
19340
|
FEEDBACK_REGION_ALL = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/gi;
|
|
@@ -18656,6 +19393,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
18656
19393
|
"element-hidden": /\.(?:toBeHidden|not\s{0,20}\.\s{0,20}toBeVisible|not\s{0,20}\.\s{0,20}toBeAttached|not\s{0,20}\.\s{0,20}toContainText)\s{0,20}\(|\.toHaveCount\s{0,20}\(\s{0,20}0\s{0,20}\)/
|
|
18657
19394
|
};
|
|
18658
19395
|
ROUTE_TERM = /\/[A-Za-z0-9_./?&=#-]{1,200}/g;
|
|
19396
|
+
ROUTE_TRAILING_PUNCTUATION = /[.,;:!?)]/;
|
|
18659
19397
|
QUOTED_LITERAL = /'([^'\\\n]{3,200})'|"([^"\\\n]{3,200})"|`([^`\\$\n]{3,200})`/g;
|
|
18660
19398
|
GENERIC_LITERAL = /^(?:true|false|button|link|heading|dialog|alertdialog|article|main|region|status|alert|textbox|combobox|checkbox|radio|tab|tabpanel|option|list|listitem|row|cell|img|navigation|banner|complementary|contentinfo|form|search|menu|menuitem|visible|hidden|attached|detached|domcontentloaded|load|networkidle)$/i;
|
|
18661
19399
|
MAX_OUTCOME_STATEMENTS = 300;
|
|
@@ -18775,8 +19513,8 @@ ${goalText}`);
|
|
|
18775
19513
|
return count3 > 0 ? [{ check: "locator-fragment", detail: String(count3), soft: true }] : [];
|
|
18776
19514
|
}
|
|
18777
19515
|
};
|
|
18778
|
-
FILTER_STEP = /\.(?:getByLabel|getByPlaceholder|getByRole|getByTitle)\s*\([^)\n]{0,200}?\b(?:filter|sort|search|status|delete|remove|dismiss|archive|clear)\b[^)\n]{0,200}\)[^\n]{0,200}\.(?:selectOption|fill|type|pressSequentially|click|check|uncheck|press)\s*\(/i;
|
|
18779
|
-
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|selectOption|setInputFiles|dragTo|clear)\s*\(/;
|
|
19516
|
+
FILTER_STEP = /\.(?:getByLabel|getByPlaceholder|getByRole|getByTitle)\s*\([^)\n]{0,200}?\b(?:filter|sort|search|status|delete|remove|dismiss|archive|clear)\b[^)\n]{0,200}\)[^\n]{0,200}\.(?:selectOption|fill|type|pressSequentially|click|check|uncheck|setChecked|press)\s*\(/i;
|
|
19517
|
+
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|dragAndDrop|clear)\s*\(/;
|
|
18780
19518
|
REDUCTION_PROOF = /\.toHaveCount\s*\(|\.not\s*\.\s*(?:toBeVisible|toBeAttached|toContainText|toHaveText)\s*\(|\.toBeHidden\s*\(|\bShowing\b|\bof \d+\b|\b\d+ (?:results?|rows?|items?|candidates?|entries|matches|records)\b|\bNo (?:[\w'-]+ ){0,3}(?:match|matches|results?|found|left|remain|yet)\b|\bNothing (?:to show|found|matches)\b|\bis empty\b|\btoHaveURL\b/i;
|
|
18781
19519
|
MAX_FILTER_LINES = 2e3;
|
|
18782
19520
|
MAX_FILTER_LINE_CHARS = 600;
|
|
@@ -18891,7 +19629,7 @@ ${goalText}`);
|
|
|
18891
19629
|
});
|
|
18892
19630
|
|
|
18893
19631
|
// ../shared/dist/regex-alternation.js
|
|
18894
|
-
function
|
|
19632
|
+
function closingParens2(source) {
|
|
18895
19633
|
const close = new Int32Array(source.length).fill(-1);
|
|
18896
19634
|
const open = [];
|
|
18897
19635
|
let inClass = false;
|
|
@@ -18916,7 +19654,7 @@ function closingParens(source) {
|
|
|
18916
19654
|
return close;
|
|
18917
19655
|
}
|
|
18918
19656
|
function alternatesAtTop(source) {
|
|
18919
|
-
const close =
|
|
19657
|
+
const close = closingParens2(source);
|
|
18920
19658
|
let start = source.startsWith("^") ? 1 : 0;
|
|
18921
19659
|
let end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
18922
19660
|
while (start < end && source[start] === "(" && close[start] === end - 1) {
|
|
@@ -18965,6 +19703,124 @@ var init_page_evidence = __esm({
|
|
|
18965
19703
|
}
|
|
18966
19704
|
});
|
|
18967
19705
|
|
|
19706
|
+
// ../shared/dist/stated-limits.js
|
|
19707
|
+
function validDate(v) {
|
|
19708
|
+
const [y, m, d] = v.split("-").map(Number);
|
|
19709
|
+
const t = new Date(Date.UTC(y, m - 1, d));
|
|
19710
|
+
return t.getUTCFullYear() === y && t.getUTCMonth() === m - 1 && t.getUTCDate() === d;
|
|
19711
|
+
}
|
|
19712
|
+
function isoFor(type, v) {
|
|
19713
|
+
const re = DATE_RE[type];
|
|
19714
|
+
if (!re || !re.test(v))
|
|
19715
|
+
return false;
|
|
19716
|
+
if (type === "date")
|
|
19717
|
+
return validDate(v);
|
|
19718
|
+
if (type === "datetime-local")
|
|
19719
|
+
return validDate(v.slice(0, 10)) && Number(v.slice(11, 13)) < 24 && Number(v.slice(14, 16)) < 60;
|
|
19720
|
+
if (type === "time")
|
|
19721
|
+
return Number(v.slice(0, 2)) < 24 && Number(v.slice(3, 5)) < 60;
|
|
19722
|
+
if (type === "month")
|
|
19723
|
+
return Number(v.slice(5, 7)) >= 1 && Number(v.slice(5, 7)) <= 12;
|
|
19724
|
+
return Number(v.slice(6, 8)) >= 1 && Number(v.slice(6, 8)) <= 53;
|
|
19725
|
+
}
|
|
19726
|
+
function clean2(raw) {
|
|
19727
|
+
return typeof raw === "string" ? raw.trim() : "";
|
|
19728
|
+
}
|
|
19729
|
+
function statedLimitsFromAttrs(attrs, inputType) {
|
|
19730
|
+
const type = (inputType ?? "").trim().toLowerCase();
|
|
19731
|
+
const limits = [];
|
|
19732
|
+
const add = (k, v) => {
|
|
19733
|
+
limits.push({ k, v });
|
|
19734
|
+
};
|
|
19735
|
+
if (NUMBER_TYPES.has(type)) {
|
|
19736
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
19737
|
+
const v = clean2(attrs[attr]);
|
|
19738
|
+
if (NUMBER_RE.test(v))
|
|
19739
|
+
add(k, v);
|
|
19740
|
+
}
|
|
19741
|
+
const step = clean2(attrs.step);
|
|
19742
|
+
if (NUMBER_RE.test(step) && Number(step) > 0)
|
|
19743
|
+
add("step", step);
|
|
19744
|
+
} else if (type in DATE_RE) {
|
|
19745
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
19746
|
+
const v = clean2(attrs[attr]);
|
|
19747
|
+
if (isoFor(type, v))
|
|
19748
|
+
add(k, v);
|
|
19749
|
+
}
|
|
19750
|
+
} else if (TEXT_TYPES.has(type)) {
|
|
19751
|
+
for (const [attr, k] of [["minlength", "minLength"], ["maxlength", "maxLength"]]) {
|
|
19752
|
+
const v = clean2(attrs[attr]);
|
|
19753
|
+
if (LENGTH_RE.test(v))
|
|
19754
|
+
add(k, String(Number(v)));
|
|
19755
|
+
}
|
|
19756
|
+
const pattern = cleanPattern(clean2(attrs.pattern).slice(0, STATED_PATTERN_MAX));
|
|
19757
|
+
if (pattern)
|
|
19758
|
+
add("pattern", pattern);
|
|
19759
|
+
}
|
|
19760
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
19761
|
+
}
|
|
19762
|
+
function cleanPattern(text) {
|
|
19763
|
+
return text.replace(/[\u0000-\u001f\u007f]/g, "").replace(/[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/g, "");
|
|
19764
|
+
}
|
|
19765
|
+
function readStatedLimits(stored) {
|
|
19766
|
+
if (!stored || typeof stored !== "object" || Array.isArray(stored))
|
|
19767
|
+
return [];
|
|
19768
|
+
const rec = stored;
|
|
19769
|
+
if (rec.v !== STATED_LIMITS_VERSION || !Array.isArray(rec.limits))
|
|
19770
|
+
return [];
|
|
19771
|
+
const out = [];
|
|
19772
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19773
|
+
for (const item of rec.limits.slice(0, MAX_LIMITS * 2)) {
|
|
19774
|
+
if (!item || typeof item !== "object")
|
|
19775
|
+
continue;
|
|
19776
|
+
const { k, v } = item;
|
|
19777
|
+
if (typeof k !== "string" || typeof v !== "string" || !KINDS.includes(k) || seen.has(k))
|
|
19778
|
+
continue;
|
|
19779
|
+
if (v.length === 0 || v.length > STATED_PATTERN_MAX)
|
|
19780
|
+
continue;
|
|
19781
|
+
const text = k === "pattern" ? cleanPattern(v) : v;
|
|
19782
|
+
if (text === "")
|
|
19783
|
+
continue;
|
|
19784
|
+
if (k === "minLength" || k === "maxLength") {
|
|
19785
|
+
if (!LENGTH_RE.test(v))
|
|
19786
|
+
continue;
|
|
19787
|
+
} else if (k === "step") {
|
|
19788
|
+
if (!NUMBER_RE.test(v))
|
|
19789
|
+
continue;
|
|
19790
|
+
} else if (k === "min" || k === "max") {
|
|
19791
|
+
if (!NUMBER_RE.test(v) && !Object.values(DATE_RE).some((re) => re.test(v)))
|
|
19792
|
+
continue;
|
|
19793
|
+
}
|
|
19794
|
+
seen.add(k);
|
|
19795
|
+
out.push({ k, v: text });
|
|
19796
|
+
}
|
|
19797
|
+
return out;
|
|
19798
|
+
}
|
|
19799
|
+
function statedLimitsRecord(limits) {
|
|
19800
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
19801
|
+
}
|
|
19802
|
+
var STATED_LIMITS_VERSION, STATED_PATTERN_MAX, KINDS, MAX_LIMITS, TEXT_TYPES, NUMBER_TYPES, DATE_RE, NUMBER_RE, LENGTH_RE;
|
|
19803
|
+
var init_stated_limits = __esm({
|
|
19804
|
+
"../shared/dist/stated-limits.js"() {
|
|
19805
|
+
"use strict";
|
|
19806
|
+
STATED_LIMITS_VERSION = 1;
|
|
19807
|
+
STATED_PATTERN_MAX = 200;
|
|
19808
|
+
KINDS = ["min", "max", "minLength", "maxLength", "step", "pattern"];
|
|
19809
|
+
MAX_LIMITS = KINDS.length;
|
|
19810
|
+
TEXT_TYPES = /* @__PURE__ */ new Set(["text", "search", "email", "url", "tel", "password", "textarea", ""]);
|
|
19811
|
+
NUMBER_TYPES = /* @__PURE__ */ new Set(["number", "range"]);
|
|
19812
|
+
DATE_RE = {
|
|
19813
|
+
date: /^\d{4}-\d{2}-\d{2}$/,
|
|
19814
|
+
"datetime-local": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/,
|
|
19815
|
+
time: /^\d{2}:\d{2}(?::\d{2})?$/,
|
|
19816
|
+
month: /^\d{4}-\d{2}$/,
|
|
19817
|
+
week: /^\d{4}-W\d{2}$/
|
|
19818
|
+
};
|
|
19819
|
+
NUMBER_RE = /^-?\d{1,15}(?:\.\d{1,10})?$/;
|
|
19820
|
+
LENGTH_RE = /^\d{1,7}$/;
|
|
19821
|
+
}
|
|
19822
|
+
});
|
|
19823
|
+
|
|
18968
19824
|
// ../shared/dist/index.js
|
|
18969
19825
|
var dist_exports = {};
|
|
18970
19826
|
__export(dist_exports, {
|
|
@@ -18972,9 +19828,11 @@ __export(dist_exports, {
|
|
|
18972
19828
|
ACTION_BATCH_MAX_SIZE: () => ACTION_BATCH_MAX_SIZE,
|
|
18973
19829
|
ADDON_DEFINITIONS: () => ADDON_DEFINITIONS,
|
|
18974
19830
|
ADMIN_EMAIL_LIMITS: () => ADMIN_EMAIL_LIMITS,
|
|
19831
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR: () => ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
18975
19832
|
ADMIN_VIEW_DEFAULT_RETURN_TO: () => ADMIN_VIEW_DEFAULT_RETURN_TO,
|
|
18976
19833
|
AGENT_AI_PROVIDER_PREFIXES: () => AGENT_AI_PROVIDER_PREFIXES,
|
|
18977
19834
|
AI_CREDIT_MARGIN: () => AI_CREDIT_MARGIN,
|
|
19835
|
+
ALLOWED_PROVIDER_CHAIN_HOPS: () => ALLOWED_PROVIDER_CHAIN_HOPS,
|
|
18978
19836
|
API_AUTH_HEADERS_ENV_KEY: () => API_AUTH_HEADERS_ENV_KEY,
|
|
18979
19837
|
API_MODEL_CATALOG: () => API_MODEL_CATALOG,
|
|
18980
19838
|
API_MODEL_FIELDS: () => API_MODEL_FIELDS,
|
|
@@ -19014,12 +19872,14 @@ __export(dist_exports, {
|
|
|
19014
19872
|
BUG_TEST_BROKEN_REASON: () => BUG_TEST_BROKEN_REASON,
|
|
19015
19873
|
BUG_TEST_BROKEN_TAG: () => BUG_TEST_BROKEN_TAG,
|
|
19016
19874
|
CACHE_PRICE_PER_M: () => CACHE_PRICE_PER_M,
|
|
19875
|
+
CANCELLED_REASON_PREFIXES: () => CANCELLED_REASON_PREFIXES,
|
|
19017
19876
|
CANVAS_UNSUPPORTED_BODY: () => CANVAS_UNSUPPORTED_BODY,
|
|
19018
19877
|
CANVAS_UNSUPPORTED_CODE: () => CANVAS_UNSUPPORTED_CODE,
|
|
19019
19878
|
CANVAS_UNSUPPORTED_NOT_CHARGED: () => CANVAS_UNSUPPORTED_NOT_CHARGED,
|
|
19020
19879
|
CANVAS_UNSUPPORTED_OVERRIDE_HINT: () => CANVAS_UNSUPPORTED_OVERRIDE_HINT,
|
|
19021
19880
|
CANVAS_UNSUPPORTED_TITLE: () => CANVAS_UNSUPPORTED_TITLE,
|
|
19022
19881
|
CAPTURE_JSON_STRUCTURE_LIMITS: () => CAPTURE_JSON_STRUCTURE_LIMITS,
|
|
19882
|
+
CHAIN_CANCELLED_RUN_ERROR: () => CHAIN_CANCELLED_RUN_ERROR,
|
|
19023
19883
|
CHAT_FAILOVER_KEY: () => CHAT_FAILOVER_KEY,
|
|
19024
19884
|
CLAUDE_CLI_DEFAULT_EFFORT: () => CLAUDE_CLI_DEFAULT_EFFORT,
|
|
19025
19885
|
CLAUDE_CLI_DEFAULT_MODEL: () => CLAUDE_CLI_DEFAULT_MODEL,
|
|
@@ -19056,6 +19916,7 @@ __export(dist_exports, {
|
|
|
19056
19916
|
DEFAULT_GEMINI_SCREEN_MODEL: () => DEFAULT_GEMINI_SCREEN_MODEL,
|
|
19057
19917
|
DEFAULT_JSON_STRUCTURE_LIMITS: () => DEFAULT_JSON_STRUCTURE_LIMITS,
|
|
19058
19918
|
DEFAULT_PLATFORM_DB_POOL_SIZE: () => DEFAULT_PLATFORM_DB_POOL_SIZE,
|
|
19919
|
+
DEFAULT_PROVIDER_ACCOUNT_ID: () => DEFAULT_PROVIDER_ACCOUNT_ID,
|
|
19059
19920
|
DEFAULT_SHARED_DB_POOL_SIZE: () => DEFAULT_SHARED_DB_POOL_SIZE,
|
|
19060
19921
|
DEFAULT_STT_MODEL: () => DEFAULT_STT_MODEL,
|
|
19061
19922
|
DEFAULT_STT_MODEL_BY_PROVIDER: () => DEFAULT_STT_MODEL_BY_PROVIDER,
|
|
@@ -19072,6 +19933,7 @@ __export(dist_exports, {
|
|
|
19072
19933
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES: () => ENVIRONMENTAL_ERROR_STORED_PREFIXES,
|
|
19073
19934
|
EVIDENCE_NOTE_PREFIXES: () => EVIDENCE_NOTE_PREFIXES,
|
|
19074
19935
|
EXPECT_CALL_RE: () => EXPECT_CALL_RE,
|
|
19936
|
+
FEATURE_ROW_RUN_WINDOW: () => FEATURE_ROW_RUN_WINDOW,
|
|
19075
19937
|
FLOW_PHASE_LABELS: () => FLOW_PHASE_LABELS,
|
|
19076
19938
|
FLOW_PHASE_TYPES: () => FLOW_PHASE_TYPES,
|
|
19077
19939
|
FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
|
|
@@ -19139,6 +20001,8 @@ __export(dist_exports, {
|
|
|
19139
20001
|
MAX_ORG_NAME_LENGTH: () => MAX_ORG_NAME_LENGTH,
|
|
19140
20002
|
MAX_PASSWORD_BYTES: () => MAX_PASSWORD_BYTES,
|
|
19141
20003
|
MAX_PLAYWRIGHT_CODE_LENGTH: () => MAX_PLAYWRIGHT_CODE_LENGTH,
|
|
20004
|
+
MAX_PROVIDER_ACCOUNTS: () => MAX_PROVIDER_ACCOUNTS,
|
|
20005
|
+
MAX_PROVIDER_ACCOUNT_MODELS: () => MAX_PROVIDER_ACCOUNT_MODELS,
|
|
19142
20006
|
MAX_SURVEY_ENTRY_URLS: () => MAX_SURVEY_ENTRY_URLS,
|
|
19143
20007
|
MAX_SURVEY_ENTRY_URL_LENGTH: () => MAX_SURVEY_ENTRY_URL_LENGTH,
|
|
19144
20008
|
MCP_ARMY_LIMITS: () => MCP_ARMY_LIMITS,
|
|
@@ -19174,7 +20038,7 @@ __export(dist_exports, {
|
|
|
19174
20038
|
MUSE_ENGINE_DEFAULT_MODEL: () => MUSE_ENGINE_DEFAULT_MODEL,
|
|
19175
20039
|
MUSE_ENGINE_MODELS: () => MUSE_ENGINE_MODELS,
|
|
19176
20040
|
NOREPLY_EMAIL: () => NOREPLY_EMAIL,
|
|
19177
|
-
|
|
20041
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS: () => OPENCODE_GO_DEEPSEEK_GLM_MODELS,
|
|
19178
20042
|
OPENCODE_GO_MODEL_PATTERN: () => OPENCODE_GO_MODEL_PATTERN,
|
|
19179
20043
|
OPENCODE_GO_PREFIX: () => OPENCODE_GO_PREFIX,
|
|
19180
20044
|
OPENROUTER_MAX_CALL_COST_USD: () => OPENROUTER_MAX_CALL_COST_USD,
|
|
@@ -19194,10 +20058,12 @@ __export(dist_exports, {
|
|
|
19194
20058
|
PLAN_FEATURES: () => PLAN_FEATURES,
|
|
19195
20059
|
PLAN_FEATURE_LOCKED_CODE: () => PLAN_FEATURE_LOCKED_CODE,
|
|
19196
20060
|
PLAN_ORDER: () => PLAN_ORDER,
|
|
20061
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR: () => PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
19197
20062
|
PLATFORM_ADMIN_EMAIL: () => PLATFORM_ADMIN_EMAIL,
|
|
19198
20063
|
PLATFORM_DEFAULT_PROVIDER: () => PLATFORM_DEFAULT_PROVIDER,
|
|
19199
20064
|
PLATFORM_PLAN_BILLING: () => PLATFORM_PLAN_BILLING,
|
|
19200
20065
|
PLATFORM_SERVER_APPLICATION_NAME: () => PLATFORM_SERVER_APPLICATION_NAME,
|
|
20066
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR: () => PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
19201
20067
|
POST_SPECIAL_TRIAL_DAYS: () => POST_SPECIAL_TRIAL_DAYS,
|
|
19202
20068
|
PRESET_DIRECT_FALLBACK: () => PRESET_DIRECT_FALLBACK,
|
|
19203
20069
|
PRODUCTION_READ_ONLY_GUARD_TEMPLATE: () => PRODUCTION_READ_ONLY_GUARD_TEMPLATE,
|
|
@@ -19209,8 +20075,12 @@ __export(dist_exports, {
|
|
|
19209
20075
|
PROJECT_OVERRIDE_FIELDS: () => PROJECT_OVERRIDE_FIELDS,
|
|
19210
20076
|
PROMOTION_GATE_MAX_CODE_CHARS: () => PROMOTION_GATE_MAX_CODE_CHARS,
|
|
19211
20077
|
PROMOTION_QUALITY_CHECKS: () => PROMOTION_QUALITY_CHECKS,
|
|
20078
|
+
PROVIDER_ACCOUNT_ID_PATTERN: () => PROVIDER_ACCOUNT_ID_PATTERN,
|
|
20079
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN: () => PROVIDER_ACCOUNT_MODEL_PATTERN,
|
|
19212
20080
|
PROVIDER_CHAINS: () => PROVIDER_CHAINS,
|
|
20081
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS: () => PROVIDER_CHAINS_SETTING_MAX_CHARS,
|
|
19213
20082
|
PROVIDER_CHAIN_LEADS: () => PROVIDER_CHAIN_LEADS,
|
|
20083
|
+
PROVIDER_CHAIN_MAX_ENTRIES: () => PROVIDER_CHAIN_MAX_ENTRIES,
|
|
19214
20084
|
PROVIDER_HOST_NOT_OFFERED: () => PROVIDER_HOST_NOT_OFFERED,
|
|
19215
20085
|
PUBLIC_PLANS: () => PUBLIC_PLANS,
|
|
19216
20086
|
QUARANTINE_CLOSE_TAGS: () => QUARANTINE_CLOSE_TAGS,
|
|
@@ -19218,10 +20088,12 @@ __export(dist_exports, {
|
|
|
19218
20088
|
READ_ONLY_TAGS: () => READ_ONLY_TAGS,
|
|
19219
20089
|
RECHECKED_NOTES: () => RECHECKED_NOTES,
|
|
19220
20090
|
RECORDING_VALUE_PLACEHOLDERS: () => RECORDING_VALUE_PLACEHOLDERS,
|
|
20091
|
+
RENDER_IDENTITY_MAX_LENGTH: () => RENDER_IDENTITY_MAX_LENGTH,
|
|
19221
20092
|
REPOSITORY_CLIS: () => REPOSITORY_CLIS,
|
|
19222
20093
|
RESERVED_PROJECT_KEYS: () => RESERVED_PROJECT_KEYS,
|
|
19223
20094
|
RESULT_STRUCTURE_TOO_COSTLY_CODE: () => RESULT_STRUCTURE_TOO_COSTLY_CODE,
|
|
19224
20095
|
RETRIED_ATTEMPTS_KEY: () => RETRIED_ATTEMPTS_KEY,
|
|
20096
|
+
RETRY_HELD_RUN_ERROR: () => RETRY_HELD_RUN_ERROR,
|
|
19225
20097
|
RUNNER_INTERRUPT_ERROR_PREFIX: () => RUNNER_INTERRUPT_ERROR_PREFIX,
|
|
19226
20098
|
RUN_INTERRUPTED_ERROR_PREFIXES: () => RUN_INTERRUPTED_ERROR_PREFIXES,
|
|
19227
20099
|
RUN_INTERRUPTION_NOT_RETRIED_MARKERS: () => RUN_INTERRUPTION_NOT_RETRIED_MARKERS,
|
|
@@ -19234,6 +20106,8 @@ __export(dist_exports, {
|
|
|
19234
20106
|
SHARED_SERVER_APPLICATION_NAME: () => SHARED_SERVER_APPLICATION_NAME,
|
|
19235
20107
|
SPEND_SOURCE_KEY: () => SPEND_SOURCE_KEY,
|
|
19236
20108
|
SPEND_SOURCE_SERVER: () => SPEND_SOURCE_SERVER,
|
|
20109
|
+
STATED_LIMITS_VERSION: () => STATED_LIMITS_VERSION,
|
|
20110
|
+
STATED_PATTERN_MAX: () => STATED_PATTERN_MAX,
|
|
19237
20111
|
STATIC_STANDARD_MIN_INTERACTIVE: () => STATIC_STANDARD_MIN_INTERACTIVE,
|
|
19238
20112
|
STT_MODEL_OPTIONS: () => STT_MODEL_OPTIONS,
|
|
19239
20113
|
SUCCESS_NOTICE_TEXT: () => SUCCESS_NOTICE_TEXT,
|
|
@@ -19263,14 +20137,20 @@ __export(dist_exports, {
|
|
|
19263
20137
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
19264
20138
|
UNEXPECTED_PASS_ERROR_PREFIX: () => UNEXPECTED_PASS_ERROR_PREFIX,
|
|
19265
20139
|
USER_CANCELLED_RUN_ERROR: () => USER_CANCELLED_RUN_ERROR,
|
|
20140
|
+
VISUAL_MASK_SELECTORS_MAX: () => VISUAL_MASK_SELECTORS_MAX,
|
|
20141
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN: () => VISUAL_MASK_SELECTOR_FORBIDDEN,
|
|
20142
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH: () => VISUAL_MASK_SELECTOR_MAX_LENGTH,
|
|
20143
|
+
VISUAL_V1_IDENTITY: () => VISUAL_V1_IDENTITY,
|
|
19266
20144
|
VOICE_PREVIEW_SAMPLE: () => VOICE_PREVIEW_SAMPLE,
|
|
19267
20145
|
WEB_PROXY_CHAIN_HEADER: () => WEB_PROXY_CHAIN_HEADER,
|
|
19268
20146
|
WITHHELD_CREDENTIAL_TEXT: () => WITHHELD_CREDENTIAL_TEXT,
|
|
19269
20147
|
ZAI_MODEL_PATTERN: () => ZAI_MODEL_PATTERN,
|
|
19270
20148
|
ZAI_PREFIX: () => ZAI_PREFIX,
|
|
20149
|
+
accountServesModel: () => accountServesModel,
|
|
19271
20150
|
accumulateStatements: () => accumulateStatements,
|
|
19272
20151
|
adoptBrokerFailover: () => adoptBrokerFailover,
|
|
19273
20152
|
aiCostToCreditCents: () => aiCostToCreditCents,
|
|
20153
|
+
allowedProviderChainHosts: () => allowedProviderChainHosts,
|
|
19274
20154
|
alternatesAtTop: () => alternatesAtTop,
|
|
19275
20155
|
analyzeDerivedValues: () => analyzeDerivedValues,
|
|
19276
20156
|
analyzeMobileSelectorQuality: () => analyzeMobileSelectorQuality,
|
|
@@ -19283,6 +20163,7 @@ __export(dist_exports, {
|
|
|
19283
20163
|
analyzeUnreachedUrlWaits: () => analyzeUnreachedUrlWaits,
|
|
19284
20164
|
analyzeUrlWaits: () => analyzeUrlWaits,
|
|
19285
20165
|
analyzeWriteResponse: () => analyzeWriteResponse,
|
|
20166
|
+
androidResourceOwners: () => androidResourceOwners,
|
|
19286
20167
|
apiModelCardsFromConfig: () => apiModelCardsFromConfig,
|
|
19287
20168
|
apiModelsForProvider: () => apiModelsForProvider,
|
|
19288
20169
|
apiProviderModelLabel: () => apiProviderModelLabel,
|
|
@@ -19293,6 +20174,7 @@ __export(dist_exports, {
|
|
|
19293
20174
|
applyLaunchSpecialPlan: () => applyLaunchSpecialPlan,
|
|
19294
20175
|
asPlainExpect: () => asPlainExpect,
|
|
19295
20176
|
assertionOnlyCode: () => assertionOnlyCode,
|
|
20177
|
+
assertionStrengthHoistedReadsOn: () => assertionStrengthHoistedReadsOn,
|
|
19296
20178
|
assertionsReadVisibleContent: () => assertionsReadVisibleContent,
|
|
19297
20179
|
assessCodeOutcomeCoverage: () => assessCodeOutcomeCoverage,
|
|
19298
20180
|
assessTitleCoverage: () => assessTitleCoverage,
|
|
@@ -19376,6 +20258,7 @@ __export(dist_exports, {
|
|
|
19376
20258
|
deepgramSpeak: () => deepgramSpeak,
|
|
19377
20259
|
deepgramTranscribe: () => deepgramTranscribe,
|
|
19378
20260
|
defaultConfirmModel: () => defaultConfirmModel,
|
|
20261
|
+
defaultProviderChainEntries: () => defaultProviderChainEntries,
|
|
19379
20262
|
defaultScreenModel: () => defaultScreenModel,
|
|
19380
20263
|
defaultVoiceForTtsModel: () => defaultVoiceForTtsModel,
|
|
19381
20264
|
deriveAuthPlan: () => deriveAuthPlan,
|
|
@@ -19418,6 +20301,7 @@ __export(dist_exports, {
|
|
|
19418
20301
|
extractOutcomeSearchTerms: () => extractOutcomeSearchTerms,
|
|
19419
20302
|
featureForAiCallType: () => featureForAiCallType,
|
|
19420
20303
|
featureForMcpTool: () => featureForMcpTool,
|
|
20304
|
+
featureRowRunStatus: () => featureRowRunStatus,
|
|
19421
20305
|
findBracedClause: () => findBracedClause,
|
|
19422
20306
|
findCounterIdPins: () => findCounterIdPins,
|
|
19423
20307
|
findCredentialTextLeftover: () => findCredentialTextLeftover,
|
|
@@ -19466,6 +20350,7 @@ __export(dist_exports, {
|
|
|
19466
20350
|
getPlanChangeType: () => getPlanChangeType,
|
|
19467
20351
|
getPlanDefinition: () => getPlanDefinition,
|
|
19468
20352
|
getPlanLabel: () => getPlanLabel,
|
|
20353
|
+
getProviderChainOverrides: () => getProviderChainOverrides,
|
|
19469
20354
|
getTrialDaysRemaining: () => getTrialDaysRemaining,
|
|
19470
20355
|
googleBrokerNavigationUrl: () => googleBrokerNavigationUrl,
|
|
19471
20356
|
googleBrokerUnavailableLine: () => googleBrokerUnavailableLine,
|
|
@@ -19479,10 +20364,10 @@ __export(dist_exports, {
|
|
|
19479
20364
|
hasEncodedRequestBody: () => hasEncodedRequestBody,
|
|
19480
20365
|
hasEngineSpecParts: () => hasEngineSpecParts,
|
|
19481
20366
|
hasOnlyConstantAssertions: () => hasOnlyConstantAssertions,
|
|
19482
|
-
hasOpenCodeGo2Prefix: () => hasOpenCodeGo2Prefix,
|
|
19483
20367
|
hasOpenCodeGoPrefix: () => hasOpenCodeGoPrefix,
|
|
19484
20368
|
hasOpenRouterPrefix: () => hasOpenRouterPrefix,
|
|
19485
20369
|
hasPlatformLocator: () => hasPlatformLocator,
|
|
20370
|
+
hasProviderChainLeadsByDefault: () => hasProviderChainLeadsByDefault,
|
|
19486
20371
|
hasReadOnlyMarker: () => hasReadOnlyMarker,
|
|
19487
20372
|
hasSurveyNotes: () => hasSurveyNotes,
|
|
19488
20373
|
hasTestFailContract: () => hasTestFailContract,
|
|
@@ -19508,8 +20393,11 @@ __export(dist_exports, {
|
|
|
19508
20393
|
isAuthTokenName: () => isAuthTokenName,
|
|
19509
20394
|
isBlockedEnvVar: () => isBlockedEnvVar,
|
|
19510
20395
|
isBrowserCliEngine: () => isBrowserCliEngine,
|
|
20396
|
+
isBrowserVersion: () => isBrowserVersion,
|
|
19511
20397
|
isBugTestBrokenError: () => isBugTestBrokenError,
|
|
20398
|
+
isCancelledReason: () => isCancelledReason,
|
|
19512
20399
|
isCanvasUnsupportedMessage: () => isCanvasUnsupportedMessage,
|
|
20400
|
+
isChainablePrimary: () => isChainablePrimary,
|
|
19513
20401
|
isCliEngineModelId: () => isCliEngineModelId,
|
|
19514
20402
|
isCliEngineSpec: () => isCliEngineSpec,
|
|
19515
20403
|
isCodeFactNote: () => isCodeFactNote,
|
|
@@ -19533,6 +20421,7 @@ __export(dist_exports, {
|
|
|
19533
20421
|
isIdentityMobileXpath: () => isIdentityMobileXpath,
|
|
19534
20422
|
isIdentityProviderSurface: () => isIdentityProviderSurface,
|
|
19535
20423
|
isIncidentalAssetPath: () => isIncidentalAssetPath,
|
|
20424
|
+
isIntentionalNegativeAuthTest: () => isIntentionalNegativeAuthTest,
|
|
19536
20425
|
isIpOrLocalhost: () => isIpOrLocalhost,
|
|
19537
20426
|
isKnownPageType: () => isKnownPageType,
|
|
19538
20427
|
isLaunchSpecialActive: () => isLaunchSpecialActive,
|
|
@@ -19560,6 +20449,7 @@ __export(dist_exports, {
|
|
|
19560
20449
|
isRunInterruptedError: () => isRunInterruptedError,
|
|
19561
20450
|
isRunnableStep: () => isRunnableStep,
|
|
19562
20451
|
isSafeDeepLink: () => isSafeDeepLink,
|
|
20452
|
+
isSafeMaskSelector: () => isSafeMaskSelector,
|
|
19563
20453
|
isSameRegistrableDomainHost: () => isSameRegistrableDomainHost,
|
|
19564
20454
|
isSelectableApiModel: () => isSelectableApiModel,
|
|
19565
20455
|
isSelfServePlan: () => isSelfServePlan,
|
|
@@ -19623,6 +20513,7 @@ __export(dist_exports, {
|
|
|
19623
20513
|
normalizeFinishReason: () => normalizeFinishReason,
|
|
19624
20514
|
normalizeNoteText: () => normalizeNoteText,
|
|
19625
20515
|
normalizePageType: () => normalizePageType,
|
|
20516
|
+
normalizeProviderAccountModels: () => normalizeProviderAccountModels,
|
|
19626
20517
|
normalizeTtsModel: () => normalizeTtsModel,
|
|
19627
20518
|
normalizeTtsVoiceId: () => normalizeTtsVoiceId,
|
|
19628
20519
|
noteChatFailover: () => noteChatFailover,
|
|
@@ -19647,13 +20538,18 @@ __export(dist_exports, {
|
|
|
19647
20538
|
parseGeminiModelsPayload: () => parseGeminiModelsPayload,
|
|
19648
20539
|
parseGoogleAuthorizeUrl: () => parseGoogleAuthorizeUrl,
|
|
19649
20540
|
parseGoogleGisRequestUrl: () => parseGoogleGisRequestUrl,
|
|
20541
|
+
parseLastActionProofMode: () => parseLastActionProofMode,
|
|
19650
20542
|
parseLimitParam: () => parseLimitParam,
|
|
19651
20543
|
parseOffsetParam: () => parseOffsetParam,
|
|
19652
20544
|
parsePageParam: () => parsePageParam,
|
|
19653
20545
|
parsePgIntSetting: () => parsePgIntSetting,
|
|
19654
20546
|
parseProjectEngineOverrides: () => parseProjectEngineOverrides,
|
|
19655
20547
|
parsePromotionGateMode: () => parsePromotionGateMode,
|
|
20548
|
+
parseProviderAccountLists: () => parseProviderAccountLists,
|
|
20549
|
+
parseProviderChainOverrides: () => parseProviderChainOverrides,
|
|
19656
20550
|
parseRecheckClearMode: () => parseRecheckClearMode,
|
|
20551
|
+
parseRenderIdentity: () => parseRenderIdentity,
|
|
20552
|
+
parseStoredProviderChainOverrides: () => parseStoredProviderChainOverrides,
|
|
19657
20553
|
parseSurveyEntryUrls: () => parseSurveyEntryUrls,
|
|
19658
20554
|
parseSuspiciousPassMode: () => parseSuspiciousPassMode,
|
|
19659
20555
|
parseTaskModelUpdate: () => parseTaskModelUpdate,
|
|
@@ -19684,7 +20580,9 @@ __export(dist_exports, {
|
|
|
19684
20580
|
projectAppHosts: () => projectAppHosts,
|
|
19685
20581
|
providerChainFor: () => providerChainFor,
|
|
19686
20582
|
providerChainHostOf: () => providerChainHostOf,
|
|
20583
|
+
providerChainHostProvider: () => providerChainHostProvider,
|
|
19687
20584
|
providerChainLeadsFor: () => providerChainLeadsFor,
|
|
20585
|
+
providerChainModelKey: () => providerChainModelKey,
|
|
19688
20586
|
providerChainPrimariesForHop: () => providerChainPrimariesForHop,
|
|
19689
20587
|
providerHostPlan: () => providerHostPlan,
|
|
19690
20588
|
readBalanced: () => readBalanced,
|
|
@@ -19694,6 +20592,7 @@ __export(dist_exports, {
|
|
|
19694
20592
|
readEnabledEngines: () => readEnabledEngines,
|
|
19695
20593
|
readProjectEngineOverrides: () => readProjectEngineOverrides,
|
|
19696
20594
|
readRetriedAttempts: () => readRetriedAttempts,
|
|
20595
|
+
readStatedLimits: () => readStatedLimits,
|
|
19697
20596
|
readStaticPageCanvasSignals: () => readStaticPageCanvasSignals,
|
|
19698
20597
|
readSurveyEntryUrls: () => readSurveyEntryUrls,
|
|
19699
20598
|
readSurveyNotes: () => readSurveyNotes,
|
|
@@ -19706,6 +20605,7 @@ __export(dist_exports, {
|
|
|
19706
20605
|
regexLiteralEnd: () => regexLiteralEnd2,
|
|
19707
20606
|
regexOpensAfter: () => regexOpensAfter,
|
|
19708
20607
|
registrableDomain: () => registrableDomain,
|
|
20608
|
+
renderIdentity: () => renderIdentity,
|
|
19709
20609
|
renderSurveyNotesForPrompt: () => renderSurveyNotesForPrompt,
|
|
19710
20610
|
repairPageType: () => repairPageType,
|
|
19711
20611
|
replaceBlockComments: () => replaceBlockComments,
|
|
@@ -19753,11 +20653,14 @@ __export(dist_exports, {
|
|
|
19753
20653
|
selectorCandidatesForStep: () => selectorCandidatesForStep,
|
|
19754
20654
|
selectorForValue: () => selectorForValue,
|
|
19755
20655
|
setAgenticCliRuntime: () => setAgenticCliRuntime,
|
|
20656
|
+
setProviderChainOverrides: () => setProviderChainOverrides,
|
|
19756
20657
|
signupPlanFor: () => signupPlanFor,
|
|
19757
20658
|
simplifyMobileWanderingInPlace: () => simplifyMobileWanderingInPlace,
|
|
19758
20659
|
siteOf: () => siteOf,
|
|
19759
20660
|
specItemsFromTestPlans: () => specItemsFromTestPlans,
|
|
19760
20661
|
splitAnswerLines: () => splitAnswerLines,
|
|
20662
|
+
statedLimitsFromAttrs: () => statedLimitsFromAttrs,
|
|
20663
|
+
statedLimitsRecord: () => statedLimitsRecord,
|
|
19761
20664
|
stepAppliesToPlatform: () => stepAppliesToPlatform,
|
|
19762
20665
|
stepConsoleLines: () => stepConsoleLines,
|
|
19763
20666
|
stepIsDivergentForPlatform: () => stepIsDivergentForPlatform,
|
|
@@ -19769,7 +20672,10 @@ __export(dist_exports, {
|
|
|
19769
20672
|
stripCodeFactPrefix: () => stripCodeFactPrefix,
|
|
19770
20673
|
stripCoverageComments: () => stripCoverageComments,
|
|
19771
20674
|
stripEnvironmentalPrefix: () => stripEnvironmentalPrefix,
|
|
20675
|
+
stripFractionZeros: () => stripFractionZeros,
|
|
20676
|
+
stripLineComment: () => stripLineComment,
|
|
19772
20677
|
stripLoginScaffolding: () => stripLoginScaffolding,
|
|
20678
|
+
stripTrailingChars: () => stripTrailingChars,
|
|
19773
20679
|
stripTrailingSlashes: () => stripTrailingSlashes,
|
|
19774
20680
|
strongerNeedsReviewSource: () => strongerNeedsReviewSource,
|
|
19775
20681
|
sttModelsForProvider: () => sttModelsForProvider,
|
|
@@ -19787,10 +20693,14 @@ __export(dist_exports, {
|
|
|
19787
20693
|
ttsFallbackModel: () => ttsFallbackModel,
|
|
19788
20694
|
ttsProviderForModel: () => ttsProviderForModel,
|
|
19789
20695
|
unexpectedPassError: () => unexpectedPassError,
|
|
20696
|
+
v1RenderIdentity: () => v1RenderIdentity,
|
|
19790
20697
|
validateAppMapDocument: () => validateAppMapDocument,
|
|
19791
20698
|
validateAssertionStrength: () => validateAssertionStrength,
|
|
19792
20699
|
validateEngineSpec: () => validateEngineSpec,
|
|
20700
|
+
validateProviderChainEntries: () => validateProviderChainEntries,
|
|
20701
|
+
validateProviderChainsSetting: () => validateProviderChainsSetting,
|
|
19793
20702
|
validateTaskModelId: () => validateTaskModelId,
|
|
20703
|
+
visualBaselinesEnabled: () => visualBaselinesEnabled,
|
|
19794
20704
|
visualProDailyBudget: () => visualProDailyBudget,
|
|
19795
20705
|
voiceMatchesTtsModel: () => voiceMatchesTtsModel,
|
|
19796
20706
|
voicesForTtsModel: () => voicesForTtsModel,
|
|
@@ -19853,11 +20763,14 @@ var init_dist = __esm({
|
|
|
19853
20763
|
init_deepgram_voices();
|
|
19854
20764
|
init_feature_flags();
|
|
19855
20765
|
init_env_flags();
|
|
20766
|
+
init_visual_compare_limits();
|
|
20767
|
+
init_visual_baseline_identity();
|
|
19856
20768
|
init_analytics_url();
|
|
19857
20769
|
init_agentic_cli_runtime();
|
|
19858
20770
|
init_api_model_catalog();
|
|
19859
20771
|
init_engine_spec();
|
|
19860
20772
|
init_provider_chains();
|
|
20773
|
+
init_provider_accounts();
|
|
19861
20774
|
init_project_engine_overrides();
|
|
19862
20775
|
init_ai_profiles();
|
|
19863
20776
|
init_openrouter_usage();
|
|
@@ -19899,6 +20812,7 @@ var init_dist = __esm({
|
|
|
19899
20812
|
init_regex_alternation();
|
|
19900
20813
|
init_page_evidence();
|
|
19901
20814
|
init_trailing_slashes();
|
|
20815
|
+
init_stated_limits();
|
|
19902
20816
|
}
|
|
19903
20817
|
});
|
|
19904
20818
|
|
|
@@ -19919,6 +20833,7 @@ var require_survey_network_guard = __commonJS({
|
|
|
19919
20833
|
exports2.isTokenRefreshWrite = isTokenRefreshWrite;
|
|
19920
20834
|
exports2.isSignInPathWrite = isSignInPathWrite;
|
|
19921
20835
|
exports2.graphqlUrlCarriesQuery = graphqlUrlCarriesQuery;
|
|
20836
|
+
exports2.graphqlUrlQueriesAreReads = graphqlUrlQueriesAreReads;
|
|
19922
20837
|
exports2.graphqlGetMayWrite = graphqlGetMayWrite;
|
|
19923
20838
|
exports2.writeShapedGet = writeShapedGet;
|
|
19924
20839
|
exports2.decideSurveyRequest = decideSurveyRequest;
|
|
@@ -20477,6 +21392,9 @@ var require_survey_network_guard = __commonJS({
|
|
|
20477
21392
|
function graphqlUrlCarriesQuery(params) {
|
|
20478
21393
|
return params.has("query");
|
|
20479
21394
|
}
|
|
21395
|
+
function graphqlUrlQueriesAreReads(params) {
|
|
21396
|
+
return params.getAll("query").every((doc) => doc.trim() !== "" && graphqlDocumentIsQueryOnly(doc));
|
|
21397
|
+
}
|
|
20480
21398
|
function graphqlGetMayWrite(url, body) {
|
|
20481
21399
|
const docs = url.searchParams.getAll("query");
|
|
20482
21400
|
return docs.length > 0 && (typeof body === "string" && body.length > 0 || docs.some((doc) => !graphqlDocumentIsQueryOnly(doc)));
|
|
@@ -20720,7 +21638,7 @@ var require_survey_network_guard = __commonJS({
|
|
|
20720
21638
|
return { action: "allow", rule: "extra-pattern", reason: extra.reason, record };
|
|
20721
21639
|
if (graphqlGet)
|
|
20722
21640
|
return { action: "block", rule: "app-write", record };
|
|
20723
|
-
if (method === "POST" && isGraphqlEndpoint(url, s) &&
|
|
21641
|
+
if (method === "POST" && isGraphqlEndpoint(url, s) && graphqlUrlQueriesAreReads(url.searchParams) && isGraphqlQueryOnly(req.postData))
|
|
20724
21642
|
return { action: "allow", rule: "graphql-query", record };
|
|
20725
21643
|
const passive = s.lastNavigationAt > 0 && (s.lastActionAt === 0 || s.lastNavigationAt >= s.lastActionAt) && s.now - s.lastNavigationAt <= s.passiveWindowMs;
|
|
20726
21644
|
const signature = learnableSignature(req, url, record, s);
|
|
@@ -21400,7 +22318,7 @@ var require_run_write_guard = __commonJS({
|
|
|
21400
22318
|
"../runner-core/dist/services/run-write-guard.js"(exports2) {
|
|
21401
22319
|
"use strict";
|
|
21402
22320
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
21403
|
-
exports2.RUN_WRITE_RELAYED_LINE = exports2.WRITE_GUARD_UNAVAILABLE_ERROR_PREFIX = exports2.WRITE_HELD_ERROR_PREFIX = exports2.RUN_WRITE_UNAVAILABLE_LINE = exports2.RUN_WRITE_SAW_LINE = exports2.RUN_WRITE_HELD_LINE = exports2.RUN_WRITE_GUARD_LINE_PREFIX = exports2.RUN_WRITE_SIGNIN_VARS_ENV = exports2.RUN_WRITE_POLICY_ENV = exports2.NO_KEEPALIVE_INIT_SCRIPT = exports2.RUN_WRITE_LEAVING_EVENT = exports2.RUN_WRITE_RELAY_KEY = exports2.RUN_WRITE_DROPPED_BINDING = exports2.RUN_WRITE_BLOCK_CONTEXT_OPTIONS = exports2.WEBSOCKET_NOT_GUARDED = exports2.RunWriteGuard = exports2.BROKER_TOKEN_TTL_MS = exports2.MAX_RUN_WRITE_RECORDS = exports2.SHARED_SUFFIX_PATTERN_REASON = exports2.FIREBASE_AUTH_HANDLER_PATH = exports2.SIGN_IN_SECRET_VARIABLE = exports2.MAX_ALLOW_PATTERN_CHARS = exports2.MAX_ALLOW_PATTERNS = exports2.DEFAULT_RECORD_ONLY_RULES = exports2.RECORD_ONLY_CAPABLE_RULES = exports2.RUN_WRITE_POLICY_VERSION = void 0;
|
|
22321
|
+
exports2.RUN_WRITE_RELAYED_LINE = exports2.WRITE_GUARD_UNAVAILABLE_ERROR_PREFIX = exports2.WRITE_HELD_ERROR_PREFIX = exports2.RUN_WRITE_UNAVAILABLE_LINE = exports2.RUN_WRITE_SAW_LINE = exports2.RUN_WRITE_HELD_LINE = exports2.RUN_WRITE_GUARD_LINE_PREFIX = exports2.RUN_WRITE_SIGNIN_VARS_ENV = exports2.RUN_WRITE_POLICY_ENV = exports2.NO_KEEPALIVE_INIT_SCRIPT = exports2.RUN_WRITE_LEAVING_EVENT = exports2.RUN_WRITE_RELAY_KEY = exports2.RUN_WRITE_DROPPED_BINDING = exports2.RUN_WRITE_BLOCK_CONTEXT_OPTIONS = exports2.WEBSOCKET_NOT_GUARDED = exports2.RunWriteGuard = exports2.BROKER_TOKEN_TTL_MS = exports2.MAX_RUN_WRITE_RECORDS = exports2.SHARED_SUFFIX_PATTERN_REASON = exports2.FIREBASE_AUTH_HANDLER_PATH = exports2.SIGN_IN_SECRET_VARIABLE = exports2.MAX_ALLOW_PATTERN_CHARS = exports2.MAX_ALLOW_PATTERNS = exports2.MAX_IDP_HOSTS = exports2.DEFAULT_RECORD_ONLY_RULES = exports2.RECORD_ONLY_CAPABLE_RULES = exports2.RUN_WRITE_POLICY_VERSION = void 0;
|
|
21404
22322
|
exports2.parseRunWritePolicy = parseRunWritePolicy;
|
|
21405
22323
|
exports2.signInSecretsOf = signInSecretsOf;
|
|
21406
22324
|
exports2.withRunWritePolicyScope = withRunWritePolicyScope;
|
|
@@ -21409,6 +22327,8 @@ var require_run_write_guard = __commonJS({
|
|
|
21409
22327
|
exports2.bodyHasSignInSecret = bodyHasSignInSecret;
|
|
21410
22328
|
exports2.compileAllowPattern = compileAllowPattern;
|
|
21411
22329
|
exports2.allowPatternProblem = allowPatternProblem;
|
|
22330
|
+
exports2.normaliseIdpHost = normaliseIdpHost;
|
|
22331
|
+
exports2.idpHostProblem = idpHostProblem;
|
|
21412
22332
|
exports2.runWritePatternNotes = runWritePatternNotes;
|
|
21413
22333
|
exports2.decideRunWrite = decideRunWrite;
|
|
21414
22334
|
exports2.isGoogleBrokerToken = isGoogleBrokerToken;
|
|
@@ -21441,6 +22361,8 @@ var require_run_write_guard = __commonJS({
|
|
|
21441
22361
|
exports2.RECORD_ONLY_CAPABLE_RULES = ["write-shaped-get"];
|
|
21442
22362
|
exports2.DEFAULT_RECORD_ONLY_RULES = ["write-shaped-get"];
|
|
21443
22363
|
var MAX_APP_SITES = 16;
|
|
22364
|
+
exports2.MAX_IDP_HOSTS = 4;
|
|
22365
|
+
var MAX_IDP_HINTS = 4;
|
|
21444
22366
|
exports2.MAX_ALLOW_PATTERNS = 50;
|
|
21445
22367
|
exports2.MAX_ALLOW_PATTERN_CHARS = 200;
|
|
21446
22368
|
var MAX_REASON_CHARS = 300;
|
|
@@ -21468,6 +22390,11 @@ var require_run_write_guard = __commonJS({
|
|
|
21468
22390
|
const e = x;
|
|
21469
22391
|
return e && typeof e.pattern === "string" && typeof e.reason === "string" ? [{ pattern: e.pattern.slice(0, exports2.MAX_ALLOW_PATTERN_CHARS), reason: e.reason.slice(0, MAX_REASON_CHARS) }] : [];
|
|
21470
22392
|
}) : [];
|
|
22393
|
+
const idpHosts = Array.isArray(v.idpHosts) ? [...new Set(v.idpHosts.filter((h) => typeof h === "string" && normaliseIdpHost(h) === h && idpHostProblem(h) === null))].slice(0, exports2.MAX_IDP_HOSTS) : [];
|
|
22394
|
+
const ignoredIdpHosts = Array.isArray(v.ignoredIdpHosts) ? v.ignoredIdpHosts.slice(0, exports2.MAX_ALLOW_PATTERNS).flatMap((x) => {
|
|
22395
|
+
const e = x;
|
|
22396
|
+
return e && typeof e.pattern === "string" && typeof e.reason === "string" ? [{ pattern: e.pattern.slice(0, exports2.MAX_ALLOW_PATTERN_CHARS), reason: e.reason.slice(0, MAX_REASON_CHARS) }] : [];
|
|
22397
|
+
}) : [];
|
|
21471
22398
|
const recordOnlyRules = Array.isArray(v.recordOnlyRules) ? exports2.RECORD_ONLY_CAPABLE_RULES.filter((rule) => v.recordOnlyRules.includes(rule)) : [...exports2.DEFAULT_RECORD_ONLY_RULES];
|
|
21472
22399
|
if (typeof v.reason !== "string")
|
|
21473
22400
|
return null;
|
|
@@ -21480,6 +22407,9 @@ var require_run_write_guard = __commonJS({
|
|
|
21480
22407
|
appSites: appSites.map((s) => s.toLowerCase()),
|
|
21481
22408
|
allowPatterns,
|
|
21482
22409
|
ignoredAllowPatterns,
|
|
22410
|
+
// Only when set: a policy without them parses exactly as before.
|
|
22411
|
+
...idpHosts.length > 0 ? { idpHosts } : {},
|
|
22412
|
+
...ignoredIdpHosts.length > 0 ? { ignoredIdpHosts } : {},
|
|
21483
22413
|
recordOnlyRules,
|
|
21484
22414
|
reason: v.reason.slice(0, MAX_REASON_CHARS),
|
|
21485
22415
|
...v.pwAgentsGuard === "off" ? { pwAgentsGuard: "off" } : {}
|
|
@@ -21681,8 +22611,153 @@ var require_run_write_guard = __commonJS({
|
|
|
21681
22611
|
return named.size + Math.min(bare.size, 2) >= 2;
|
|
21682
22612
|
}
|
|
21683
22613
|
var GRAPHQL_SIGN_IN_NAME = /^(?:log_?in|sign_?in|authenticate|login\w{0,40}|signin\w{0,40})$/i;
|
|
22614
|
+
var GRAPHQL_SIGN_IN_VERBS = ["login", "signin", "authenticate"];
|
|
22615
|
+
var GRAPHQL_SIGN_IN_PHRASE_WORDS = /* @__PURE__ */ new Set(["with", "via", "by", "using"]);
|
|
22616
|
+
var GRAPHQL_SIGN_IN_TAIL_WORDS = /* @__PURE__ */ new Set([
|
|
22617
|
+
"user",
|
|
22618
|
+
"mutation",
|
|
22619
|
+
"mfa",
|
|
22620
|
+
"otp",
|
|
22621
|
+
"totp",
|
|
22622
|
+
"sso",
|
|
22623
|
+
"anonymous",
|
|
22624
|
+
"anonymously",
|
|
22625
|
+
"email",
|
|
22626
|
+
"password",
|
|
22627
|
+
"phone",
|
|
22628
|
+
"number",
|
|
22629
|
+
"code",
|
|
22630
|
+
"token",
|
|
22631
|
+
"refresh",
|
|
22632
|
+
"custom",
|
|
22633
|
+
"api",
|
|
22634
|
+
"key",
|
|
22635
|
+
"magic",
|
|
22636
|
+
"credentials",
|
|
22637
|
+
"username",
|
|
22638
|
+
"credential",
|
|
22639
|
+
"sms",
|
|
22640
|
+
"pin",
|
|
22641
|
+
"jwt",
|
|
22642
|
+
"mobile",
|
|
22643
|
+
"session",
|
|
22644
|
+
"ticket",
|
|
22645
|
+
"qr",
|
|
22646
|
+
"biometric",
|
|
22647
|
+
"biometrics",
|
|
22648
|
+
"wallet",
|
|
22649
|
+
"identifier",
|
|
22650
|
+
"address",
|
|
22651
|
+
"local",
|
|
22652
|
+
"login",
|
|
22653
|
+
"userid",
|
|
22654
|
+
"passkey",
|
|
22655
|
+
"webauthn",
|
|
22656
|
+
"idp",
|
|
22657
|
+
"oauth",
|
|
22658
|
+
"oidc",
|
|
22659
|
+
"saml",
|
|
22660
|
+
"ldap",
|
|
22661
|
+
"google",
|
|
22662
|
+
"apple",
|
|
22663
|
+
"github",
|
|
22664
|
+
"gitlab",
|
|
22665
|
+
"facebook",
|
|
22666
|
+
"microsoft",
|
|
22667
|
+
"azure",
|
|
22668
|
+
"twitter",
|
|
22669
|
+
"linkedin",
|
|
22670
|
+
"discord",
|
|
22671
|
+
"slack",
|
|
22672
|
+
"twitch",
|
|
22673
|
+
"keycloak",
|
|
22674
|
+
"okta",
|
|
22675
|
+
"ethereum",
|
|
22676
|
+
"firebase",
|
|
22677
|
+
"cognito",
|
|
22678
|
+
"apikey",
|
|
22679
|
+
"appleid",
|
|
22680
|
+
"auth0",
|
|
22681
|
+
"faceid",
|
|
22682
|
+
"touchid",
|
|
22683
|
+
"twofactor",
|
|
22684
|
+
"backupcode",
|
|
22685
|
+
"recoverycode",
|
|
22686
|
+
"rememberme"
|
|
22687
|
+
]);
|
|
22688
|
+
var GRAPHQL_SIGN_IN_SUBJECT_WORDS = /* @__PURE__ */ new Set(["user", "customer", "admin", "member", "staff", "account"]);
|
|
22689
|
+
var GRAPHQL_SIGN_IN_JOINERS = /* @__PURE__ */ new Set(["and", "or"]);
|
|
22690
|
+
var GRAPHQL_SIGN_IN_JOINED_KINDS = /* @__PURE__ */ new Set([
|
|
22691
|
+
"github",
|
|
22692
|
+
"gitlab",
|
|
22693
|
+
"linkedin",
|
|
22694
|
+
"webauthn",
|
|
22695
|
+
"passkey",
|
|
22696
|
+
"apikey",
|
|
22697
|
+
"idp",
|
|
22698
|
+
"appleid",
|
|
22699
|
+
"auth0",
|
|
22700
|
+
"faceid",
|
|
22701
|
+
"touchid",
|
|
22702
|
+
"twofactor",
|
|
22703
|
+
"backupcode",
|
|
22704
|
+
"recoverycode",
|
|
22705
|
+
"rememberme",
|
|
22706
|
+
"username",
|
|
22707
|
+
"userid"
|
|
22708
|
+
]);
|
|
22709
|
+
function joinSplitKinds(words) {
|
|
22710
|
+
const out = [];
|
|
22711
|
+
for (let i = 0; i < words.length; i++) {
|
|
22712
|
+
let joined = 0;
|
|
22713
|
+
for (let n = Math.min(3, words.length - i); n >= 2; n--) {
|
|
22714
|
+
const part = words.slice(i, i + n);
|
|
22715
|
+
if (!part.some((w) => GRAPHQL_SIGN_IN_JOINERS.has(w)) && GRAPHQL_SIGN_IN_JOINED_KINDS.has(part.join(""))) {
|
|
22716
|
+
joined = n;
|
|
22717
|
+
break;
|
|
22718
|
+
}
|
|
22719
|
+
}
|
|
22720
|
+
if (joined) {
|
|
22721
|
+
out.push(words.slice(i, i + joined).join(""));
|
|
22722
|
+
i += joined - 1;
|
|
22723
|
+
} else
|
|
22724
|
+
out.push(words[i]);
|
|
22725
|
+
}
|
|
22726
|
+
return out;
|
|
22727
|
+
}
|
|
22728
|
+
var GRAPHQL_SIGN_IN_LINK_KINDS = /* @__PURE__ */ new Set(["magic", "email"]);
|
|
22729
|
+
function graphqlSignInTail(name) {
|
|
22730
|
+
const words = wordsOf(name.replace(/(?<=[A-Z0-9][A-Z0-9])(?=[A-Z][a-z])/g, " "));
|
|
22731
|
+
const head = words[0] === "log" || words[0] === "sign" ? words[1] === "in" ? [`${words[0]}in`, ...words.slice(2)] : null : words;
|
|
22732
|
+
if (!head || head.length === 0)
|
|
22733
|
+
return null;
|
|
22734
|
+
const verb = GRAPHQL_SIGN_IN_VERBS.find((v) => head[0].startsWith(v));
|
|
22735
|
+
if (!verb)
|
|
22736
|
+
return null;
|
|
22737
|
+
const glued = head[0].slice(verb.length);
|
|
22738
|
+
return glued ? [glued, ...head.slice(1)] : head.slice(1);
|
|
22739
|
+
}
|
|
22740
|
+
function isGraphqlSignInTail(tail) {
|
|
22741
|
+
const words = joinSplitKinds(tail);
|
|
22742
|
+
let start = 0;
|
|
22743
|
+
while (start < words.length && GRAPHQL_SIGN_IN_SUBJECT_WORDS.has(words[start]))
|
|
22744
|
+
start++;
|
|
22745
|
+
if (start === words.length)
|
|
22746
|
+
return true;
|
|
22747
|
+
let kinds = words.slice(start);
|
|
22748
|
+
const phrase = kinds.findIndex((w) => GRAPHQL_SIGN_IN_PHRASE_WORDS.has(w));
|
|
22749
|
+
if (phrase >= 0) {
|
|
22750
|
+
if (phrase === kinds.length - 1 || phrase > 0 && GRAPHQL_SIGN_IN_JOINERS.has(kinds[phrase - 1]) || GRAPHQL_SIGN_IN_JOINERS.has(kinds[phrase + 1]))
|
|
22751
|
+
return false;
|
|
22752
|
+
kinds = [...kinds.slice(0, phrase), ...kinds.slice(phrase + 1)];
|
|
22753
|
+
}
|
|
22754
|
+
if (kinds.length === 0)
|
|
22755
|
+
return false;
|
|
22756
|
+
const isKind = (w, before) => GRAPHQL_SIGN_IN_TAIL_WORDS.has(w) || /^v\d{1,3}$/.test(w) || /^\d?fa$/.test(w) || w === "link" && before !== void 0 && GRAPHQL_SIGN_IN_LINK_KINDS.has(before);
|
|
22757
|
+
return kinds.every((w, i) => GRAPHQL_SIGN_IN_JOINERS.has(w) ? i > 0 && i < kinds.length - 1 && !GRAPHQL_SIGN_IN_JOINERS.has(kinds[i - 1]) : isKind(w, i === phrase ? void 0 : kinds[i - 1]));
|
|
22758
|
+
}
|
|
21684
22759
|
function wordsOf(segment) {
|
|
21685
|
-
return segment.replace(/([a-z])(?=[A-Z0-9])/g, "$1 ").toLowerCase().split(/[\s
|
|
22760
|
+
return segment.replace(/([a-z])(?=[A-Z0-9])/g, "$1 ").toLowerCase().split(/[\s.,_/-]+/).filter(Boolean);
|
|
21686
22761
|
}
|
|
21687
22762
|
function rawSegmentsOf(pathname) {
|
|
21688
22763
|
return pathname.split("/").map((seg) => {
|
|
@@ -21703,7 +22778,10 @@ var require_run_write_guard = __commonJS({
|
|
|
21703
22778
|
return words.some((w) => ACCOUNT_CHANGE_WORDS.has(w)) && words.some((w) => ACCOUNT_CHANGE_CONTEXT.has(w));
|
|
21704
22779
|
}
|
|
21705
22780
|
function isGraphqlSignInName(name) {
|
|
21706
|
-
|
|
22781
|
+
if (!GRAPHQL_SIGN_IN_NAME.test(name))
|
|
22782
|
+
return false;
|
|
22783
|
+
const tail = graphqlSignInTail(name);
|
|
22784
|
+
return tail !== null && isGraphqlSignInTail(tail) && !changesSomething([name], { passwordIsCredential: true });
|
|
21707
22785
|
}
|
|
21708
22786
|
function graphqlSignIn(body) {
|
|
21709
22787
|
let parsed;
|
|
@@ -21739,6 +22817,173 @@ var require_run_write_guard = __commonJS({
|
|
|
21739
22817
|
}
|
|
21740
22818
|
return signIns > 0 ? "document" : null;
|
|
21741
22819
|
}
|
|
22820
|
+
var NOT_A_BROKER_SIGN_IN_WORDS = /* @__PURE__ */ new Set([
|
|
22821
|
+
"add",
|
|
22822
|
+
"book",
|
|
22823
|
+
"booking",
|
|
22824
|
+
"bookings",
|
|
22825
|
+
"order",
|
|
22826
|
+
"orders",
|
|
22827
|
+
"reserve",
|
|
22828
|
+
"reservation",
|
|
22829
|
+
"reservations",
|
|
22830
|
+
"submit",
|
|
22831
|
+
"send",
|
|
22832
|
+
"invite",
|
|
22833
|
+
"invites",
|
|
22834
|
+
"invitation",
|
|
22835
|
+
"invitations",
|
|
22836
|
+
"checkout",
|
|
22837
|
+
"purchase",
|
|
22838
|
+
"purchases",
|
|
22839
|
+
"buy",
|
|
22840
|
+
"pay",
|
|
22841
|
+
"payment",
|
|
22842
|
+
"payments",
|
|
22843
|
+
"cart",
|
|
22844
|
+
"subscribe",
|
|
22845
|
+
"subscription",
|
|
22846
|
+
"subscriptions",
|
|
22847
|
+
"publish",
|
|
22848
|
+
"upload",
|
|
22849
|
+
"charge",
|
|
22850
|
+
"charges",
|
|
22851
|
+
"refund",
|
|
22852
|
+
"refunds"
|
|
22853
|
+
]);
|
|
22854
|
+
var BROKER_MAKE_VERBS = /* @__PURE__ */ new Set(["create", "generate"]);
|
|
22855
|
+
var BROKER_CREDENTIAL_WORDS = /* @__PURE__ */ new Set(["session", "sessions", "login", "logins", "signin", "sign", "token", "tokens", "jwt", "jwts"]);
|
|
22856
|
+
var BROKER_CREDENTIAL_QUALIFIERS = /* @__PURE__ */ new Set([
|
|
22857
|
+
"access",
|
|
22858
|
+
"refresh",
|
|
22859
|
+
"id",
|
|
22860
|
+
"auth",
|
|
22861
|
+
"oauth",
|
|
22862
|
+
"bearer",
|
|
22863
|
+
"in",
|
|
22864
|
+
"new",
|
|
22865
|
+
"user",
|
|
22866
|
+
"customer",
|
|
22867
|
+
"with",
|
|
22868
|
+
"from",
|
|
22869
|
+
"via",
|
|
22870
|
+
"for",
|
|
22871
|
+
"by",
|
|
22872
|
+
"and",
|
|
22873
|
+
"mutation",
|
|
22874
|
+
"google",
|
|
22875
|
+
"apple",
|
|
22876
|
+
"facebook",
|
|
22877
|
+
"github",
|
|
22878
|
+
"microsoft",
|
|
22879
|
+
"sso",
|
|
22880
|
+
"social",
|
|
22881
|
+
"oidc",
|
|
22882
|
+
"firebase"
|
|
22883
|
+
]);
|
|
22884
|
+
function namesOnlyACredential(words) {
|
|
22885
|
+
const rest = words.filter((w) => !BROKER_MAKE_VERBS.has(w));
|
|
22886
|
+
return rest.some((w) => BROKER_CREDENTIAL_WORDS.has(w)) && rest.every((w) => BROKER_CREDENTIAL_WORDS.has(w) || BROKER_CREDENTIAL_QUALIFIERS.has(w));
|
|
22887
|
+
}
|
|
22888
|
+
function actsBesidesBrokerSignIn(segments) {
|
|
22889
|
+
return segments.some((seg, i) => {
|
|
22890
|
+
const words = wordsOf(seg);
|
|
22891
|
+
if (words.some((w) => NOT_A_BROKER_SIGN_IN_WORDS.has(w)) || NOT_A_BROKER_SIGN_IN_WORDS.has(words.join("")))
|
|
22892
|
+
return true;
|
|
22893
|
+
if (!words.some((w) => BROKER_MAKE_VERBS.has(w)))
|
|
22894
|
+
return false;
|
|
22895
|
+
if (namesOnlyACredential(words))
|
|
22896
|
+
return false;
|
|
22897
|
+
return !(words.length === 1 && i > 0 && i === segments.length - 1 && namesOnlyACredential(wordsOf(segments[i - 1])));
|
|
22898
|
+
});
|
|
22899
|
+
}
|
|
22900
|
+
function brokerRefuses(segments) {
|
|
22901
|
+
return changesSomething(segments) || actsBesidesBrokerSignIn(segments);
|
|
22902
|
+
}
|
|
22903
|
+
var BROKER_SIGN_IN_NAME_WORDS = /* @__PURE__ */ new Set(["login", "signin", "sign", "auth", "authenticate", "google", "oauth", "sso", "social", "session"]);
|
|
22904
|
+
function isBrokerSignInName(name) {
|
|
22905
|
+
return typeof name === "string" && wordsOf(name).some((w) => BROKER_SIGN_IN_NAME_WORDS.has(w)) && !brokerRefuses([name]);
|
|
22906
|
+
}
|
|
22907
|
+
function graphqlBrokerSignIn(body) {
|
|
22908
|
+
let parsed;
|
|
22909
|
+
try {
|
|
22910
|
+
parsed = JSON.parse(body);
|
|
22911
|
+
} catch {
|
|
22912
|
+
parsed = { query: body };
|
|
22913
|
+
}
|
|
22914
|
+
const entries = Array.isArray(parsed) ? parsed : [parsed];
|
|
22915
|
+
let mutationRoots = 0;
|
|
22916
|
+
for (const entry of entries) {
|
|
22917
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
22918
|
+
return false;
|
|
22919
|
+
const { query, operationName } = entry;
|
|
22920
|
+
const record = entry;
|
|
22921
|
+
const ids = PERSISTED_ID_KEYS.map((key) => record[key]).filter((n) => n !== void 0);
|
|
22922
|
+
const names = operationName === void 0 ? ids : [operationName, ...ids];
|
|
22923
|
+
if (ids.length > 0 && !names.every(isBrokerSignInName))
|
|
22924
|
+
return false;
|
|
22925
|
+
if (typeof query !== "string") {
|
|
22926
|
+
return !Array.isArray(parsed) && query === void 0 && names.length > 0 && names.every(isBrokerSignInName);
|
|
22927
|
+
}
|
|
22928
|
+
const ops = (0, survey_network_guard_js_1.graphqlOperationRoots)(query);
|
|
22929
|
+
if (!ops)
|
|
22930
|
+
return false;
|
|
22931
|
+
for (const op of ops) {
|
|
22932
|
+
if (op.kind === "query")
|
|
22933
|
+
continue;
|
|
22934
|
+
if (typeof operationName === "string" && brokerRefuses([operationName]))
|
|
22935
|
+
return false;
|
|
22936
|
+
const roots = op.roots.filter((root) => root !== "__typename");
|
|
22937
|
+
if (roots.some((root) => brokerRefuses([root])))
|
|
22938
|
+
return false;
|
|
22939
|
+
mutationRoots += roots.length;
|
|
22940
|
+
}
|
|
22941
|
+
}
|
|
22942
|
+
return mutationRoots === 1;
|
|
22943
|
+
}
|
|
22944
|
+
var GRAPHQL_DOCUMENT_START = /^[\s,]*(?:[{#]|(?:query|mutation|subscription|fragment)\b)/;
|
|
22945
|
+
function looksLikeGraphqlDocument(text) {
|
|
22946
|
+
return GRAPHQL_DOCUMENT_START.test(text) || (0, survey_network_guard_js_1.graphqlOperationRoots)(text) !== null;
|
|
22947
|
+
}
|
|
22948
|
+
var PERSISTED_ID_KEYS = ["id", "documentId", "doc_id", "queryId"];
|
|
22949
|
+
var GRAPHQL_ENVELOPE_FIELDS = ["variables", "operationName", "documentId", "doc_id", "queryId", "sha256Hash", "hash", "extensions", "operations"];
|
|
22950
|
+
function hasGraphqlEnvelope(has2, queryIsString) {
|
|
22951
|
+
return queryIsString || GRAPHQL_ENVELOPE_FIELDS.some(has2);
|
|
22952
|
+
}
|
|
22953
|
+
function carriesGraphql(search, body, contentType) {
|
|
22954
|
+
if (search.getAll("query").some(looksLikeGraphqlDocument))
|
|
22955
|
+
return true;
|
|
22956
|
+
if (/^\s*application\/graphql\b/i.test(contentType ?? ""))
|
|
22957
|
+
return true;
|
|
22958
|
+
if (/multipart\//i.test(contentType ?? "") || /^\s*--/.test(body)) {
|
|
22959
|
+
const parts = new Set([...body.matchAll(/\bname\s*=\s*"?([\w-]+)/gi)].map((m) => m[1]));
|
|
22960
|
+
return hasGraphqlEnvelope((field) => parts.has(field), parts.has("query"));
|
|
22961
|
+
}
|
|
22962
|
+
let parsed;
|
|
22963
|
+
try {
|
|
22964
|
+
parsed = JSON.parse(body);
|
|
22965
|
+
} catch {
|
|
22966
|
+
if (looksLikeGraphqlDocument(body))
|
|
22967
|
+
return true;
|
|
22968
|
+
const form = new URLSearchParams(body);
|
|
22969
|
+
return hasGraphqlEnvelope((field) => form.has(field), form.has("query"));
|
|
22970
|
+
}
|
|
22971
|
+
if (Array.isArray(parsed))
|
|
22972
|
+
return true;
|
|
22973
|
+
if (!parsed || typeof parsed !== "object")
|
|
22974
|
+
return false;
|
|
22975
|
+
const record = parsed;
|
|
22976
|
+
return hasGraphqlEnvelope((field) => record[field] !== void 0, typeof record.query === "string");
|
|
22977
|
+
}
|
|
22978
|
+
function isBrokerSignInShape(pathname, search, postData, contentType) {
|
|
22979
|
+
if (brokerRefuses(rawSegmentsOf(pathname)))
|
|
22980
|
+
return false;
|
|
22981
|
+
if (!isGraphqlPath(pathname) && !(typeof postData === "string" && carriesGraphql(search, postData, contentType)))
|
|
22982
|
+
return true;
|
|
22983
|
+
if ((0, survey_network_guard_js_1.graphqlUrlCarriesQuery)(search) || PERSISTED_ID_KEYS.some((key) => search.has(key)) || typeof postData !== "string" || postData.length > MAX_BODY_CHARS)
|
|
22984
|
+
return false;
|
|
22985
|
+
return graphqlBrokerSignIn(postData);
|
|
22986
|
+
}
|
|
21742
22987
|
function isCredentialSignInShape(pathname, search, postData, contentType) {
|
|
21743
22988
|
if (typeof postData === "string" && postData.length > MAX_BODY_CHARS)
|
|
21744
22989
|
return false;
|
|
@@ -21952,6 +23197,26 @@ var require_run_write_guard = __commonJS({
|
|
|
21952
23197
|
}).join("");
|
|
21953
23198
|
return { method, host, path: new RegExp(`^${body}/?$`, "i") };
|
|
21954
23199
|
}
|
|
23200
|
+
function normaliseIdpHost(raw) {
|
|
23201
|
+
return raw.trim().toLowerCase().replace(/\.$/, "");
|
|
23202
|
+
}
|
|
23203
|
+
var WILDCARD_DNS_RE = /(?:^|\.)(?:nip\.io|sslip\.io|xip\.io|localtest\.me|lvh\.me|vcap\.me|traefik\.me|localho\.st|localhost\.direct|local\.gd|fuf\.me)$/;
|
|
23204
|
+
function idpHostProblem(host) {
|
|
23205
|
+
if (host.length > 253 || !/^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/.test(host))
|
|
23206
|
+
return "not a host name (no scheme, port, path or wildcard)";
|
|
23207
|
+
if (/^[0-9.]+$/.test(host))
|
|
23208
|
+
return "an IP address";
|
|
23209
|
+
if (/(?:^|\.)(?:localhost|local|internal)$/.test(host))
|
|
23210
|
+
return "a local name";
|
|
23211
|
+
if (WILDCARD_DNS_RE.test(host))
|
|
23212
|
+
return "a wildcard-DNS name (it can point at any address)";
|
|
23213
|
+
if ((0, shared_1.isSharedSuffix)(host))
|
|
23214
|
+
return exports2.SHARED_SUFFIX_PATTERN_REASON;
|
|
23215
|
+
return null;
|
|
23216
|
+
}
|
|
23217
|
+
function isIdpHost(url, host, policy) {
|
|
23218
|
+
return url.protocol === "https:" && url.port === "" && (policy.idpHosts ?? []).includes(host);
|
|
23219
|
+
}
|
|
21955
23220
|
function matchesAllowPatterns(method, host, pathname, policy, compiled) {
|
|
21956
23221
|
const patterns = compiled ?? policy.allowPatterns.map(compileAllowPattern).filter((p) => p !== null);
|
|
21957
23222
|
return patterns.some((p) => {
|
|
@@ -21975,7 +23240,10 @@ var require_run_write_guard = __commonJS({
|
|
|
21975
23240
|
return reason ? [{ pattern, reason }] : [];
|
|
21976
23241
|
})
|
|
21977
23242
|
];
|
|
21978
|
-
return
|
|
23243
|
+
return [
|
|
23244
|
+
...ignored.map(({ pattern, reason }) => `[run-write-guard] SAFE_WRITE_PATTERNS entry ${JSON.stringify(pattern)} ignored: ${reason}`),
|
|
23245
|
+
...(policy.ignoredIdpHosts ?? []).map(({ pattern, reason }) => `[run-write-guard] AUTH_PROVIDER_HOSTS entry ${JSON.stringify(pattern)} ignored: ${reason}`)
|
|
23246
|
+
];
|
|
21979
23247
|
}
|
|
21980
23248
|
function describe(facts, url, rule) {
|
|
21981
23249
|
return {
|
|
@@ -22027,6 +23295,8 @@ var require_run_write_guard = __commonJS({
|
|
|
22027
23295
|
return { action: "write", rule: "sign-up", record: describe(facts, url, "sign-up") };
|
|
22028
23296
|
if (isAuthProviderWrite(method, host, pathname, facts.amzTarget, url.searchParams))
|
|
22029
23297
|
return { action: "allow", rule: "auth-provider" };
|
|
23298
|
+
if (isIdpHost(url, host, policy) && isAuth0CustomDomainSignIn(method, pathname, url.searchParams))
|
|
23299
|
+
return { action: "allow", rule: "auth-provider" };
|
|
22030
23300
|
const appSite = isAppSite(host, policy);
|
|
22031
23301
|
if (facts.registeredAuthHandler && pathname === exports2.FIREBASE_AUTH_HANDLER_PATH)
|
|
22032
23302
|
return { action: "allow", rule: "auth-provider" };
|
|
@@ -22034,7 +23304,7 @@ var require_run_write_guard = __commonJS({
|
|
|
22034
23304
|
return { action: "allow", rule: "sign-in" };
|
|
22035
23305
|
if (appSite && isAuth0CustomDomainSignIn(method, pathname, url.searchParams))
|
|
22036
23306
|
return { action: "allow", rule: "sign-in" };
|
|
22037
|
-
if (appSite && method === "POST" && facts.brokerTokenInBody &&
|
|
23307
|
+
if (appSite && method === "POST" && facts.brokerTokenInBody && isBrokerSignInShape(pathname, url.searchParams, facts.postData, facts.contentType)) {
|
|
22038
23308
|
return { action: "allow", rule: "broker-sign-in" };
|
|
22039
23309
|
}
|
|
22040
23310
|
if (appSite && isEvidencedTokenRefresh(method, pathname, facts.postData))
|
|
@@ -22042,7 +23312,7 @@ var require_run_write_guard = __commonJS({
|
|
|
22042
23312
|
const signIn = appSite && method === "POST" && facts.signInSecretInBody ? isCredentialSignInShape(pathname, url.searchParams, facts.postData, facts.contentType) : false;
|
|
22043
23313
|
if (signIn)
|
|
22044
23314
|
return { action: "allow", rule: "credential-sign-in", ...signIn === "persisted" ? { persisted: true } : {} };
|
|
22045
|
-
if (method === "POST" && isGraphqlPath(pathname) &&
|
|
23315
|
+
if (method === "POST" && isGraphqlPath(pathname) && (0, survey_network_guard_js_1.graphqlUrlQueriesAreReads)(url.searchParams) && isGraphqlQueryOnlyBody(facts.postData))
|
|
22046
23316
|
return { action: "allow", rule: "graphql-query" };
|
|
22047
23317
|
if (method === "POST" && hostIs(host, SEARCH_POST_HOSTS))
|
|
22048
23318
|
return { action: "allow", rule: "search-post" };
|
|
@@ -22099,6 +23369,8 @@ var require_run_write_guard = __commonJS({
|
|
|
22099
23369
|
relayRejected = 0;
|
|
22100
23370
|
/** Credential sign-ins already said in the run log (observe mode; method, host and path shape). */
|
|
22101
23371
|
signInsLogged = /* @__PURE__ */ new Set();
|
|
23372
|
+
/** Hosts already named in the run log as a possible AUTH_PROVIDER_HOSTS entry (at most MAX_IDP_HINTS). */
|
|
23373
|
+
idpHintsLogged = /* @__PURE__ */ new Set();
|
|
22102
23374
|
constructor(policy, opts = {}) {
|
|
22103
23375
|
this.policy = policy;
|
|
22104
23376
|
this.compiled = policy.allowPatterns.map(compileAllowPattern).filter((p) => p !== null);
|
|
@@ -22196,6 +23468,22 @@ var require_run_write_guard = __commonJS({
|
|
|
22196
23468
|
const verb = held ? "held" : "saw";
|
|
22197
23469
|
const why = record.writeShaped ? `${record.rule}, ${record.writeShaped}` : record.rule;
|
|
22198
23470
|
this.log?.(`[run-write-guard] ${verb} ${record.method} ${record.host}${record.path}${record.keys.length ? ` (${record.keys.join(", ")})` : ""} [${why}]`);
|
|
23471
|
+
this.hintIdpHost(record);
|
|
23472
|
+
}
|
|
23473
|
+
/**
|
|
23474
|
+
* An Auth0 sign-in step (by path) posted to another site was a third-party write: the tenant may
|
|
23475
|
+
* answer on a custom domain of its own. Said once per host, for at most MAX_IDP_HINTS hosts, so a
|
|
23476
|
+
* person knows AUTH_PROVIDER_HOSTS exists; the guard never names the host itself.
|
|
23477
|
+
*/
|
|
23478
|
+
hintIdpHost(record) {
|
|
23479
|
+
if (record.rule !== "third-party-write" || record.method !== "POST")
|
|
23480
|
+
return;
|
|
23481
|
+
if (this.idpHintsLogged.has(record.host) || this.idpHintsLogged.size >= MAX_IDP_HINTS)
|
|
23482
|
+
return;
|
|
23483
|
+
if ((this.policy.idpHosts ?? []).includes(record.host) || !AUTH0_AUTH_RE.test(record.path.toLowerCase()))
|
|
23484
|
+
return;
|
|
23485
|
+
this.idpHintsLogged.add(record.host);
|
|
23486
|
+
this.log?.(`[run-write-guard] note: ${record.host} looks like an Auth0 sign-in on another site; if it is the app's own sign-in, a project admin can name it in AUTH_PROVIDER_HOSTS in Test Data`);
|
|
22199
23487
|
}
|
|
22200
23488
|
/**
|
|
22201
23489
|
* A page sent a message over a WebSocket to the app's site. The guard cannot tell a read from a
|
|
@@ -23003,8 +24291,9 @@ var require_run_write_guard = __commonJS({
|
|
|
23003
24291
|
};
|
|
23004
24292
|
Object.assign(context, {
|
|
23005
24293
|
route: async (url, handler, options) => {
|
|
23006
|
-
await route(url, handler, options);
|
|
24294
|
+
const disposable = await route(url, handler, options);
|
|
23007
24295
|
others.push({ url, handler });
|
|
24296
|
+
return disposable;
|
|
23008
24297
|
},
|
|
23009
24298
|
unroute: async (url, handler) => {
|
|
23010
24299
|
if (handler === void 0 && sameRouteUrl(url, GUARD_ROUTE)) {
|
|
@@ -23337,6 +24626,7 @@ var require_run_write_guard = __commonJS({
|
|
|
23337
24626
|
}
|
|
23338
24627
|
function buildRunWriteGuardHook(policy, modulePath, signInSecretNames = [], opts = {}) {
|
|
23339
24628
|
const withContext = opts.browserContext !== false;
|
|
24629
|
+
const hookTest = opts.hookTest ?? "test";
|
|
23340
24630
|
const names = signInSecretNames.filter((n) => /^[A-Za-z_][A-Za-z0-9_]{0,63}$/.test(n)).slice(0, 16);
|
|
23341
24631
|
return `
|
|
23342
24632
|
import { createRequire as __qaWriteGuardRequire } from 'node:module';
|
|
@@ -23359,7 +24649,7 @@ try {
|
|
|
23359
24649
|
} catch (err) {
|
|
23360
24650
|
__qaWriteGuardError = err;
|
|
23361
24651
|
}
|
|
23362
|
-
|
|
24652
|
+
${hookTest}.beforeEach(async (${withContext ? "{ context }" : ""}) => {
|
|
23363
24653
|
try {
|
|
23364
24654
|
if (__qaWriteGuardError) throw __qaWriteGuardError;
|
|
23365
24655
|
${withContext ? "await __qaWriteGuard.installRunWriteGuard(context, __qaWriteGuardPolicy, { onLog: (line) => console.log(line), signInSecrets: __qaWriteGuardSecrets });" : "// an @api test: no browser context, only Node's fetch is guarded"}
|
|
@@ -23368,7 +24658,7 @@ test.beforeEach(async (${withContext ? "{ context }" : ""}) => {
|
|
|
23368
24658
|
${policy.mode === "block" ? "throw err;" : "// observe: never fail the test"}
|
|
23369
24659
|
}
|
|
23370
24660
|
});${withContext && policy.mode === "block" ? `
|
|
23371
|
-
|
|
24661
|
+
${hookTest}.afterEach(async ({ context }) => {
|
|
23372
24662
|
try { if (__qaWriteGuard) await __qaWriteGuard.clearRunWriteRelay(context); } catch { /* the context closes next */ }
|
|
23373
24663
|
});` : ""}
|
|
23374
24664
|
`;
|