@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
|
@@ -105,13 +105,13 @@ function isBlockedEnvVar(key) {
|
|
|
105
105
|
function sanitizeTestVariables(vars) {
|
|
106
106
|
if (!vars)
|
|
107
107
|
return {};
|
|
108
|
-
const
|
|
108
|
+
const clean3 = {};
|
|
109
109
|
for (const [key, value] of Object.entries(vars)) {
|
|
110
110
|
if (!isBlockedEnvVar(key)) {
|
|
111
|
-
|
|
111
|
+
clean3[key] = value;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
return
|
|
114
|
+
return clean3;
|
|
115
115
|
}
|
|
116
116
|
function buildSandboxedEnv(processEnv, testVariables) {
|
|
117
117
|
const env = {};
|
|
@@ -1619,8 +1619,11 @@ var init_discovery_har_decision = __esm({
|
|
|
1619
1619
|
});
|
|
1620
1620
|
|
|
1621
1621
|
// ../shared/dist/run-classification.js
|
|
1622
|
-
function
|
|
1623
|
-
|
|
1622
|
+
function isCancelledReason(error) {
|
|
1623
|
+
if (typeof error !== "string")
|
|
1624
|
+
return false;
|
|
1625
|
+
const text = error.trim();
|
|
1626
|
+
return CANCELLED_REASON_PREFIXES.some((prefix) => text.startsWith(prefix));
|
|
1624
1627
|
}
|
|
1625
1628
|
function isHeldHealRun(run) {
|
|
1626
1629
|
return run?.status === "PASSED" && typeof run.error === "string" && run.error.startsWith(HEAL_PATCH_HELD_RUN_ERROR_PREFIX);
|
|
@@ -1653,7 +1656,7 @@ function pickLatestHealthRun(runs) {
|
|
|
1653
1656
|
for (const run of runs) {
|
|
1654
1657
|
if (run.mode === "auth-setup")
|
|
1655
1658
|
continue;
|
|
1656
|
-
if (run.status === "ERROR" &&
|
|
1659
|
+
if (run.status === "ERROR" && isCancelledReason(run.error))
|
|
1657
1660
|
continue;
|
|
1658
1661
|
if (isHeldHealRun(run))
|
|
1659
1662
|
continue;
|
|
@@ -1671,6 +1674,15 @@ function pickDisplayRun(runs) {
|
|
|
1671
1674
|
return latest;
|
|
1672
1675
|
return pickLatestHealthRun(runs) ?? latest;
|
|
1673
1676
|
}
|
|
1677
|
+
function featureRowRunStatus(runs) {
|
|
1678
|
+
const latest = runs.find((run) => run.mode !== "auth-setup");
|
|
1679
|
+
if (!latest)
|
|
1680
|
+
return null;
|
|
1681
|
+
const decisive = pickLatestHealthRun(runs.filter((run) => !isEnvironmentalError(run)));
|
|
1682
|
+
if (decisive)
|
|
1683
|
+
return decisive.status;
|
|
1684
|
+
return latest.status === "PENDING" || latest.status === "RUNNING" ? latest.status : null;
|
|
1685
|
+
}
|
|
1674
1686
|
function isEnvironmentalError(run) {
|
|
1675
1687
|
if (!run)
|
|
1676
1688
|
return false;
|
|
@@ -1702,7 +1714,7 @@ function classifyErrorMessage(error) {
|
|
|
1702
1714
|
return "config_issue";
|
|
1703
1715
|
if (EMAIL_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix)))
|
|
1704
1716
|
return "email_not_received";
|
|
1705
|
-
if (
|
|
1717
|
+
if (isCancelledReason(error))
|
|
1706
1718
|
return "cancelled";
|
|
1707
1719
|
if (isRetriedRunInterruption(error))
|
|
1708
1720
|
return "interrupted";
|
|
@@ -1737,7 +1749,7 @@ function heldHealRunWhere() {
|
|
|
1737
1749
|
function excludeCancelledRunsWhere() {
|
|
1738
1750
|
return {
|
|
1739
1751
|
NOT: [
|
|
1740
|
-
{ status: "ERROR", error: { not: null, startsWith:
|
|
1752
|
+
{ status: "ERROR", OR: CANCELLED_REASON_PREFIXES.map((prefix) => ({ error: { not: null, startsWith: prefix } })) },
|
|
1741
1753
|
heldHealRunWhere()
|
|
1742
1754
|
]
|
|
1743
1755
|
};
|
|
@@ -1815,11 +1827,25 @@ function reportedBugWhere() {
|
|
|
1815
1827
|
function bugReviewStatus(status) {
|
|
1816
1828
|
return status === "QUARANTINED" ? "confirmed" : "needs-review";
|
|
1817
1829
|
}
|
|
1818
|
-
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;
|
|
1830
|
+
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;
|
|
1819
1831
|
var init_run_classification = __esm({
|
|
1820
1832
|
"../shared/dist/run-classification.js"() {
|
|
1821
1833
|
"use strict";
|
|
1822
1834
|
USER_CANCELLED_RUN_ERROR = "Cancelled by user";
|
|
1835
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR = "Cancelled by platform support";
|
|
1836
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR = "Cancelled by platform admin";
|
|
1837
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR = "Admin force-cancelled all active runs";
|
|
1838
|
+
CHAIN_CANCELLED_RUN_ERROR = "Cancelled: parent run cancelled";
|
|
1839
|
+
RETRY_HELD_RUN_ERROR = "Cancelled: auto generation paused";
|
|
1840
|
+
CANCELLED_REASON_PREFIXES = [
|
|
1841
|
+
USER_CANCELLED_RUN_ERROR,
|
|
1842
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
1843
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
1844
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
1845
|
+
CHAIN_CANCELLED_RUN_ERROR,
|
|
1846
|
+
RETRY_HELD_RUN_ERROR
|
|
1847
|
+
];
|
|
1848
|
+
isUserCancelledError = isCancelledReason;
|
|
1823
1849
|
HEAL_PATCH_HELD_RUN_ERROR_PREFIX = "Heal patch held";
|
|
1824
1850
|
RUNNER_INTERRUPT_ERROR_PREFIX = "Runner shutting down";
|
|
1825
1851
|
SERVER_INTERRUPT_ERROR_PREFIX = "Run interrupted by server restart";
|
|
@@ -1848,9 +1874,10 @@ var init_run_classification = __esm({
|
|
|
1848
1874
|
];
|
|
1849
1875
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES = [
|
|
1850
1876
|
...ENVIRONMENTAL_ERROR_PREFIXES.flatMap((prefix) => [prefix, `Error: ${prefix}`]),
|
|
1851
|
-
// Written by the
|
|
1852
|
-
|
|
1877
|
+
// Written by the cancels as is, with no prefix wrapper.
|
|
1878
|
+
...CANCELLED_REASON_PREFIXES
|
|
1853
1879
|
];
|
|
1880
|
+
FEATURE_ROW_RUN_WINDOW = 10;
|
|
1854
1881
|
BUG_SURFACE_SUPPRESSING_TAGS = ["@rate-limit-blocked", "@quota-exceeded", "@auth-lost"];
|
|
1855
1882
|
QUARANTINE_CLOSE_TAGS = [
|
|
1856
1883
|
"@bug-found",
|
|
@@ -3134,9 +3161,40 @@ function semanticTarget(label, platform, base) {
|
|
|
3134
3161
|
}
|
|
3135
3162
|
};
|
|
3136
3163
|
}
|
|
3164
|
+
function androidResourceOwners(value) {
|
|
3165
|
+
const owners = [];
|
|
3166
|
+
for (const match of value.matchAll(ANDROID_RESOURCE_ID_SUFFIX_RE)) {
|
|
3167
|
+
let runStart = match.index;
|
|
3168
|
+
while (runStart > 0 && /[a-z0-9_.]/i.test(value[runStart - 1]))
|
|
3169
|
+
runStart--;
|
|
3170
|
+
const owner = ownerAtEndOfRun(value.slice(runStart, match.index));
|
|
3171
|
+
if (owner !== null)
|
|
3172
|
+
owners.push(owner);
|
|
3173
|
+
}
|
|
3174
|
+
return owners;
|
|
3175
|
+
}
|
|
3176
|
+
function ownerAtEndOfRun(run) {
|
|
3177
|
+
const segments = run.split(".");
|
|
3178
|
+
const last = segments.length - 1;
|
|
3179
|
+
const startsWithLetter = (segment) => /^[a-z]/i.test(segment);
|
|
3180
|
+
if (last < 1 || !startsWithLetter(segments[last]))
|
|
3181
|
+
return null;
|
|
3182
|
+
let first = last;
|
|
3183
|
+
while (first > 0 && startsWithLetter(segments[first - 1]))
|
|
3184
|
+
first--;
|
|
3185
|
+
let offset = 0;
|
|
3186
|
+
for (let i = 0; i < first - 1; i++)
|
|
3187
|
+
offset += segments[i].length + 1;
|
|
3188
|
+
if (first > 0) {
|
|
3189
|
+
const letterAt = segments[first - 1].search(/[a-z]/i);
|
|
3190
|
+
if (letterAt >= 0)
|
|
3191
|
+
return run.slice(offset + letterAt);
|
|
3192
|
+
offset += segments[first - 1].length + 1;
|
|
3193
|
+
}
|
|
3194
|
+
return first < last ? run.slice(offset) : null;
|
|
3195
|
+
}
|
|
3137
3196
|
function containsForeignAppPackage(value, targetAppId) {
|
|
3138
|
-
for (const
|
|
3139
|
-
const owner = match[1];
|
|
3197
|
+
for (const owner of androidResourceOwners(value)) {
|
|
3140
3198
|
if (targetAppId && owner !== targetAppId && !owner.startsWith(`${targetAppId}.`))
|
|
3141
3199
|
return true;
|
|
3142
3200
|
}
|
|
@@ -3273,7 +3331,7 @@ function healMobileTestSteps(input) {
|
|
|
3273
3331
|
summary: changed ? uniq(summary).slice(0, 12) : []
|
|
3274
3332
|
};
|
|
3275
3333
|
}
|
|
3276
|
-
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE,
|
|
3334
|
+
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE, ANDROID_RESOURCE_ID_SUFFIX_RE, COMMON_EXTERNAL_PREFIXES;
|
|
3277
3335
|
var init_mobile_step_healer = __esm({
|
|
3278
3336
|
"../shared/dist/mobile-step-healer.js"() {
|
|
3279
3337
|
"use strict";
|
|
@@ -3294,7 +3352,7 @@ var init_mobile_step_healer = __esm({
|
|
|
3294
3352
|
"assertStateDelta"
|
|
3295
3353
|
]);
|
|
3296
3354
|
FOREIGN_PACKAGE_RE = /\b[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*){2,}\b/gi;
|
|
3297
|
-
|
|
3355
|
+
ANDROID_RESOURCE_ID_SUFFIX_RE = /:id\//gi;
|
|
3298
3356
|
COMMON_EXTERNAL_PREFIXES = [
|
|
3299
3357
|
"com.android.",
|
|
3300
3358
|
"com.google.",
|
|
@@ -4727,7 +4785,7 @@ var init_assertion_classifier = __esm({
|
|
|
4727
4785
|
// toHaveCount(0) stays tier 4 (absence proof) via TIER4_PATTERNS.
|
|
4728
4786
|
[/\.toHaveCount\s*\(\s*[1-9]\d*\s*\)/, "non-zero toHaveCount asserts a record count that changes between runs"],
|
|
4729
4787
|
// parenthesised counts like "(3)" or "[12]" in text - but not Playwright method args
|
|
4730
|
-
[
|
|
4788
|
+
[/\((?<!\.\w{3,20}\s*\()\s*\d+\s*\)(?!\s*(?:[,;]\s*)?\))/i, "parenthesised count is session-specific"],
|
|
4731
4789
|
// bare email addresses in assertion content
|
|
4732
4790
|
[/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i, "email address is user-specific"],
|
|
4733
4791
|
// currency/balance amounts (dynamic account data)
|
|
@@ -4973,7 +5031,7 @@ var init_assertion_proof = __esm({
|
|
|
4973
5031
|
PRESENCE_MATCHER = /\.(?:toBeVisible|toBeAttached|toBeEnabled|toBeInViewport|toBeEditable|toBeFocused)\s*\(|\.toHaveCount\s*\(\s*1\s*\)/;
|
|
4974
5032
|
TEXT_MATCHER = /\.(?:toHaveText|toContainText)\s*\(/;
|
|
4975
5033
|
ANY_VALUE_SOURCE = /^(?:\.|\\S|\\w|\\d|\[\^\\s\]|\[0-9\]|\[\\d\]|\[\\w\]|\[\\s\\S\])[+*]?\??$/;
|
|
4976
|
-
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s
|
|
5034
|
+
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s*[,)]/;
|
|
4977
5035
|
EMPTY_NOT_VALUE = /\.not\s*\.\s*toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/;
|
|
4978
5036
|
TEXT_MATCHER_LITERAL = /\.(?:toHaveText|toContainText)\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
4979
5037
|
GET_BY_TEXT_LITERAL = /getByText\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
@@ -4990,7 +5048,7 @@ var init_assertion_proof = __esm({
|
|
|
4990
5048
|
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;
|
|
4991
5049
|
TEXT_LOCATOR = /\.getByText\s*\(|\.filter\s*\(\s*\{\s*hasText\s*:/g;
|
|
4992
5050
|
CSS_LOCATOR = /\.locator\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/g;
|
|
4993
|
-
SPECIFIC_CSS = /\[[^\]]*=|#[\w-]|has-text|:text/;
|
|
5051
|
+
SPECIFIC_CSS = /\[[^\][=]*=|#[\w-]|has-text|:text/;
|
|
4994
5052
|
}
|
|
4995
5053
|
});
|
|
4996
5054
|
|
|
@@ -5954,22 +6012,37 @@ function classifyAuthHandoffIntent(text) {
|
|
|
5954
6012
|
function withoutIdpUrlAsserts(code) {
|
|
5955
6013
|
return code.replace(/\.(?:toHaveURL|waitForURL)\s*\((?:[^)(]|\([^)]*\))*\)/g, (match) => /accountchooser|accounts\.google|appleid\.apple|login\.microsoftonline|\/v\d+\/signin|oauth/i.test(match) ? "" : match);
|
|
5956
6014
|
}
|
|
6015
|
+
function stripLineComment(line) {
|
|
6016
|
+
let from = line.length;
|
|
6017
|
+
while (from > 0) {
|
|
6018
|
+
const c = line.charCodeAt(from - 1);
|
|
6019
|
+
if (c === 10 || c === 13 || c === 8232 || c === 8233)
|
|
6020
|
+
break;
|
|
6021
|
+
from--;
|
|
6022
|
+
}
|
|
6023
|
+
const at = line.indexOf("//", from);
|
|
6024
|
+
return at < 0 ? line : line.slice(0, at);
|
|
6025
|
+
}
|
|
5957
6026
|
function stripComments(code) {
|
|
5958
|
-
return replaceBlockComments(code, () => "").split("\n").map(
|
|
6027
|
+
return replaceBlockComments(code, () => "").split("\n").map(stripLineComment).join("\n");
|
|
5959
6028
|
}
|
|
5960
|
-
function
|
|
5961
|
-
const
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
let depth = 0;
|
|
5965
|
-
for (let i = open; i < code.length; i++) {
|
|
6029
|
+
function closingParens(code) {
|
|
6030
|
+
const close = new Int32Array(code.length).fill(-1);
|
|
6031
|
+
const open = [];
|
|
6032
|
+
for (let i = 0; i < code.length; i++) {
|
|
5966
6033
|
const c = code[i];
|
|
5967
6034
|
if (c === "(")
|
|
5968
|
-
|
|
5969
|
-
else if (c === ")" &&
|
|
5970
|
-
|
|
6035
|
+
open.push(i);
|
|
6036
|
+
else if (c === ")" && open.length > 0)
|
|
6037
|
+
close[open.pop()] = i;
|
|
5971
6038
|
}
|
|
5972
|
-
return
|
|
6039
|
+
return close;
|
|
6040
|
+
}
|
|
6041
|
+
function balancedCall(code, close, start) {
|
|
6042
|
+
const open = code.indexOf("(", start);
|
|
6043
|
+
if (open < 0 || close[open] < 0)
|
|
6044
|
+
return null;
|
|
6045
|
+
return { inner: code.slice(open + 1, close[open]), end: close[open] };
|
|
5973
6046
|
}
|
|
5974
6047
|
function resolveLocator(code, subject) {
|
|
5975
6048
|
const id = subject.trim().match(/^([A-Za-z_$][\w$]*)$/);
|
|
@@ -6017,8 +6090,10 @@ function isAuthHandoffDismissCode(code) {
|
|
|
6017
6090
|
const expects = [];
|
|
6018
6091
|
const re = new RegExp(EXPECT_CALL_RE.source, "g");
|
|
6019
6092
|
let match;
|
|
6093
|
+
let close = null;
|
|
6020
6094
|
while (match = re.exec(body)) {
|
|
6021
|
-
|
|
6095
|
+
close ??= closingParens(body);
|
|
6096
|
+
const found = balancedCall(body, close, match.index);
|
|
6022
6097
|
if (found)
|
|
6023
6098
|
expects.push({ inner: found.inner, tail: body.slice(found.end, found.end + 48) });
|
|
6024
6099
|
}
|
|
@@ -6063,12 +6138,209 @@ var init_auth_handoff_coverage = __esm({
|
|
|
6063
6138
|
}
|
|
6064
6139
|
});
|
|
6065
6140
|
|
|
6141
|
+
// ../shared/dist/auth-plan.js
|
|
6142
|
+
function hasInlineLoginSteps(playwrightCode) {
|
|
6143
|
+
if (!playwrightCode)
|
|
6144
|
+
return false;
|
|
6145
|
+
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
6146
|
+
}
|
|
6147
|
+
function hasGeneratedAuthGuard(playwrightCode) {
|
|
6148
|
+
if (!playwrightCode)
|
|
6149
|
+
return false;
|
|
6150
|
+
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
6151
|
+
}
|
|
6152
|
+
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
6153
|
+
if (!sharedAuthInjectEnabled)
|
|
6154
|
+
return false;
|
|
6155
|
+
if (tags.includes("@auth"))
|
|
6156
|
+
return false;
|
|
6157
|
+
if (tags.includes("@api"))
|
|
6158
|
+
return true;
|
|
6159
|
+
if (!tags.includes("@needs-auth"))
|
|
6160
|
+
return false;
|
|
6161
|
+
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
6162
|
+
return true;
|
|
6163
|
+
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
6164
|
+
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
6165
|
+
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
6166
|
+
}
|
|
6167
|
+
function codeReadsStoredCredentials(code) {
|
|
6168
|
+
if (!code)
|
|
6169
|
+
return false;
|
|
6170
|
+
if (/__vqaLogin\b/.test(code))
|
|
6171
|
+
return true;
|
|
6172
|
+
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
6173
|
+
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
6174
|
+
return true;
|
|
6175
|
+
}
|
|
6176
|
+
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
6177
|
+
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
6178
|
+
return true;
|
|
6179
|
+
}
|
|
6180
|
+
return false;
|
|
6181
|
+
}
|
|
6182
|
+
function explicitAuthTypeTags(t) {
|
|
6183
|
+
const found = /* @__PURE__ */ new Set();
|
|
6184
|
+
for (const tag of t) {
|
|
6185
|
+
if (AUTH_TYPE_TAGS.includes(tag))
|
|
6186
|
+
found.add(tag);
|
|
6187
|
+
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
6188
|
+
found.add(AUTH_TAG_ALIASES[tag]);
|
|
6189
|
+
}
|
|
6190
|
+
return [...found];
|
|
6191
|
+
}
|
|
6192
|
+
function invalidPlan(configurationError) {
|
|
6193
|
+
return {
|
|
6194
|
+
version: 1,
|
|
6195
|
+
source: "invalid",
|
|
6196
|
+
acquisition: "unsupported",
|
|
6197
|
+
presentation: "none",
|
|
6198
|
+
needsCookieState: false,
|
|
6199
|
+
needsStandingHeaders: false,
|
|
6200
|
+
standingHeadersMode: "none",
|
|
6201
|
+
needsLoginCreds: false,
|
|
6202
|
+
requiredEnvKeys: [],
|
|
6203
|
+
configurationError
|
|
6204
|
+
};
|
|
6205
|
+
}
|
|
6206
|
+
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
6207
|
+
return {
|
|
6208
|
+
version: 1,
|
|
6209
|
+
source: "explicit",
|
|
6210
|
+
authTypeTag: authTypeTag2,
|
|
6211
|
+
acquisition,
|
|
6212
|
+
presentation,
|
|
6213
|
+
needsCookieState: opts.cookie,
|
|
6214
|
+
needsStandingHeaders: opts.standingMode === "required",
|
|
6215
|
+
standingHeadersMode: opts.standingMode,
|
|
6216
|
+
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
6217
|
+
requiredEnvKeys: opts.requiredEnvKeys
|
|
6218
|
+
};
|
|
6219
|
+
}
|
|
6220
|
+
function deriveAuthPlan(tags, code, opts) {
|
|
6221
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
6222
|
+
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
6223
|
+
const isApi = t.includes("@api");
|
|
6224
|
+
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
6225
|
+
if (explicit.length > 0) {
|
|
6226
|
+
if (t.includes("@auth")) {
|
|
6227
|
+
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
6228
|
+
}
|
|
6229
|
+
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
6230
|
+
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
6231
|
+
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
6232
|
+
switch (loginCompose[0]) {
|
|
6233
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
6234
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
6235
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
6236
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
6237
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
6238
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
if (explicit.length > 1) {
|
|
6242
|
+
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
6243
|
+
}
|
|
6244
|
+
switch (explicit[0]) {
|
|
6245
|
+
case AUTH_TAG_UNSUPPORTED:
|
|
6246
|
+
return {
|
|
6247
|
+
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
6248
|
+
};
|
|
6249
|
+
case AUTH_TAG_NONE:
|
|
6250
|
+
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
6251
|
+
case AUTH_TAG_STANDING:
|
|
6252
|
+
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
6253
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
6254
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
6255
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
6256
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
6257
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
6258
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
6259
|
+
}
|
|
6260
|
+
}
|
|
6261
|
+
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
6262
|
+
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
6263
|
+
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
6264
|
+
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
6265
|
+
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
6266
|
+
return {
|
|
6267
|
+
version: 1,
|
|
6268
|
+
source: "legacy",
|
|
6269
|
+
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
6270
|
+
presentation: authedLegacy ? "cookie" : "none",
|
|
6271
|
+
needsCookieState: cookie,
|
|
6272
|
+
needsStandingHeaders: false,
|
|
6273
|
+
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
6274
|
+
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
6275
|
+
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
6276
|
+
needsLoginCreds,
|
|
6277
|
+
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
6278
|
+
};
|
|
6279
|
+
}
|
|
6280
|
+
function authTypeTag(tags) {
|
|
6281
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
6282
|
+
const explicit = explicitAuthTypeTags(t);
|
|
6283
|
+
return explicit.length === 1 ? explicit[0] : void 0;
|
|
6284
|
+
}
|
|
6285
|
+
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;
|
|
6286
|
+
var init_auth_plan = __esm({
|
|
6287
|
+
"../shared/dist/auth-plan.js"() {
|
|
6288
|
+
"use strict";
|
|
6289
|
+
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
6290
|
+
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
6291
|
+
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
6292
|
+
AUTH_TAG_STANDING = "@auth-standing";
|
|
6293
|
+
AUTH_TAG_NONE = "@auth-none";
|
|
6294
|
+
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
6295
|
+
AUTH_TYPE_TAGS = [
|
|
6296
|
+
AUTH_TAG_COOKIE_STATE,
|
|
6297
|
+
AUTH_TAG_LOGIN_COOKIE,
|
|
6298
|
+
AUTH_TAG_LOGIN_BEARER,
|
|
6299
|
+
AUTH_TAG_STANDING,
|
|
6300
|
+
AUTH_TAG_NONE,
|
|
6301
|
+
AUTH_TAG_UNSUPPORTED
|
|
6302
|
+
];
|
|
6303
|
+
AUTH_TAG_ALIASES = {
|
|
6304
|
+
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
6305
|
+
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
6306
|
+
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
6307
|
+
"@auth-api-key": AUTH_TAG_STANDING,
|
|
6308
|
+
"@auth-standing-header": AUTH_TAG_STANDING
|
|
6309
|
+
};
|
|
6310
|
+
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
6311
|
+
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
6312
|
+
}
|
|
6313
|
+
});
|
|
6314
|
+
|
|
6066
6315
|
// ../shared/dist/assertion-strength.js
|
|
6316
|
+
function parseLastActionProofMode(raw) {
|
|
6317
|
+
const v = (raw ?? "").trim().toLowerCase();
|
|
6318
|
+
return v === "on" || v === "shadow" ? v : "off";
|
|
6319
|
+
}
|
|
6320
|
+
function isUrlProof(stmt) {
|
|
6321
|
+
if (URL_PROOF.test(stmt))
|
|
6322
|
+
return true;
|
|
6323
|
+
let calls = 0;
|
|
6324
|
+
for (const open of stmt.matchAll(POLL_OPEN)) {
|
|
6325
|
+
if (++calls > POLL_CALLS_MAX)
|
|
6326
|
+
break;
|
|
6327
|
+
const from = open.index + open[0].length;
|
|
6328
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
6329
|
+
if (args === null)
|
|
6330
|
+
continue;
|
|
6331
|
+
const subject = pollSubject(args);
|
|
6332
|
+
if (!POLL_PAGE_URL.test(subject))
|
|
6333
|
+
continue;
|
|
6334
|
+
if (!POLL_PAGE_URL_ONLY.test(subject) || PAGE_VALUE_MATCHER.test(stmt.slice(from + args.length)))
|
|
6335
|
+
return true;
|
|
6336
|
+
}
|
|
6337
|
+
return false;
|
|
6338
|
+
}
|
|
6067
6339
|
function liveExpectStatements(uncommented) {
|
|
6068
6340
|
const masked = maskedOutsideStrings(uncommented).split("\n");
|
|
6069
6341
|
return accumulateStatements(uncommented.split("\n")).filter((s) => EXPECT_STMT.test(s.stmt) && EXPECT_STMT.test(masked[s.startLine - 1] ?? ""));
|
|
6070
6342
|
}
|
|
6071
|
-
function
|
|
6343
|
+
function stripLineComment2(ln) {
|
|
6072
6344
|
let quote = null;
|
|
6073
6345
|
for (let i = 0; i < ln.length; i++) {
|
|
6074
6346
|
const c = ln[i];
|
|
@@ -6091,7 +6363,7 @@ function splitInteractionStatementsWithLines(lines) {
|
|
|
6091
6363
|
let depth = 0;
|
|
6092
6364
|
let scaffold = false;
|
|
6093
6365
|
for (let i = 0; i < lines.length; i++) {
|
|
6094
|
-
const ln =
|
|
6366
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
6095
6367
|
if (!ln)
|
|
6096
6368
|
continue;
|
|
6097
6369
|
const isContinuation = out.length > 0 && (ln.startsWith(".") || depth > 0 && !scaffold);
|
|
@@ -6115,7 +6387,7 @@ function testBlockIds(lines) {
|
|
|
6115
6387
|
let any = false;
|
|
6116
6388
|
let block = 0;
|
|
6117
6389
|
for (let i = 0; i < lines.length; i++) {
|
|
6118
|
-
const ln =
|
|
6390
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
6119
6391
|
if (!open) {
|
|
6120
6392
|
if (!TEST_BLOCK_OPEN.test(ln))
|
|
6121
6393
|
continue;
|
|
@@ -6199,7 +6471,7 @@ function expectSubjectSpan(stmt) {
|
|
|
6199
6471
|
}
|
|
6200
6472
|
return null;
|
|
6201
6473
|
}
|
|
6202
|
-
function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
6474
|
+
function resolveSubjectBindings(stmts, bindings, blockOfLine, boundAt) {
|
|
6203
6475
|
if (bindings.length === 0)
|
|
6204
6476
|
return [...stmts];
|
|
6205
6477
|
return stmts.map((item) => {
|
|
@@ -6222,14 +6494,22 @@ function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
|
6222
6494
|
subject = `${lead[1]}${found.expr.replace(/;\s*$/, "")}${subject.slice(lead[0].length)}`;
|
|
6223
6495
|
line = found.line;
|
|
6224
6496
|
}
|
|
6225
|
-
|
|
6497
|
+
const out = { ...item, stmt: `${item.stmt.slice(0, span.from)}${subject}${item.stmt.slice(span.to)}` };
|
|
6498
|
+
if (boundAt !== void 0 && line !== item.startLine)
|
|
6499
|
+
boundAt.set(out, line);
|
|
6500
|
+
return out;
|
|
6226
6501
|
});
|
|
6227
6502
|
}
|
|
6228
6503
|
function stripLoginScaffolding(code) {
|
|
6229
|
-
const
|
|
6504
|
+
const lines = code.split("\n");
|
|
6505
|
+
return keptScaffoldingLines(lines).map((i) => lines[i]).join("\n");
|
|
6506
|
+
}
|
|
6507
|
+
function keptScaffoldingLines(lines) {
|
|
6508
|
+
const kept = [];
|
|
6230
6509
|
let inAuth = false;
|
|
6231
6510
|
let inInbox = false;
|
|
6232
|
-
for (
|
|
6511
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6512
|
+
const ln = lines[i];
|
|
6233
6513
|
if (!inAuth && !inInbox && AUTH_START.test(ln)) {
|
|
6234
6514
|
inAuth = true;
|
|
6235
6515
|
continue;
|
|
@@ -6250,9 +6530,9 @@ function stripLoginScaffolding(code) {
|
|
|
6250
6530
|
}
|
|
6251
6531
|
if (LOGIN_CALL_LINE.test(ln))
|
|
6252
6532
|
continue;
|
|
6253
|
-
|
|
6533
|
+
kept.push(i);
|
|
6254
6534
|
}
|
|
6255
|
-
return
|
|
6535
|
+
return kept;
|
|
6256
6536
|
}
|
|
6257
6537
|
function stripCommentsAndLogs(code) {
|
|
6258
6538
|
return stripCoverageComments(code).split("\n").filter((ln) => !/^\s*console\./.test(ln)).join("\n");
|
|
@@ -6404,6 +6684,41 @@ function isVacuousErrorAbsence(stmt, presence) {
|
|
|
6404
6684
|
return false;
|
|
6405
6685
|
return !presence().includes(m[1]);
|
|
6406
6686
|
}
|
|
6687
|
+
function isVacuousAccountAbsence(stmt, shown, account) {
|
|
6688
|
+
if (!claimsAbsence(stmt))
|
|
6689
|
+
return false;
|
|
6690
|
+
if (!ABSENCE_MATCHER.test(stmt)) {
|
|
6691
|
+
const negated = NEGATED_TEXT.exec(stmt);
|
|
6692
|
+
if (!negated)
|
|
6693
|
+
return false;
|
|
6694
|
+
const read = account.exec(stmt.slice(negated.index));
|
|
6695
|
+
return read !== null && !shown().has(read[0]);
|
|
6696
|
+
}
|
|
6697
|
+
const m = account.exec(stmt);
|
|
6698
|
+
if (!m || shown().has(m[0]))
|
|
6699
|
+
return false;
|
|
6700
|
+
for (let at = endOfEnclosingCall(stmt, m.index + m[0].length); at < stmt.length; at = endOfEnclosingCall(stmt, at)) {
|
|
6701
|
+
SCOPING_STEP.lastIndex = at;
|
|
6702
|
+
if (SCOPING_STEP.test(stmt))
|
|
6703
|
+
return false;
|
|
6704
|
+
}
|
|
6705
|
+
return true;
|
|
6706
|
+
}
|
|
6707
|
+
function endOfEnclosingCall(stmt, from) {
|
|
6708
|
+
let depth = 0;
|
|
6709
|
+
for (let i = from; i < stmt.length; i++) {
|
|
6710
|
+
const c = stmt[i];
|
|
6711
|
+
if (c === "'" || c === '"') {
|
|
6712
|
+
for (i++; i < stmt.length && stmt[i] !== c; i++)
|
|
6713
|
+
if (stmt[i] === "\\")
|
|
6714
|
+
i++;
|
|
6715
|
+
} else if (c === "(")
|
|
6716
|
+
depth++;
|
|
6717
|
+
else if (c === ")" && depth-- === 0)
|
|
6718
|
+
return i + 1;
|
|
6719
|
+
}
|
|
6720
|
+
return stmt.length;
|
|
6721
|
+
}
|
|
6407
6722
|
function isBareContainerVisibility(stmt) {
|
|
6408
6723
|
return BARE_CONTAINER_ROLE.test(stmt) && !GET_BY_TEXT.test(stmt) && !HAS_TEXT_FILTER.test(stmt) && !TEXT_CONTENT_MATCHER.test(stmt);
|
|
6409
6724
|
}
|
|
@@ -6485,7 +6800,7 @@ function roleNames(s) {
|
|
|
6485
6800
|
function interactedControlNames(lines) {
|
|
6486
6801
|
const names = /* @__PURE__ */ new Set();
|
|
6487
6802
|
for (const raw of lines) {
|
|
6488
|
-
const ln =
|
|
6803
|
+
const ln = stripLineComment2(raw);
|
|
6489
6804
|
if (!INTERACT_VERB.test(ln))
|
|
6490
6805
|
continue;
|
|
6491
6806
|
for (const n of roleNames(ln))
|
|
@@ -6681,6 +6996,14 @@ function balancedArguments(code, from, limit = code.length) {
|
|
|
6681
6996
|
}
|
|
6682
6997
|
return null;
|
|
6683
6998
|
}
|
|
6999
|
+
function expectCallTail(stmt) {
|
|
7000
|
+
const at = stmt.search(EXPECT_CALL_RE);
|
|
7001
|
+
if (at < 0)
|
|
7002
|
+
return null;
|
|
7003
|
+
const from = stmt.indexOf("(", at) + 1;
|
|
7004
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
7005
|
+
return args === null ? null : stmt.slice(from + args.length).trimStart();
|
|
7006
|
+
}
|
|
6684
7007
|
function matcherArgumentsAreConstant(body, from) {
|
|
6685
7008
|
MATCHER_OPEN.lastIndex = from;
|
|
6686
7009
|
const opened = MATCHER_OPEN.exec(body);
|
|
@@ -6722,9 +7045,12 @@ function envValueKey(name) {
|
|
|
6722
7045
|
function enteredValues(stmts) {
|
|
6723
7046
|
const values = /* @__PURE__ */ new Map();
|
|
6724
7047
|
const navLines = [];
|
|
7048
|
+
const accountConsts = /* @__PURE__ */ new Set();
|
|
6725
7049
|
for (const { stmt, startLine } of stmts) {
|
|
6726
7050
|
if (PAGE_NAV.test(stmt))
|
|
6727
7051
|
navLines.push(startLine);
|
|
7052
|
+
for (const c of stmt.matchAll(ACCOUNT_CONST))
|
|
7053
|
+
accountConsts.add(c[1].replace(/\$/g, "\\$"));
|
|
6728
7054
|
let m;
|
|
6729
7055
|
ENTERED_VALUE.lastIndex = 0;
|
|
6730
7056
|
const add = (value) => {
|
|
@@ -6740,7 +7066,8 @@ function enteredValues(stmts) {
|
|
|
6740
7066
|
while (m = ENTERED_ENV.exec(stmt))
|
|
6741
7067
|
add(envValueKey(m[1] ?? m[2] ?? m[3] ?? m[4]));
|
|
6742
7068
|
}
|
|
6743
|
-
|
|
7069
|
+
const consts = accountConsts.size > 0 ? `|(?<![\\w$.])(?:${[...accountConsts].join("|")})(?![\\w$])` : "";
|
|
7070
|
+
return { values, navLines, account: new RegExp(`${ACCOUNT_ENV}${consts}`) };
|
|
6744
7071
|
}
|
|
6745
7072
|
function countBelow(lines, line) {
|
|
6746
7073
|
let lo = 0;
|
|
@@ -6877,6 +7204,9 @@ function comparesWithItself(subject, tail) {
|
|
|
6877
7204
|
return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
|
|
6878
7205
|
}
|
|
6879
7206
|
function asPlainAssertion(s) {
|
|
7207
|
+
return plainAssertion(s, false);
|
|
7208
|
+
}
|
|
7209
|
+
function plainAssertion(s, keepSelfCompare) {
|
|
6880
7210
|
const { stmt } = s;
|
|
6881
7211
|
if (COUNT_AT_LEAST_ZERO.test(stmt))
|
|
6882
7212
|
return [];
|
|
@@ -6885,13 +7215,13 @@ function asPlainAssertion(s) {
|
|
|
6885
7215
|
return [s];
|
|
6886
7216
|
const plain = subject.replace(/^await\s+/, "").trim();
|
|
6887
7217
|
const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
|
|
6888
|
-
const tail = stmt.slice(subjectAt + subject.length).trimStart();
|
|
7218
|
+
const tail = (stmt.startsWith("expect.poll", stmt.search(EXPECT_CALL_RE)) ? expectCallTail(stmt) : null) ?? stmt.slice(subjectAt + subject.length).trimStart();
|
|
6889
7219
|
const as = (rewritten) => [{ ...s, stmt: rewritten }];
|
|
6890
7220
|
if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
|
|
6891
7221
|
return [];
|
|
6892
7222
|
if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
|
|
6893
7223
|
return [];
|
|
6894
|
-
if (comparesWithItself(plain, tail))
|
|
7224
|
+
if (!keepSelfCompare && comparesWithItself(plain, tail))
|
|
6895
7225
|
return [];
|
|
6896
7226
|
const visible = /^(.+)\.\s*isVisible\s*\(\s*\)$/s.exec(plain);
|
|
6897
7227
|
if (visible && IS_VISIBLE_TRUE.test(tail))
|
|
@@ -6902,6 +7232,9 @@ function asPlainAssertion(s) {
|
|
|
6902
7232
|
}
|
|
6903
7233
|
return [s];
|
|
6904
7234
|
}
|
|
7235
|
+
function assertionStrengthHoistedReadsOn(value = typeof process !== "undefined" ? process.env?.ASSERTION_STRENGTH_HOISTED_READS : void 0) {
|
|
7236
|
+
return /^(1|true|on)$/i.test((value ?? "").trim());
|
|
7237
|
+
}
|
|
6905
7238
|
function creditsOutcomeAlways(stmt, entered, startLine) {
|
|
6906
7239
|
if (!OUTCOME_ALWAYS.some((re) => re.test(stmt)))
|
|
6907
7240
|
return false;
|
|
@@ -6934,6 +7267,22 @@ function successNoticeQuote(stmt) {
|
|
|
6934
7267
|
}
|
|
6935
7268
|
return null;
|
|
6936
7269
|
}
|
|
7270
|
+
function namedPagePath(arg) {
|
|
7271
|
+
const text = arg.trim();
|
|
7272
|
+
let path;
|
|
7273
|
+
const quoted = /^(['"`])([^'"`]*)\1$/.exec(text);
|
|
7274
|
+
const regex = quoted ? null : /^\/((?:\\.|[^/\\])+)\/[a-z]*$/.exec(text);
|
|
7275
|
+
if (quoted) {
|
|
7276
|
+
path = quoted[2].replace(/^\$\{[^}]*\}/, "").replace(/^\*\*/, "").replace(/^[a-z][a-z\d+.-]*:\/\/[^/]*/i, "").replace(/\/\*\*$/, "/");
|
|
7277
|
+
} else if (regex) {
|
|
7278
|
+
path = regex[1].replace(/^\^/, "").replace(/^\.\*/, "").replace(/\$$/, "").replace(/\\([/.-])/g, "$1");
|
|
7279
|
+
} else {
|
|
7280
|
+
return null;
|
|
7281
|
+
}
|
|
7282
|
+
if (!PLAIN_PAGE_PATH.test(path))
|
|
7283
|
+
return null;
|
|
7284
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
7285
|
+
}
|
|
6937
7286
|
function provesStoredControlValue(stmt, startLine, persistence) {
|
|
6938
7287
|
if (!persistence || startLine === void 0)
|
|
6939
7288
|
return false;
|
|
@@ -6960,16 +7309,80 @@ function reopenedAfterSave(startLine, persistence, reopens = persistence.reloadL
|
|
|
6960
7309
|
}
|
|
6961
7310
|
return lo < reopens.length && reopens[lo] < startLine;
|
|
6962
7311
|
}
|
|
6963
|
-
function
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
7312
|
+
function actsBetween(withLines, from, to) {
|
|
7313
|
+
let acts = actLinesOf.get(withLines);
|
|
7314
|
+
if (acts === void 0) {
|
|
7315
|
+
acts = withLines.filter((s) => ACTS.test(s.stmt)).map((s) => s.startLine).sort((a, b) => a - b);
|
|
7316
|
+
actLinesOf.set(withLines, acts);
|
|
7317
|
+
}
|
|
7318
|
+
let lo = 0;
|
|
7319
|
+
let hi = acts.length;
|
|
7320
|
+
while (lo < hi) {
|
|
7321
|
+
const mid = lo + hi >> 1;
|
|
7322
|
+
if (acts[mid] <= from)
|
|
7323
|
+
lo = mid + 1;
|
|
7324
|
+
else
|
|
7325
|
+
hi = mid;
|
|
7326
|
+
}
|
|
7327
|
+
return lo < acts.length && acts[lo] < to;
|
|
7328
|
+
}
|
|
7329
|
+
function signInProofWindow(stmts, withLines, lines, blockIds) {
|
|
7330
|
+
if (blockIds === null)
|
|
7331
|
+
return void 0;
|
|
7332
|
+
const testBodies2 = /* @__PURE__ */ new Set();
|
|
7333
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7334
|
+
const id = blockIds[i];
|
|
7335
|
+
if (id > 0 && (i === 0 || blockIds[i - 1] !== id) && TEST_BODY_OPEN.test(stripLineComment2(lines[i]).trim()))
|
|
7336
|
+
testBodies2.add(id);
|
|
7337
|
+
}
|
|
7338
|
+
const blockOf = (i) => blockIds[withLines[i].startLine - 1];
|
|
7339
|
+
const passwordAt = stmts.findIndex((stmt, i) => testBodies2.has(blockOf(i)) && ENV_PASSWORD_ENTRY.test(stmt));
|
|
7340
|
+
if (passwordAt < 0)
|
|
7341
|
+
return void 0;
|
|
7342
|
+
const body = blockOf(passwordAt);
|
|
7343
|
+
let clickAt = passwordAt + 1;
|
|
7344
|
+
while (clickAt < stmts.length && FORM_INPUT.test(stmts[clickAt]) && !ANY_CLICK.test(stmts[clickAt]))
|
|
7345
|
+
clickAt++;
|
|
7346
|
+
if (clickAt >= stmts.length || blockOf(clickAt) !== body || !ANY_CLICK.test(stmts[clickAt]) || NAV_LOCATOR.test(stmts[clickAt]))
|
|
7347
|
+
return void 0;
|
|
7348
|
+
let end = clickAt + 1;
|
|
7349
|
+
for (; end < stmts.length && blockOf(end) === body; end++) {
|
|
7350
|
+
if (CLOSERS_ONLY.test(stmts[end]))
|
|
7351
|
+
continue;
|
|
7352
|
+
if (!ASSERT_OR_WAIT.test(stmts[end]) || ACTS.test(stmts[end]))
|
|
7353
|
+
return void 0;
|
|
7354
|
+
}
|
|
7355
|
+
return { after: withLines[clickAt].startLine, until: end < stmts.length ? withLines[end].startLine : Number.POSITIVE_INFINITY };
|
|
7356
|
+
}
|
|
7357
|
+
function isAccountControlCheck(stmt) {
|
|
7358
|
+
if (!VISIBILITY_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt) || OPTION_ABSENCE.test(stmt))
|
|
7359
|
+
return false;
|
|
7360
|
+
const role = ACCOUNT_CONTROL_ROLE.exec(stmt);
|
|
7361
|
+
if (!role)
|
|
7362
|
+
return false;
|
|
7363
|
+
const rest = stmt.slice(role.index + role[0].length, role.index + role[0].length + 300);
|
|
7364
|
+
const close = rest.indexOf("}");
|
|
7365
|
+
const options = close < 0 ? rest : rest.slice(0, close);
|
|
7366
|
+
const name = options.match(/(?:^|[\s,])name\s*:\s*/);
|
|
7367
|
+
return name !== null && ACCOUNT_EMAIL_ENV.test(options.slice(name.index + name[0].length));
|
|
7368
|
+
}
|
|
7369
|
+
function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine, persistence, signedIn) {
|
|
7370
|
+
if (mutated && hasAttributeTransition(stmts))
|
|
7371
|
+
return { kind: "durable" };
|
|
7372
|
+
const notices = [];
|
|
7373
|
+
const note = (text) => {
|
|
7374
|
+
if (notices.length === 0)
|
|
7375
|
+
notices.push(text);
|
|
7376
|
+
};
|
|
7377
|
+
let presenceText;
|
|
7378
|
+
const presence = () => presenceText ??= stmts.filter((o) => !ABSENCE_MATCHER.test(o.stmt) && !NEGATED_ASSERT.test(o.stmt)).map((o) => o.stmt).join("\n");
|
|
7379
|
+
let shownAccounts;
|
|
7380
|
+
const shown = () => {
|
|
7381
|
+
if (shownAccounts)
|
|
7382
|
+
return shownAccounts;
|
|
7383
|
+
const ref = new RegExp(entered.account.source, "g");
|
|
7384
|
+
return shownAccounts = new Set(stmts.filter((o) => !claimsAbsence(o.stmt)).flatMap((o) => Array.from(o.stmt.matchAll(ref), (m) => m[0])));
|
|
7385
|
+
};
|
|
6973
7386
|
for (const { stmt, startLine } of stmts) {
|
|
6974
7387
|
if (firstMutLine !== void 0 && startLine !== void 0 && startLine < firstMutLine)
|
|
6975
7388
|
continue;
|
|
@@ -6977,6 +7390,11 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
6977
7390
|
continue;
|
|
6978
7391
|
if (COUNT_ONE.test(stmt) && quotedAssertedStrings(stmt).some((t) => clicked.has(t.toLowerCase())))
|
|
6979
7392
|
continue;
|
|
7393
|
+
if (isVacuousAccountAbsence(stmt, shown, entered.account))
|
|
7394
|
+
continue;
|
|
7395
|
+
if (signedIn && startLine !== void 0 && startLine > signedIn.after && startLine < signedIn.until && isAccountControlCheck(stmt)) {
|
|
7396
|
+
return { kind: "durable" };
|
|
7397
|
+
}
|
|
6980
7398
|
if (creditsOutcomeAlways(stmt, entered, startLine))
|
|
6981
7399
|
return { kind: "durable" };
|
|
6982
7400
|
if (mutated && !NEGATED_ASSERT.test(stmt) && MESSAGE_SURFACE.test(stmt) && OUTCOME_TEXT.test(assertedText(stmt))) {
|
|
@@ -7058,6 +7476,53 @@ function noticeOnlyExemption(clicked, noticeText, interactionStmts) {
|
|
|
7058
7476
|
function detectOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine) {
|
|
7059
7477
|
return classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine).kind !== "none";
|
|
7060
7478
|
}
|
|
7479
|
+
function clickLabel(stmt) {
|
|
7480
|
+
let label = null;
|
|
7481
|
+
for (const m of stmt.matchAll(CONTROL_LABEL))
|
|
7482
|
+
label = m[2] ?? m[3] ?? null;
|
|
7483
|
+
return label;
|
|
7484
|
+
}
|
|
7485
|
+
function teardownLines(lines) {
|
|
7486
|
+
const out = new Array(lines.length).fill(false);
|
|
7487
|
+
let open = false;
|
|
7488
|
+
let depth = 0;
|
|
7489
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7490
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
7491
|
+
let from = 0;
|
|
7492
|
+
if (!open) {
|
|
7493
|
+
const m = TEARDOWN_OPEN.exec(ln);
|
|
7494
|
+
if (!m)
|
|
7495
|
+
continue;
|
|
7496
|
+
open = true;
|
|
7497
|
+
depth = 0;
|
|
7498
|
+
from = m.index;
|
|
7499
|
+
}
|
|
7500
|
+
out[i] = true;
|
|
7501
|
+
let closed = false;
|
|
7502
|
+
let quote = null;
|
|
7503
|
+
for (let k = from; k < ln.length; k++) {
|
|
7504
|
+
const ch = ln[k];
|
|
7505
|
+
if (quote !== null) {
|
|
7506
|
+
if (ch === "\\")
|
|
7507
|
+
k++;
|
|
7508
|
+
else if (ch === quote)
|
|
7509
|
+
quote = null;
|
|
7510
|
+
continue;
|
|
7511
|
+
}
|
|
7512
|
+
if (ch === "'" || ch === '"' || ch === "`")
|
|
7513
|
+
quote = ch;
|
|
7514
|
+
else if (ch === "{")
|
|
7515
|
+
depth++;
|
|
7516
|
+
else if (ch === "}") {
|
|
7517
|
+
depth--;
|
|
7518
|
+
closed = true;
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
if (depth <= 0 && closed)
|
|
7522
|
+
open = false;
|
|
7523
|
+
}
|
|
7524
|
+
return out;
|
|
7525
|
+
}
|
|
7061
7526
|
function validateAssertionStrength(code, opts = {}) {
|
|
7062
7527
|
const body = stripLoginScaffolding(code);
|
|
7063
7528
|
const lines = body.split("\n");
|
|
@@ -7101,7 +7566,13 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7101
7566
|
const interactionStmts = inlineLocatorBindings(interactionStmtsRaw);
|
|
7102
7567
|
const blockIds = testBlockIds(lines);
|
|
7103
7568
|
const blockOfLine = (line) => blockIds?.[line - 1] ?? 0;
|
|
7104
|
-
const
|
|
7569
|
+
const hoistedReads = assertionStrengthHoistedReadsOn();
|
|
7570
|
+
const boundAt = hoistedReads ? /* @__PURE__ */ new Map() : void 0;
|
|
7571
|
+
const resolved = resolveSubjectBindings(stmts, scopedLocatorBindings(interactionStmtsWithLines, blockOfLine), blockOfLine, boundAt);
|
|
7572
|
+
const checks = boundAt === void 0 ? resolved : resolved.flatMap((s) => {
|
|
7573
|
+
const from = boundAt.get(s);
|
|
7574
|
+
return plainAssertion(s, from !== void 0 && actsBetween(interactionStmtsWithLines, from, s.startLine));
|
|
7575
|
+
});
|
|
7105
7576
|
const insideTest = linesInsideTestBlocks(lines);
|
|
7106
7577
|
const inTestOrder = (i) => insideTest === null || insideTest[interactionStmtsWithLines[i].startLine - 1] === true;
|
|
7107
7578
|
let mutated = opts.interactionPerformed === true;
|
|
@@ -7111,9 +7582,34 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7111
7582
|
let navClicks = 0;
|
|
7112
7583
|
const persistence = { mutLines: [], reloadLines: [], reloadCalls: [] };
|
|
7113
7584
|
const openedPages = /* @__PURE__ */ new Set();
|
|
7585
|
+
let checkedPage = null;
|
|
7586
|
+
const savedOnCheckedPage = /* @__PURE__ */ new Set();
|
|
7587
|
+
const saveAt = (i, at) => {
|
|
7588
|
+
lastMutIdx = i;
|
|
7589
|
+
if (!inTestOrder(i))
|
|
7590
|
+
return;
|
|
7591
|
+
persistence.mutLines.push(at);
|
|
7592
|
+
if (firstMutIdx < 0)
|
|
7593
|
+
firstMutIdx = i;
|
|
7594
|
+
if (checkedPage !== null)
|
|
7595
|
+
savedOnCheckedPage.add(checkedPage);
|
|
7596
|
+
};
|
|
7597
|
+
const lastActionProof = opts.lastActionProof ?? "off";
|
|
7598
|
+
const teardown = lastActionProof === "off" ? null : teardownLines(lines);
|
|
7599
|
+
const acts = { last: null, prev: null, count: 0 };
|
|
7600
|
+
const noteAct = (i, at, kind) => {
|
|
7601
|
+
if (teardown === null || teardown[at - 1] || !inTestOrder(i))
|
|
7602
|
+
return;
|
|
7603
|
+
if (kind !== "enter")
|
|
7604
|
+
acts.count++;
|
|
7605
|
+
acts.prev = acts.last;
|
|
7606
|
+
acts.last = { i, kind };
|
|
7607
|
+
};
|
|
7114
7608
|
for (let i = 0; i < interactionStmts.length; i++) {
|
|
7115
7609
|
const ln = interactionStmts[i];
|
|
7116
7610
|
const at = interactionStmtsWithLines[i].startLine;
|
|
7611
|
+
if (teardown !== null && acts.last?.kind === "fill" && ENTER_PRESS.test(ln))
|
|
7612
|
+
noteAct(i, at, "enter");
|
|
7117
7613
|
if (RELOAD.test(ln)) {
|
|
7118
7614
|
persistence.reloadLines.push(at);
|
|
7119
7615
|
persistence.reloadCalls.push(at);
|
|
@@ -7121,32 +7617,31 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7121
7617
|
const opened = ln.match(/\.goto\s*\(\s*([^,)]+)/);
|
|
7122
7618
|
if (opened) {
|
|
7123
7619
|
const page = opened[1].trim();
|
|
7124
|
-
|
|
7620
|
+
const path = namedPagePath(page);
|
|
7621
|
+
if (openedPages.has(page) || path !== null && savedOnCheckedPage.has(path))
|
|
7125
7622
|
persistence.reloadLines.push(at);
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
}
|
|
7623
|
+
openedPages.add(page);
|
|
7624
|
+
checkedPage = null;
|
|
7625
|
+
}
|
|
7626
|
+
if (/\bpage\s*\.\s*go(?:Back|Forward)\s*\(/.test(ln))
|
|
7627
|
+
checkedPage = null;
|
|
7628
|
+
const checked = URL_CHECK_ARG.exec(ln);
|
|
7629
|
+
if (checked)
|
|
7630
|
+
checkedPage = namedPagePath(checked[1] ?? checked[2]);
|
|
7129
7631
|
if (FORM_INPUT.test(ln)) {
|
|
7130
7632
|
mutated = true;
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
persistence.mutLines.push(at);
|
|
7134
|
-
if (firstMutIdx < 0)
|
|
7135
|
-
firstMutIdx = i;
|
|
7136
|
-
}
|
|
7633
|
+
saveAt(i, at);
|
|
7634
|
+
noteAct(i, at, "fill");
|
|
7137
7635
|
continue;
|
|
7138
7636
|
}
|
|
7139
7637
|
if (ANY_CLICK.test(ln)) {
|
|
7140
7638
|
if (NAV_LOCATOR.test(ln)) {
|
|
7141
7639
|
navClicks++;
|
|
7640
|
+
checkedPage = null;
|
|
7142
7641
|
} else {
|
|
7143
7642
|
mutated = true;
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
persistence.mutLines.push(at);
|
|
7147
|
-
if (firstMutIdx < 0)
|
|
7148
|
-
firstMutIdx = i;
|
|
7149
|
-
}
|
|
7643
|
+
saveAt(i, at);
|
|
7644
|
+
noteAct(i, at, "click");
|
|
7150
7645
|
}
|
|
7151
7646
|
}
|
|
7152
7647
|
}
|
|
@@ -7179,9 +7674,28 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7179
7674
|
};
|
|
7180
7675
|
}
|
|
7181
7676
|
const orderedPersistence = firstMutLine !== void 0 ? persistence : void 0;
|
|
7182
|
-
const
|
|
7677
|
+
const signedIn = signInProofWindow(interactionStmts, interactionStmtsWithLines, lines, blockIds);
|
|
7678
|
+
const proof = classifyOutcomeProof(checks, mutated, reloaded, clickedControlNames(interactionStmts), entered, firstMutLine, orderedPersistence, signedIn);
|
|
7183
7679
|
if (proof.kind === "durable") {
|
|
7184
7680
|
const signals2 = base({ interacted, mutated, navOnly, hasOutcomeProof: true, terminal });
|
|
7681
|
+
const { last, prev } = acts;
|
|
7682
|
+
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])))) {
|
|
7683
|
+
const lastLine = interactionStmtsWithLines[last.i].startLine;
|
|
7684
|
+
const clicked = clickedControlNames(interactionStmts);
|
|
7685
|
+
const after = classifyOutcomeProof(checks, mutated, reloaded, clicked, entered, lastLine, orderedPersistence, signedIn);
|
|
7686
|
+
const unproven = after.kind === "none" || after.kind === "notice" && noticeOnlyExemption(clicked, after.noticeText, interactionStmts) === null;
|
|
7687
|
+
if (unproven && lastActionProof === "on") {
|
|
7688
|
+
const line = (keptScaffoldingLines(code.split("\n"))[lastLine - 1] ?? lastLine - 1) + 1;
|
|
7689
|
+
return {
|
|
7690
|
+
ok: false,
|
|
7691
|
+
severity: "block",
|
|
7692
|
+
reason: `the last save (line ${line}) has no outcome check after it (the earlier check proves only the earlier action)`,
|
|
7693
|
+
signals: { ...signals2, lastActionUnproven: true }
|
|
7694
|
+
};
|
|
7695
|
+
}
|
|
7696
|
+
if (unproven)
|
|
7697
|
+
signals2.lastActionUnproven = true;
|
|
7698
|
+
}
|
|
7185
7699
|
return { ok: true, severity: "none", reason: "proves an outcome (count / diff / value / revealed content)", signals: signals2 };
|
|
7186
7700
|
}
|
|
7187
7701
|
if (mutated && proof.kind === "notice") {
|
|
@@ -7230,7 +7744,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7230
7744
|
signals
|
|
7231
7745
|
};
|
|
7232
7746
|
}
|
|
7233
|
-
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx &&
|
|
7747
|
+
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx && isUrlProof(s));
|
|
7234
7748
|
if (urlProofAfter) {
|
|
7235
7749
|
return {
|
|
7236
7750
|
ok: false,
|
|
@@ -7267,7 +7781,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7267
7781
|
signals
|
|
7268
7782
|
};
|
|
7269
7783
|
}
|
|
7270
|
-
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;
|
|
7784
|
+
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;
|
|
7271
7785
|
var init_assertion_strength = __esm({
|
|
7272
7786
|
"../shared/dist/assertion-strength.js"() {
|
|
7273
7787
|
"use strict";
|
|
@@ -7276,6 +7790,7 @@ var init_assertion_strength = __esm({
|
|
|
7276
7790
|
init_assertion_proof();
|
|
7277
7791
|
init_auth_handoff_coverage();
|
|
7278
7792
|
init_expect_call();
|
|
7793
|
+
init_auth_plan();
|
|
7279
7794
|
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;
|
|
7280
7795
|
OUTCOME_ALWAYS = [
|
|
7281
7796
|
/\.toHaveCount\s*\(/,
|
|
@@ -7292,7 +7807,7 @@ var init_assertion_strength = __esm({
|
|
|
7292
7807
|
// form field value
|
|
7293
7808
|
/\.toMatch\s*\(/,
|
|
7294
7809
|
// string/regex content match (e.g. textContent() vs /[2-9] selected/)
|
|
7295
|
-
|
|
7810
|
+
/\.(?<!\.not\s*\.)\s*toBeDisabled\s*\(/,
|
|
7296
7811
|
// a control became DISABLED — a gating/validation outcome (not.toBeDisabled is the toBeEnabled twin)
|
|
7297
7812
|
/\.not\.toBeVisible\s*\(/,
|
|
7298
7813
|
/\.toBeHidden\s*\(/
|
|
@@ -7301,12 +7816,16 @@ var init_assertion_strength = __esm({
|
|
|
7301
7816
|
FORM_INPUT = /\.(fill|selectOption|setInputFiles|check|uncheck|setChecked|pressSequentially)\s*\(|keyboard\.type\s*\(/;
|
|
7302
7817
|
ANY_CLICK = /\.click\s*\(/;
|
|
7303
7818
|
NAV_LOCATOR = /getByRole\s*\(\s*['"`](?:link|menuitem)['"`]/i;
|
|
7304
|
-
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(|\bexpect\s*\(\s*(?:await\s+)?page\s*\.\s*url\s*\(\s*\)\s*\)
|
|
7819
|
+
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*\(/;
|
|
7820
|
+
POLL_OPEN = /\bexpect\s*\.\s*poll\s*\(/g;
|
|
7821
|
+
POLL_PAGE_URL = /^page\s*\.\s*url\s*\(\s*\)/;
|
|
7822
|
+
POLL_PAGE_URL_ONLY = /^page\s*\.\s*url\s*\(\s*\)$/;
|
|
7823
|
+
POLL_CALLS_MAX = 8;
|
|
7305
7824
|
RELOAD = /\.reload\s*\(/;
|
|
7306
7825
|
EXPECT_STMT = /\bexpect\s*[.(]/;
|
|
7307
7826
|
BLOCK_SCAFFOLD2 = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
7308
7827
|
TEST_BLOCK_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow|serial|describe\.serial))?\s*\(|^(?:test\.)?(?:beforeEach|beforeAll)\s*\(/;
|
|
7309
|
-
LOCATOR_BINDING = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s
|
|
7828
|
+
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*\(.+)$/;
|
|
7310
7829
|
EXPECT_OPEN = /\bexpect(?:\.soft)?\s*\(/;
|
|
7311
7830
|
STATE_MATCHER = /\.(toBeChecked|toBeVisible|toHaveValue|toBeDisabled|toBeEnabled)\s*\(/;
|
|
7312
7831
|
CHROME_LOCATOR = /getByRole\s*\(\s*['"`](?:heading|navigation|banner|main|contentinfo|complementary|region|search|tablist|tab|button|link|menuitem|textbox|searchbox|combobox|spinbutton)['"`]/i;
|
|
@@ -7326,7 +7845,7 @@ var init_assertion_strength = __esm({
|
|
|
7326
7845
|
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;
|
|
7327
7846
|
AUTH_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_AUTH/;
|
|
7328
7847
|
AUTH_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_AUTH/;
|
|
7329
|
-
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s
|
|
7848
|
+
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s*(?:;\s*)?$/;
|
|
7330
7849
|
INBOX_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_INBOX/;
|
|
7331
7850
|
INBOX_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_INBOX/;
|
|
7332
7851
|
NEGATED_ASSERT = /\.not\s*\.\s*to[A-Z]\w*|\.toBeHidden\s*\(/;
|
|
@@ -7336,7 +7855,7 @@ var init_assertion_strength = __esm({
|
|
|
7336
7855
|
TITLE_LINE = /^\s*(?:test|describe)(?:\.\w+)?\s*\(/;
|
|
7337
7856
|
FAILURE_STATUS_ASSERT = [
|
|
7338
7857
|
/\.status\s*\(\s*\)[^;]{0,200}\.(?:toBeGreaterThanOrEqual|toBeGreaterThan)\s*\(\s*(?:399|[45]\d\d)\b/,
|
|
7339
|
-
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\))
|
|
7858
|
+
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\)\s*)?>=?\s*(?:399|[45]\d\d)\b[^;]{0,200}\)\s*\.\s*(?:toBe\s*\(\s*true|toBeTruthy)/,
|
|
7340
7859
|
/\bexpect\s*\([^;]{0,200}\.ok\s*\(\s*\)\s*\)\s*\.\s*(?:toBe\s*\(\s*false\s*\)|toBeFalsy\s*\()/
|
|
7341
7860
|
];
|
|
7342
7861
|
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;
|
|
@@ -7351,6 +7870,7 @@ var init_assertion_strength = __esm({
|
|
|
7351
7870
|
NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
|
|
7352
7871
|
ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
|
|
7353
7872
|
TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
|
|
7873
|
+
SCOPING_STEP = /(?:\s*\.\s*(?:first|last|nth)\s*\([^()]*\))*\s*\.\s*(?:getBy[A-Z]\w*|locator|filter)\s*\(/y;
|
|
7354
7874
|
NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
|
|
7355
7875
|
ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
|
|
7356
7876
|
REQUEST_WORD = /\brequest\b/;
|
|
@@ -7377,6 +7897,9 @@ var init_assertion_strength = __esm({
|
|
|
7377
7897
|
ENV_READ = String.raw`process\.env(?:(?:\?\.|\.)([A-Za-z_]\w*)|(?:\?\.)?\[\s*['"]([A-Za-z_]\w*)['"]\s*\])`;
|
|
7378
7898
|
ENTERED_ENV = new RegExp(String.raw`\.(?:fill|pressSequentially)\s*\(\s*${ENV_READ}|keyboard\.type\s*\(\s*${ENV_READ}`, "g");
|
|
7379
7899
|
HAVE_VALUE_ENV = new RegExp(String.raw`\.toHaveValue\s*\(\s*${ENV_READ}`);
|
|
7900
|
+
ACCOUNT_KEYS = TEST_USER_ENV_KEYS.join("|");
|
|
7901
|
+
ACCOUNT_ENV = `process\\.env(?:\\??\\.(?:${ACCOUNT_KEYS})\\b|(?:\\?\\.)?\\[\\s*['"\`](?:${ACCOUNT_KEYS})['"\`]\\s*\\])`;
|
|
7902
|
+
ACCOUNT_CONST = new RegExp(`\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*(?::\\s*string\\s*)?=\\s*${ACCOUNT_ENV}`, "g");
|
|
7380
7903
|
IN_FLIGHT_TEXT = /^(?:(?:sending|saving|loading|searching|checking|processing|submitting|preparing|updating|please wait|working|one moment)\b[^.]{0,40}\.{2,3}|\.{3}|…)$/i;
|
|
7381
7904
|
LOCATOR_VALUE_READ = /\.(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts|evaluate|evaluateAll|boundingBox|all)\s*\(/;
|
|
7382
7905
|
LOCATOR_EXPR = /^(?:this\.)?page\s*\.\s*(?:getBy\w+|locator)\s*\(/;
|
|
@@ -7388,14 +7911,38 @@ var init_assertion_strength = __esm({
|
|
|
7388
7911
|
IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
|
|
7389
7912
|
PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
7390
7913
|
COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
|
|
7914
|
+
URL_CHECK_ARG = /\bpage\s*\.\s*waitForURL\s*\(\s*([^,)]+)|\bexpect(?:\s*\.\s*soft)?\s*\(\s*page\s*\)\s*\.\s*toHaveURL\s*\(\s*([^,)]+)/;
|
|
7915
|
+
PLAIN_PAGE_PATH = /^\/[\w\-./~%]*(?:[?#][^\s]*)?$/;
|
|
7391
7916
|
FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
|
|
7392
7917
|
CONTROL_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(|\.toHaveAttribute\s*\(\s*['"`]aria-checked['"`]/;
|
|
7918
|
+
ACCOUNT_EMAIL_ENV = /^process\.env(?:(?:\?\.|\.)TEST_USER_EMAIL\b|(?:\?\.)?\[\s*['"]TEST_USER_EMAIL['"]\s*\])/;
|
|
7919
|
+
ENV_PASSWORD_ENTRY = /\.(?:fill|pressSequentially)\s*\(\s*process\.env(?:(?:\?\.|\.)TEST_USER_PASSWORD\b|(?:\?\.)?\[\s*['"]TEST_USER_PASSWORD['"]\s*\])/;
|
|
7920
|
+
ACCOUNT_CONTROL_ROLE = /getByRole\s*\(\s*['"`](?:button|link|menuitem)['"`]\s*,\s*\{/;
|
|
7921
|
+
ASSERT_OR_WAIT = /^(?:await\s+)?(?:expect(?:\.soft|\.poll)?\s*\(|[\w$]+(?:\.[\w$]+)*\.waitFor[A-Za-z]*\s*\()/;
|
|
7922
|
+
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*\(/;
|
|
7923
|
+
actLinesOf = /* @__PURE__ */ new WeakMap();
|
|
7924
|
+
CLOSERS_ONLY = /^[})\];,\s]+$/;
|
|
7925
|
+
TEST_BODY_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/;
|
|
7393
7926
|
COPY_CONTROL = /\bcopy\b/i;
|
|
7394
7927
|
COPIED_NOTICE = /\bcopied\b/i;
|
|
7395
7928
|
SEND_CONTROL = /\b(send|submit|subscribe|sign up for|contact|feedback|join (the )?waitlist)\b/i;
|
|
7396
7929
|
SEND_NOTICE = /\b(thank|thanks|sent|subscribed|received|in touch)\b/i;
|
|
7397
7930
|
MARK_READ_CONTROL = /\bmark(?:ed)? as read\b|\bmark all(?: as)? read\b/i;
|
|
7398
7931
|
APP_DATA_FIELD = /\b(title|name of|amount|price|quantity|sku|status|due|assignee|project|ticket|invoice|order)\b/i;
|
|
7932
|
+
COMMIT_CONTROL = /\b(?:save|submit|update|apply|add|create|post|send|publish)\b|\bconfirm\s+changes\b/i;
|
|
7933
|
+
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;
|
|
7934
|
+
DESTRUCTIVE_CONTROL = /\b(?:delete|remove|discard)\b/i;
|
|
7935
|
+
ENTER_PRESS = /\.press\s*\(\s*['"`]Enter['"`]/;
|
|
7936
|
+
CONTROL_LABEL = /(?:name\s*:\s*|getBy(?:Text|Label|Title|TestId)\s*\(\s*|has-text\(\s*)(?:(['"`])((?:(?!\1).)*)\1|\/((?:\\.|[^/\\])+)\/)/g;
|
|
7937
|
+
isCommitClick = (stmt) => {
|
|
7938
|
+
const label = clickLabel(stmt);
|
|
7939
|
+
return label !== null && COMMIT_CONTROL.test(label) && !NOT_COMMIT_CONTROL.test(label) && !EXCLUDE_AFFORDANCE.test(label);
|
|
7940
|
+
};
|
|
7941
|
+
isDestructiveClick = (stmt) => {
|
|
7942
|
+
const label = clickLabel(stmt);
|
|
7943
|
+
return label !== null && DESTRUCTIVE_CONTROL.test(label);
|
|
7944
|
+
};
|
|
7945
|
+
TEARDOWN_OPEN = /\bfinally\s*\{|^(?:test\.)?(?:after|before)(?:Each|All)\s*\(/;
|
|
7399
7946
|
}
|
|
7400
7947
|
});
|
|
7401
7948
|
|
|
@@ -8685,235 +9232,61 @@ function googleBrokerUnavailableLine(lines, testError) {
|
|
|
8685
9232
|
else if (GOOGLE_SIGNED_IN.test(text) || text.startsWith("[google-sign-in] "))
|
|
8686
9233
|
last = null;
|
|
8687
9234
|
}
|
|
8688
|
-
}
|
|
8689
|
-
return last;
|
|
8690
|
-
}
|
|
8691
|
-
function stepConsoleLines(result) {
|
|
8692
|
-
const steps = Array.isArray(result) ? result : result && typeof result === "object" && Array.isArray(result.stepResults) ? result.stepResults : [];
|
|
8693
|
-
return steps.flatMap((step) => {
|
|
8694
|
-
const logs = step && typeof step === "object" ? step.consoleLogs : null;
|
|
8695
|
-
return Array.isArray(logs) ? logs.filter((line) => typeof line === "string") : [];
|
|
8696
|
-
});
|
|
8697
|
-
}
|
|
8698
|
-
var GOOGLE_BROKER_UNAVAILABLE, GOOGLE_BROKER_ASKED, GOOGLE_SIGNED_IN, TIMEOUT_ERROR;
|
|
8699
|
-
var init_google_broker_lines = __esm({
|
|
8700
|
-
"../shared/dist/google-broker-lines.js"() {
|
|
8701
|
-
"use strict";
|
|
8702
|
-
GOOGLE_BROKER_UNAVAILABLE = /^\[google-sign-in\] (?:(?:busy|rate_limited|timeout|offline): |failed: Google sign-in service (?:answered 50[234]\b|unreachable))/;
|
|
8703
|
-
GOOGLE_BROKER_ASKED = /^\[google-sign-in\] the app started Google sign-in; asking the broker/;
|
|
8704
|
-
GOOGLE_SIGNED_IN = /^\[google-sign-in\] returned to the app with Google sign-in/;
|
|
8705
|
-
TIMEOUT_ERROR = /Test timeout of \d+ms exceeded|TimeoutError|Timeout:? \d+ ?ms/i;
|
|
8706
|
-
}
|
|
8707
|
-
});
|
|
8708
|
-
|
|
8709
|
-
// ../shared/dist/admin-view-return-to.js
|
|
8710
|
-
function sanitizeAdminViewReturnTo(value) {
|
|
8711
|
-
if (typeof value !== "string")
|
|
8712
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8713
|
-
const trimmed = value.trim();
|
|
8714
|
-
if (!trimmed || trimmed.length > MAX_RETURN_TO_LENGTH)
|
|
8715
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8716
|
-
if (!trimmed.startsWith("/") || trimmed.startsWith("//"))
|
|
8717
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8718
|
-
if (trimmed.includes("\\") || /[\s\u0000-\u001f\u007f]/.test(trimmed))
|
|
8719
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8720
|
-
let url;
|
|
8721
|
-
try {
|
|
8722
|
-
url = new URL(trimmed, PLACEHOLDER_ORIGIN);
|
|
8723
|
-
} catch {
|
|
8724
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8725
|
-
}
|
|
8726
|
-
if (url.origin !== PLACEHOLDER_ORIGIN)
|
|
8727
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8728
|
-
if (BLOCKED_PATH_RE.test(url.pathname))
|
|
8729
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8730
|
-
const out = `${url.pathname}${url.search}${url.hash}`;
|
|
8731
|
-
if (out.startsWith("//") || out.includes("\\"))
|
|
8732
|
-
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
8733
|
-
return out;
|
|
8734
|
-
}
|
|
8735
|
-
var ADMIN_VIEW_DEFAULT_RETURN_TO, MAX_RETURN_TO_LENGTH, PLACEHOLDER_ORIGIN, BLOCKED_PATH_RE;
|
|
8736
|
-
var init_admin_view_return_to = __esm({
|
|
8737
|
-
"../shared/dist/admin-view-return-to.js"() {
|
|
8738
|
-
"use strict";
|
|
8739
|
-
ADMIN_VIEW_DEFAULT_RETURN_TO = "/sessions";
|
|
8740
|
-
MAX_RETURN_TO_LENGTH = 2048;
|
|
8741
|
-
PLACEHOLDER_ORIGIN = "https://admin-view.invalid";
|
|
8742
|
-
BLOCKED_PATH_RE = /^\/(?:login|admin-view)/i;
|
|
8743
|
-
}
|
|
8744
|
-
});
|
|
8745
|
-
|
|
8746
|
-
// ../shared/dist/auth-plan.js
|
|
8747
|
-
function hasInlineLoginSteps(playwrightCode) {
|
|
8748
|
-
if (!playwrightCode)
|
|
8749
|
-
return false;
|
|
8750
|
-
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
8751
|
-
}
|
|
8752
|
-
function hasGeneratedAuthGuard(playwrightCode) {
|
|
8753
|
-
if (!playwrightCode)
|
|
8754
|
-
return false;
|
|
8755
|
-
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
8756
|
-
}
|
|
8757
|
-
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
8758
|
-
if (!sharedAuthInjectEnabled)
|
|
8759
|
-
return false;
|
|
8760
|
-
if (tags.includes("@auth"))
|
|
8761
|
-
return false;
|
|
8762
|
-
if (tags.includes("@api"))
|
|
8763
|
-
return true;
|
|
8764
|
-
if (!tags.includes("@needs-auth"))
|
|
8765
|
-
return false;
|
|
8766
|
-
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
8767
|
-
return true;
|
|
8768
|
-
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
8769
|
-
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
8770
|
-
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
8771
|
-
}
|
|
8772
|
-
function codeReadsStoredCredentials(code) {
|
|
8773
|
-
if (!code)
|
|
8774
|
-
return false;
|
|
8775
|
-
if (/__vqaLogin\b/.test(code))
|
|
8776
|
-
return true;
|
|
8777
|
-
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
8778
|
-
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
8779
|
-
return true;
|
|
8780
|
-
}
|
|
8781
|
-
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
8782
|
-
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
8783
|
-
return true;
|
|
8784
|
-
}
|
|
8785
|
-
return false;
|
|
8786
|
-
}
|
|
8787
|
-
function explicitAuthTypeTags(t) {
|
|
8788
|
-
const found = /* @__PURE__ */ new Set();
|
|
8789
|
-
for (const tag of t) {
|
|
8790
|
-
if (AUTH_TYPE_TAGS.includes(tag))
|
|
8791
|
-
found.add(tag);
|
|
8792
|
-
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
8793
|
-
found.add(AUTH_TAG_ALIASES[tag]);
|
|
8794
|
-
}
|
|
8795
|
-
return [...found];
|
|
8796
|
-
}
|
|
8797
|
-
function invalidPlan(configurationError) {
|
|
8798
|
-
return {
|
|
8799
|
-
version: 1,
|
|
8800
|
-
source: "invalid",
|
|
8801
|
-
acquisition: "unsupported",
|
|
8802
|
-
presentation: "none",
|
|
8803
|
-
needsCookieState: false,
|
|
8804
|
-
needsStandingHeaders: false,
|
|
8805
|
-
standingHeadersMode: "none",
|
|
8806
|
-
needsLoginCreds: false,
|
|
8807
|
-
requiredEnvKeys: [],
|
|
8808
|
-
configurationError
|
|
8809
|
-
};
|
|
8810
|
-
}
|
|
8811
|
-
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
8812
|
-
return {
|
|
8813
|
-
version: 1,
|
|
8814
|
-
source: "explicit",
|
|
8815
|
-
authTypeTag: authTypeTag2,
|
|
8816
|
-
acquisition,
|
|
8817
|
-
presentation,
|
|
8818
|
-
needsCookieState: opts.cookie,
|
|
8819
|
-
needsStandingHeaders: opts.standingMode === "required",
|
|
8820
|
-
standingHeadersMode: opts.standingMode,
|
|
8821
|
-
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
8822
|
-
requiredEnvKeys: opts.requiredEnvKeys
|
|
8823
|
-
};
|
|
8824
|
-
}
|
|
8825
|
-
function deriveAuthPlan(tags, code, opts) {
|
|
8826
|
-
const t = Array.isArray(tags) ? tags : [];
|
|
8827
|
-
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
8828
|
-
const isApi = t.includes("@api");
|
|
8829
|
-
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
8830
|
-
if (explicit.length > 0) {
|
|
8831
|
-
if (t.includes("@auth")) {
|
|
8832
|
-
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
8833
|
-
}
|
|
8834
|
-
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
8835
|
-
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
8836
|
-
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
8837
|
-
switch (loginCompose[0]) {
|
|
8838
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
8839
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8840
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
8841
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8842
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
8843
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
8844
|
-
}
|
|
8845
|
-
}
|
|
8846
|
-
if (explicit.length > 1) {
|
|
8847
|
-
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
8848
|
-
}
|
|
8849
|
-
switch (explicit[0]) {
|
|
8850
|
-
case AUTH_TAG_UNSUPPORTED:
|
|
8851
|
-
return {
|
|
8852
|
-
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
8853
|
-
};
|
|
8854
|
-
case AUTH_TAG_NONE:
|
|
8855
|
-
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
8856
|
-
case AUTH_TAG_STANDING:
|
|
8857
|
-
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
8858
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
8859
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8860
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
8861
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8862
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
8863
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
8864
|
-
}
|
|
8865
|
-
}
|
|
8866
|
-
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
8867
|
-
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
8868
|
-
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
8869
|
-
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
8870
|
-
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
8871
|
-
return {
|
|
8872
|
-
version: 1,
|
|
8873
|
-
source: "legacy",
|
|
8874
|
-
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
8875
|
-
presentation: authedLegacy ? "cookie" : "none",
|
|
8876
|
-
needsCookieState: cookie,
|
|
8877
|
-
needsStandingHeaders: false,
|
|
8878
|
-
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
8879
|
-
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
8880
|
-
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
8881
|
-
needsLoginCreds,
|
|
8882
|
-
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
8883
|
-
};
|
|
9235
|
+
}
|
|
9236
|
+
return last;
|
|
8884
9237
|
}
|
|
8885
|
-
function
|
|
8886
|
-
const
|
|
8887
|
-
|
|
8888
|
-
|
|
9238
|
+
function stepConsoleLines(result) {
|
|
9239
|
+
const steps = Array.isArray(result) ? result : result && typeof result === "object" && Array.isArray(result.stepResults) ? result.stepResults : [];
|
|
9240
|
+
return steps.flatMap((step) => {
|
|
9241
|
+
const logs = step && typeof step === "object" ? step.consoleLogs : null;
|
|
9242
|
+
return Array.isArray(logs) ? logs.filter((line) => typeof line === "string") : [];
|
|
9243
|
+
});
|
|
8889
9244
|
}
|
|
8890
|
-
var
|
|
8891
|
-
var
|
|
8892
|
-
"../shared/dist/
|
|
9245
|
+
var GOOGLE_BROKER_UNAVAILABLE, GOOGLE_BROKER_ASKED, GOOGLE_SIGNED_IN, TIMEOUT_ERROR;
|
|
9246
|
+
var init_google_broker_lines = __esm({
|
|
9247
|
+
"../shared/dist/google-broker-lines.js"() {
|
|
8893
9248
|
"use strict";
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
9249
|
+
GOOGLE_BROKER_UNAVAILABLE = /^\[google-sign-in\] (?:(?:busy|rate_limited|timeout|offline): |failed: Google sign-in service (?:answered 50[234]\b|unreachable))/;
|
|
9250
|
+
GOOGLE_BROKER_ASKED = /^\[google-sign-in\] the app started Google sign-in; asking the broker/;
|
|
9251
|
+
GOOGLE_SIGNED_IN = /^\[google-sign-in\] returned to the app with Google sign-in/;
|
|
9252
|
+
TIMEOUT_ERROR = /Test timeout of \d+ms exceeded|TimeoutError|Timeout:? \d+ ?ms/i;
|
|
9253
|
+
}
|
|
9254
|
+
});
|
|
9255
|
+
|
|
9256
|
+
// ../shared/dist/admin-view-return-to.js
|
|
9257
|
+
function sanitizeAdminViewReturnTo(value) {
|
|
9258
|
+
if (typeof value !== "string")
|
|
9259
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9260
|
+
const trimmed = value.trim();
|
|
9261
|
+
if (!trimmed || trimmed.length > MAX_RETURN_TO_LENGTH)
|
|
9262
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9263
|
+
if (!trimmed.startsWith("/") || trimmed.startsWith("//"))
|
|
9264
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9265
|
+
if (trimmed.includes("\\") || /[\s\u0000-\u001f\u007f]/.test(trimmed))
|
|
9266
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9267
|
+
let url;
|
|
9268
|
+
try {
|
|
9269
|
+
url = new URL(trimmed, PLACEHOLDER_ORIGIN);
|
|
9270
|
+
} catch {
|
|
9271
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9272
|
+
}
|
|
9273
|
+
if (url.origin !== PLACEHOLDER_ORIGIN)
|
|
9274
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9275
|
+
if (BLOCKED_PATH_RE.test(url.pathname))
|
|
9276
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9277
|
+
const out = `${url.pathname}${url.search}${url.hash}`;
|
|
9278
|
+
if (out.startsWith("//") || out.includes("\\"))
|
|
9279
|
+
return ADMIN_VIEW_DEFAULT_RETURN_TO;
|
|
9280
|
+
return out;
|
|
9281
|
+
}
|
|
9282
|
+
var ADMIN_VIEW_DEFAULT_RETURN_TO, MAX_RETURN_TO_LENGTH, PLACEHOLDER_ORIGIN, BLOCKED_PATH_RE;
|
|
9283
|
+
var init_admin_view_return_to = __esm({
|
|
9284
|
+
"../shared/dist/admin-view-return-to.js"() {
|
|
9285
|
+
"use strict";
|
|
9286
|
+
ADMIN_VIEW_DEFAULT_RETURN_TO = "/sessions";
|
|
9287
|
+
MAX_RETURN_TO_LENGTH = 2048;
|
|
9288
|
+
PLACEHOLDER_ORIGIN = "https://admin-view.invalid";
|
|
9289
|
+
BLOCKED_PATH_RE = /^\/(?:login|admin-view)/i;
|
|
8917
9290
|
}
|
|
8918
9291
|
});
|
|
8919
9292
|
|
|
@@ -8924,13 +9297,16 @@ function stripEchoLines(text) {
|
|
|
8924
9297
|
function matchesAny(text, patterns) {
|
|
8925
9298
|
return patterns.some((p) => p.test(text));
|
|
8926
9299
|
}
|
|
9300
|
+
function isIntentionalNegativeAuthTest(input) {
|
|
9301
|
+
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
9302
|
+
return matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH);
|
|
9303
|
+
}
|
|
8927
9304
|
function detectAuthBlock(input) {
|
|
8928
9305
|
const tags = input.tags ?? [];
|
|
8929
9306
|
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
8930
9307
|
if (!isAuthed)
|
|
8931
9308
|
return NO_DETECTION;
|
|
8932
|
-
|
|
8933
|
-
if (matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH))
|
|
9309
|
+
if (isIntentionalNegativeAuthTest(input))
|
|
8934
9310
|
return NO_DETECTION;
|
|
8935
9311
|
const sources = [];
|
|
8936
9312
|
if (input.error)
|
|
@@ -9033,7 +9409,7 @@ var init_auth_block_detector = __esm({
|
|
|
9033
9409
|
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
9034
9410
|
];
|
|
9035
9411
|
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
9036
|
-
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
|
|
9412
|
+
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;
|
|
9037
9413
|
}
|
|
9038
9414
|
});
|
|
9039
9415
|
|
|
@@ -9974,12 +10350,70 @@ function isSharedAuthInjectEnabled(value = process.env.SHARED_AUTH_INJECT) {
|
|
|
9974
10350
|
function isAuthReadinessGuardEnabled(value = process.env.AUTH_READINESS_GUARD) {
|
|
9975
10351
|
return value?.trim().toLowerCase() !== "false";
|
|
9976
10352
|
}
|
|
10353
|
+
function visualBaselinesEnabled(projectId, raw = process.env.VISUAL_BASELINES_PROJECTS) {
|
|
10354
|
+
if (typeof projectId !== "string" || projectId.trim() === "")
|
|
10355
|
+
return false;
|
|
10356
|
+
const listed = (raw ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
10357
|
+
return listed.includes("*") || listed.includes(projectId);
|
|
10358
|
+
}
|
|
9977
10359
|
var init_feature_flags = __esm({
|
|
9978
10360
|
"../shared/dist/feature-flags.js"() {
|
|
9979
10361
|
"use strict";
|
|
9980
10362
|
}
|
|
9981
10363
|
});
|
|
9982
10364
|
|
|
10365
|
+
// ../shared/dist/visual-compare-limits.js
|
|
10366
|
+
function isSafeMaskSelector(selector) {
|
|
10367
|
+
if (typeof selector !== "string")
|
|
10368
|
+
return false;
|
|
10369
|
+
if (selector.trim().length === 0)
|
|
10370
|
+
return false;
|
|
10371
|
+
if (selector.length > VISUAL_MASK_SELECTOR_MAX_LENGTH)
|
|
10372
|
+
return false;
|
|
10373
|
+
return !VISUAL_MASK_SELECTOR_FORBIDDEN.test(selector);
|
|
10374
|
+
}
|
|
10375
|
+
var VISUAL_MASK_SELECTORS_MAX, VISUAL_MASK_SELECTOR_MAX_LENGTH, VISUAL_MASK_SELECTOR_FORBIDDEN;
|
|
10376
|
+
var init_visual_compare_limits = __esm({
|
|
10377
|
+
"../shared/dist/visual-compare-limits.js"() {
|
|
10378
|
+
"use strict";
|
|
10379
|
+
VISUAL_MASK_SELECTORS_MAX = 50;
|
|
10380
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH = 300;
|
|
10381
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN = /[{};@<\r\n]/;
|
|
10382
|
+
}
|
|
10383
|
+
});
|
|
10384
|
+
|
|
10385
|
+
// ../shared/dist/visual-baseline-identity.js
|
|
10386
|
+
function isBrowserVersion(value) {
|
|
10387
|
+
return typeof value === "string" && value.length <= 32 && BROWSER_VERSION.test(value);
|
|
10388
|
+
}
|
|
10389
|
+
function renderIdentity(flavour, version, image) {
|
|
10390
|
+
if (!/^[a-z][a-z-]{0,31}$/.test(flavour) || !/^[a-z][a-z-]{0,31}$/.test(image) || !isBrowserVersion(version))
|
|
10391
|
+
return null;
|
|
10392
|
+
const identity = `${flavour}/${version}/${image}`;
|
|
10393
|
+
return identity.length <= RENDER_IDENTITY_MAX_LENGTH ? identity : null;
|
|
10394
|
+
}
|
|
10395
|
+
function v1RenderIdentity(version) {
|
|
10396
|
+
return renderIdentity(VISUAL_V1_IDENTITY.flavour, version, VISUAL_V1_IDENTITY.image);
|
|
10397
|
+
}
|
|
10398
|
+
function parseRenderIdentity(value) {
|
|
10399
|
+
if (typeof value !== "string" || value.length > RENDER_IDENTITY_MAX_LENGTH)
|
|
10400
|
+
return null;
|
|
10401
|
+
const parts = value.split("/");
|
|
10402
|
+
if (parts.length !== 3)
|
|
10403
|
+
return null;
|
|
10404
|
+
const [flavour, version, image] = parts;
|
|
10405
|
+
return renderIdentity(flavour, version, image) === value ? { flavour, version, image } : null;
|
|
10406
|
+
}
|
|
10407
|
+
var VISUAL_V1_IDENTITY, RENDER_IDENTITY_MAX_LENGTH, BROWSER_VERSION;
|
|
10408
|
+
var init_visual_baseline_identity = __esm({
|
|
10409
|
+
"../shared/dist/visual-baseline-identity.js"() {
|
|
10410
|
+
"use strict";
|
|
10411
|
+
VISUAL_V1_IDENTITY = { platform: "linux", image: "runner-fast", flavour: "headless-shell" };
|
|
10412
|
+
RENDER_IDENTITY_MAX_LENGTH = 64;
|
|
10413
|
+
BROWSER_VERSION = /^\d{1,4}(\.\d{1,6}){0,3}$/;
|
|
10414
|
+
}
|
|
10415
|
+
});
|
|
10416
|
+
|
|
9983
10417
|
// ../shared/dist/analytics-url.js
|
|
9984
10418
|
function isSensitiveQueryKey(key) {
|
|
9985
10419
|
return SENSITIVE_QUERY_KEY_RE.test(key);
|
|
@@ -10333,14 +10767,9 @@ function isOpenCodeGoModelId(id) {
|
|
|
10333
10767
|
function hasOpenCodeGoPrefix(id) {
|
|
10334
10768
|
return (id?.trim() ?? "").startsWith(OPENCODE_GO_PREFIX);
|
|
10335
10769
|
}
|
|
10336
|
-
function hasOpenCodeGo2Prefix(id) {
|
|
10337
|
-
return (id?.trim() ?? "").startsWith(OPENCODE_GO_2_PREFIX);
|
|
10338
|
-
}
|
|
10339
10770
|
function openCodeGoWireModel(id) {
|
|
10340
10771
|
const trimmed = id?.trim() ?? "";
|
|
10341
|
-
|
|
10342
|
-
return null;
|
|
10343
|
-
return trimmed.slice((hasOpenCodeGo2Prefix(trimmed) ? OPENCODE_GO_2_PREFIX : OPENCODE_GO_PREFIX).length);
|
|
10772
|
+
return isOpenCodeGoModelId(trimmed) ? trimmed.slice(OPENCODE_GO_PREFIX.length) : null;
|
|
10344
10773
|
}
|
|
10345
10774
|
function isZaiModelId(id) {
|
|
10346
10775
|
const trimmed = id?.trim() ?? "";
|
|
@@ -10449,7 +10878,7 @@ function museCliContributorMode(env = process.env) {
|
|
|
10449
10878
|
const raw = (env.MUSE_CLI_CONTRIBUTOR_MODE ?? "").trim().toLowerCase();
|
|
10450
10879
|
return raw === "off" || raw === "false" || raw === "0" || raw === "no" ? "off" : "on";
|
|
10451
10880
|
}
|
|
10452
|
-
var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX,
|
|
10881
|
+
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;
|
|
10453
10882
|
var init_engine_spec = __esm({
|
|
10454
10883
|
"../shared/dist/engine-spec.js"() {
|
|
10455
10884
|
"use strict";
|
|
@@ -10508,8 +10937,7 @@ var init_engine_spec = __esm({
|
|
|
10508
10937
|
OPENROUTER_PREFIX = "openrouter:";
|
|
10509
10938
|
OPENROUTER_MODEL_PATTERN = /^openrouter:[a-z0-9][a-z0-9._-]{0,40}\/[A-Za-z0-9._:-]{1,100}$/;
|
|
10510
10939
|
OPENCODE_GO_PREFIX = "opencode-go:";
|
|
10511
|
-
|
|
10512
|
-
OPENCODE_GO_MODEL_PATTERN = /^opencode-go(?:-2)?:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
10940
|
+
OPENCODE_GO_MODEL_PATTERN = /^opencode-go:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
10513
10941
|
ZAI_PREFIX = "zai:";
|
|
10514
10942
|
ZAI_MODEL_PATTERN = /^zai:glm-[a-z0-9][a-z0-9._-]{0,60}$/;
|
|
10515
10943
|
}
|
|
@@ -10834,14 +11262,19 @@ function has(map, key) {
|
|
|
10834
11262
|
}
|
|
10835
11263
|
function providerChainFor(modelId) {
|
|
10836
11264
|
const key = chainKey(modelId);
|
|
11265
|
+
if (key && has(_overrideHops, key))
|
|
11266
|
+
return _overrideHops[key];
|
|
10837
11267
|
return key && has(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
|
|
10838
11268
|
}
|
|
10839
11269
|
function providerChainLeadsFor(modelId) {
|
|
10840
11270
|
const key = chainKey(modelId);
|
|
11271
|
+
if (key && has(_overrideLeads, key))
|
|
11272
|
+
return _overrideLeads[key];
|
|
10841
11273
|
return key && has(PROVIDER_CHAIN_LEADS, key) ? PROVIDER_CHAIN_LEADS[key] : [];
|
|
10842
11274
|
}
|
|
10843
11275
|
function allChains() {
|
|
10844
|
-
|
|
11276
|
+
const ordered = (map, override) => [...Object.entries(map).filter(([key]) => !has(override, key)), ...Object.entries(override)];
|
|
11277
|
+
return [...ordered(PROVIDER_CHAINS, _overrideHops), ...ordered(PROVIDER_CHAIN_LEADS, _overrideLeads)];
|
|
10845
11278
|
}
|
|
10846
11279
|
function isProviderChainHopId(modelId) {
|
|
10847
11280
|
const id = modelId ?? "";
|
|
@@ -10858,14 +11291,24 @@ function providerChainHostOf(value, modelValue) {
|
|
|
10858
11291
|
return "own";
|
|
10859
11292
|
if (hasZaiPrefix(value))
|
|
10860
11293
|
return "zai";
|
|
10861
|
-
if (hasOpenCodeGo2Prefix(value))
|
|
10862
|
-
return "opencode-go-2";
|
|
10863
11294
|
if (hasOpenCodeGoPrefix(value))
|
|
10864
11295
|
return "opencode-go";
|
|
10865
11296
|
if (hasOpenRouterPrefix(value))
|
|
10866
11297
|
return "openrouter";
|
|
10867
11298
|
return "own";
|
|
10868
11299
|
}
|
|
11300
|
+
function providerChainHostProvider(value) {
|
|
11301
|
+
if (typeof value !== "string" || !value)
|
|
11302
|
+
return null;
|
|
11303
|
+
if (hasOpenRouterPrefix(value))
|
|
11304
|
+
return "openrouter";
|
|
11305
|
+
if (hasOpenCodeGoPrefix(value))
|
|
11306
|
+
return "opencode-go";
|
|
11307
|
+
if (hasZaiPrefix(value))
|
|
11308
|
+
return "zai";
|
|
11309
|
+
const key = chainKey(value);
|
|
11310
|
+
return API_MODEL_CATALOG.find((m) => m.id === key)?.provider ?? GEMINI_ASSISTANT_MODELS.find((m) => m.id === key)?.provider ?? null;
|
|
11311
|
+
}
|
|
10869
11312
|
function providerHostPlan(modelId) {
|
|
10870
11313
|
const key = chainKey(modelId);
|
|
10871
11314
|
if (!key)
|
|
@@ -10883,7 +11326,140 @@ function providerHostPlan(modelId) {
|
|
|
10883
11326
|
}
|
|
10884
11327
|
return steps;
|
|
10885
11328
|
}
|
|
10886
|
-
|
|
11329
|
+
function providerChainModelKey(modelId) {
|
|
11330
|
+
return chainKey(modelId);
|
|
11331
|
+
}
|
|
11332
|
+
function hasProviderChainLeadsByDefault(modelId) {
|
|
11333
|
+
const key = chainKey(modelId);
|
|
11334
|
+
return key !== null && has(PROVIDER_CHAIN_LEADS, key);
|
|
11335
|
+
}
|
|
11336
|
+
function isChainablePrimary(id) {
|
|
11337
|
+
return typeof id === "string" && id !== "" && (has(PROVIDER_CHAINS, id) || has(PROVIDER_CHAIN_LEADS, id));
|
|
11338
|
+
}
|
|
11339
|
+
function defaultProviderChainEntries(primary) {
|
|
11340
|
+
if (!isChainablePrimary(primary))
|
|
11341
|
+
return [];
|
|
11342
|
+
const leads = has(PROVIDER_CHAIN_LEADS, primary) ? PROVIDER_CHAIN_LEADS[primary] : [];
|
|
11343
|
+
const hops = has(PROVIDER_CHAINS, primary) ? PROVIDER_CHAINS[primary] : [];
|
|
11344
|
+
return [...leads, primary, ...hops].map((hop) => ({ hop, enabled: true }));
|
|
11345
|
+
}
|
|
11346
|
+
function allowedProviderChainHosts(primary) {
|
|
11347
|
+
return defaultProviderChainEntries(primary).map((entry) => entry.hop);
|
|
11348
|
+
}
|
|
11349
|
+
function isPlainObject2(value) {
|
|
11350
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
11351
|
+
}
|
|
11352
|
+
function validateProviderChainEntries(primary, entries) {
|
|
11353
|
+
if (!isChainablePrimary(primary))
|
|
11354
|
+
return `${String(primary).slice(0, 80)} has no provider chain to order`;
|
|
11355
|
+
if (!Array.isArray(entries))
|
|
11356
|
+
return `${primary}: the chain must be a list`;
|
|
11357
|
+
if (entries.length > PROVIDER_CHAIN_MAX_ENTRIES)
|
|
11358
|
+
return `${primary}: at most ${PROVIDER_CHAIN_MAX_ENTRIES} hosts`;
|
|
11359
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
11360
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11361
|
+
for (const entry of entries) {
|
|
11362
|
+
if (!isPlainObject2(entry))
|
|
11363
|
+
return `${primary}: each host must be { hop, enabled }`;
|
|
11364
|
+
const keys = Object.keys(entry);
|
|
11365
|
+
if (keys.length !== 2 || !keys.includes("hop") || !keys.includes("enabled"))
|
|
11366
|
+
return `${primary}: each host must be { hop, enabled } and nothing else`;
|
|
11367
|
+
const { hop, enabled } = entry;
|
|
11368
|
+
if (typeof enabled !== "boolean")
|
|
11369
|
+
return `${primary}: enabled must be true or false`;
|
|
11370
|
+
if (typeof hop !== "string" || !hop)
|
|
11371
|
+
return `${primary}: hop must be a model value`;
|
|
11372
|
+
if (!allowed.includes(hop))
|
|
11373
|
+
return `${primary}: ${hop.slice(0, 80)} is not a host of this model`;
|
|
11374
|
+
if (seen.has(hop))
|
|
11375
|
+
return `${primary}: ${hop} is listed twice`;
|
|
11376
|
+
if (hop === primary && !enabled)
|
|
11377
|
+
return `${primary}: the model's own value stays on (pick another model on AI Models instead)`;
|
|
11378
|
+
seen.add(hop);
|
|
11379
|
+
}
|
|
11380
|
+
if (!seen.has(primary))
|
|
11381
|
+
return `${primary}: list the model's own value once, where its own host sits`;
|
|
11382
|
+
return null;
|
|
11383
|
+
}
|
|
11384
|
+
function decodeProviderChains(raw) {
|
|
11385
|
+
let value = raw;
|
|
11386
|
+
if (typeof raw === "string") {
|
|
11387
|
+
if (raw.length > PROVIDER_CHAINS_SETTING_MAX_CHARS)
|
|
11388
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
11389
|
+
try {
|
|
11390
|
+
value = JSON.parse(raw);
|
|
11391
|
+
} catch {
|
|
11392
|
+
return { ok: false, error: "AI_PROVIDER_CHAINS must be valid JSON" };
|
|
11393
|
+
}
|
|
11394
|
+
} else if (JSON.stringify(raw ?? null).length > PROVIDER_CHAINS_SETTING_MAX_CHARS) {
|
|
11395
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
11396
|
+
}
|
|
11397
|
+
if (!isPlainObject2(value))
|
|
11398
|
+
return { ok: false, error: 'AI_PROVIDER_CHAINS must be an object: { "<model>": [ { "hop": "<model value>", "enabled": true } ] }' };
|
|
11399
|
+
if (Object.keys(value).length > PROVIDER_CHAIN_MAX_PRIMARIES)
|
|
11400
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS names at most ${PROVIDER_CHAIN_MAX_PRIMARIES} models` };
|
|
11401
|
+
return { ok: true, value };
|
|
11402
|
+
}
|
|
11403
|
+
function checkedProviderChains(value) {
|
|
11404
|
+
const out = {};
|
|
11405
|
+
for (const [primary, entries] of Object.entries(value)) {
|
|
11406
|
+
const problem = validateProviderChainEntries(primary, entries);
|
|
11407
|
+
if (problem)
|
|
11408
|
+
return { ok: false, error: problem };
|
|
11409
|
+
out[primary] = entries.map(({ hop, enabled }) => ({ hop, enabled }));
|
|
11410
|
+
}
|
|
11411
|
+
return { ok: true, value: out };
|
|
11412
|
+
}
|
|
11413
|
+
function parseProviderChainOverrides(raw) {
|
|
11414
|
+
const decoded = decodeProviderChains(raw);
|
|
11415
|
+
return decoded.ok ? checkedProviderChains(decoded.value) : decoded;
|
|
11416
|
+
}
|
|
11417
|
+
function parseStoredProviderChainOverrides(raw) {
|
|
11418
|
+
const decoded = decodeProviderChains(raw);
|
|
11419
|
+
if (!decoded.ok)
|
|
11420
|
+
return decoded;
|
|
11421
|
+
const dropped = [];
|
|
11422
|
+
const kept = {};
|
|
11423
|
+
for (const [primary, entries] of Object.entries(decoded.value)) {
|
|
11424
|
+
if (!isChainablePrimary(primary) || !Array.isArray(entries)) {
|
|
11425
|
+
kept[primary] = entries;
|
|
11426
|
+
continue;
|
|
11427
|
+
}
|
|
11428
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
11429
|
+
kept[primary] = entries.filter((entry) => {
|
|
11430
|
+
const hop = isPlainObject2(entry) ? entry.hop : void 0;
|
|
11431
|
+
if (typeof hop !== "string" || hop === "" || allowed.includes(hop))
|
|
11432
|
+
return true;
|
|
11433
|
+
dropped.push({ primary, hop: hop.slice(0, 80) });
|
|
11434
|
+
return false;
|
|
11435
|
+
});
|
|
11436
|
+
}
|
|
11437
|
+
const checked = checkedProviderChains(kept);
|
|
11438
|
+
return checked.ok ? { ...checked, dropped } : checked;
|
|
11439
|
+
}
|
|
11440
|
+
function validateProviderChainsSetting(raw) {
|
|
11441
|
+
const parsed = parseProviderChainOverrides(raw);
|
|
11442
|
+
return parsed.ok ? null : parsed.error;
|
|
11443
|
+
}
|
|
11444
|
+
function setProviderChainOverrides(value, onDropped) {
|
|
11445
|
+
const parsed = value === null || value === void 0 || value === "" ? null : parseStoredProviderChainOverrides(value);
|
|
11446
|
+
if (parsed?.ok && parsed.dropped.length > 0)
|
|
11447
|
+
onDropped?.(parsed.dropped);
|
|
11448
|
+
_overrides = parsed?.ok ? parsed.value : null;
|
|
11449
|
+
_overrideLeads = {};
|
|
11450
|
+
_overrideHops = {};
|
|
11451
|
+
for (const [primary, entries] of Object.entries(_overrides ?? {})) {
|
|
11452
|
+
const at = entries.findIndex((entry) => entry.hop === primary);
|
|
11453
|
+
const on = (list) => list.filter((entry) => entry.enabled).map((entry) => entry.hop);
|
|
11454
|
+
_overrideLeads[primary] = on(entries.slice(0, at));
|
|
11455
|
+
_overrideHops[primary] = on(entries.slice(at + 1));
|
|
11456
|
+
}
|
|
11457
|
+
return parsed === null || parsed.ok;
|
|
11458
|
+
}
|
|
11459
|
+
function getProviderChainOverrides() {
|
|
11460
|
+
return _overrides;
|
|
11461
|
+
}
|
|
11462
|
+
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;
|
|
10887
11463
|
var init_provider_chains = __esm({
|
|
10888
11464
|
"../shared/dist/provider-chains.js"() {
|
|
10889
11465
|
"use strict";
|
|
@@ -10895,18 +11471,120 @@ var init_provider_chains = __esm({
|
|
|
10895
11471
|
"muse-spark-1.3-contributor": ["openrouter:meta/muse-spark-1.3-contributor"],
|
|
10896
11472
|
"claude-haiku-5-5": ["opencode-go:claude-haiku-5-5", "openrouter:anthropic/claude-haiku-5.5"],
|
|
10897
11473
|
"gemini-3.1-pro-preview": ["openrouter:google/gemini-3.1-pro-preview"],
|
|
10898
|
-
"deepseek-flash": ["opencode-go
|
|
10899
|
-
"deepseek-v4-pro": ["opencode-go
|
|
11474
|
+
"deepseek-flash": ["opencode-go:deepseek-v4.1-flash", "openrouter:deepseek/deepseek-v4.1-flash"],
|
|
11475
|
+
"deepseek-v4-pro": ["opencode-go:deepseek-v4-pro", "openrouter:deepseek/deepseek-v4-pro"]
|
|
10900
11476
|
};
|
|
10901
11477
|
PROVIDER_CHAIN_LEADS = {
|
|
10902
|
-
"openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go
|
|
10903
|
-
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go
|
|
10904
|
-
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go
|
|
11478
|
+
"openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go:glm-5.3-flash"],
|
|
11479
|
+
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go:glm-5.3"],
|
|
11480
|
+
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go:glm-5.2"]
|
|
10905
11481
|
};
|
|
10906
11482
|
PROVIDER_HOST_NOT_OFFERED = {
|
|
10907
11483
|
"muse-spark-1.3-contributor": { "opencode-go": "OpenCode Go serves Muse only on its Responses API" },
|
|
10908
11484
|
"gemini-3.1-pro-preview": { "opencode-go": "OpenCode Go does not serve Gemini" }
|
|
10909
11485
|
};
|
|
11486
|
+
PROVIDER_CHAIN_MAX_ENTRIES = 8;
|
|
11487
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS = 16e3;
|
|
11488
|
+
PROVIDER_CHAIN_MAX_PRIMARIES = 32;
|
|
11489
|
+
ALLOWED_PROVIDER_CHAIN_HOPS = /* @__PURE__ */ new Set([
|
|
11490
|
+
...Object.values(PROVIDER_CHAINS).flat(),
|
|
11491
|
+
...Object.values(PROVIDER_CHAIN_LEADS).flat()
|
|
11492
|
+
]);
|
|
11493
|
+
_overrides = null;
|
|
11494
|
+
_overrideLeads = {};
|
|
11495
|
+
_overrideHops = {};
|
|
11496
|
+
}
|
|
11497
|
+
});
|
|
11498
|
+
|
|
11499
|
+
// ../shared/dist/provider-accounts.js
|
|
11500
|
+
function modelNames(modelId) {
|
|
11501
|
+
const value = modelId.trim();
|
|
11502
|
+
const names = /* @__PURE__ */ new Set([value]);
|
|
11503
|
+
for (const prefix of HOST_PREFIXES) {
|
|
11504
|
+
if (!value.startsWith(prefix))
|
|
11505
|
+
continue;
|
|
11506
|
+
const bare = value.slice(prefix.length);
|
|
11507
|
+
names.add(bare);
|
|
11508
|
+
const slash = bare.lastIndexOf("/");
|
|
11509
|
+
if (slash >= 0)
|
|
11510
|
+
names.add(bare.slice(slash + 1));
|
|
11511
|
+
}
|
|
11512
|
+
const canonical = canonicalModelId(value);
|
|
11513
|
+
if (canonical) {
|
|
11514
|
+
names.add(canonical);
|
|
11515
|
+
const entry = API_MODEL_CATALOG.find((m) => m.id === canonical || m.apiModel === canonical);
|
|
11516
|
+
if (entry) {
|
|
11517
|
+
names.add(entry.id);
|
|
11518
|
+
if (entry.apiModel)
|
|
11519
|
+
names.add(entry.apiModel);
|
|
11520
|
+
}
|
|
11521
|
+
}
|
|
11522
|
+
return names;
|
|
11523
|
+
}
|
|
11524
|
+
function accountServesModel(models, modelId) {
|
|
11525
|
+
if (!models || models.length === 0)
|
|
11526
|
+
return true;
|
|
11527
|
+
if (!modelId)
|
|
11528
|
+
return false;
|
|
11529
|
+
const names = modelNames(modelId);
|
|
11530
|
+
return models.some((model) => names.has(model.trim()));
|
|
11531
|
+
}
|
|
11532
|
+
function normalizeProviderAccountModels(models) {
|
|
11533
|
+
if (!Array.isArray(models))
|
|
11534
|
+
return null;
|
|
11535
|
+
const out = [];
|
|
11536
|
+
for (const model of models) {
|
|
11537
|
+
if (typeof model !== "string")
|
|
11538
|
+
return null;
|
|
11539
|
+
const trimmed = model.trim();
|
|
11540
|
+
if (!PROVIDER_ACCOUNT_MODEL_PATTERN.test(trimmed) || trimmed.includes(".."))
|
|
11541
|
+
return null;
|
|
11542
|
+
if (!out.includes(trimmed))
|
|
11543
|
+
out.push(trimmed);
|
|
11544
|
+
}
|
|
11545
|
+
return out.length > MAX_PROVIDER_ACCOUNT_MODELS ? null : out;
|
|
11546
|
+
}
|
|
11547
|
+
function parseProviderAccountLists(value, providers) {
|
|
11548
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
11549
|
+
return null;
|
|
11550
|
+
const parsed = {};
|
|
11551
|
+
for (const provider of providers) {
|
|
11552
|
+
const list = value[provider];
|
|
11553
|
+
if (!Array.isArray(list))
|
|
11554
|
+
continue;
|
|
11555
|
+
const accounts = [];
|
|
11556
|
+
for (const raw of list) {
|
|
11557
|
+
if (!raw || typeof raw !== "object")
|
|
11558
|
+
continue;
|
|
11559
|
+
const { id, label, key, models } = raw;
|
|
11560
|
+
if (typeof id !== "string" || !id.trim() || typeof key !== "string" || !key.trim())
|
|
11561
|
+
continue;
|
|
11562
|
+
const modelList = Array.isArray(models) ? models.filter((m) => typeof m === "string" && m.trim() !== "").map((m) => m.trim()) : [];
|
|
11563
|
+
accounts.push({ id: id.trim(), label: typeof label === "string" && label.trim() ? label.trim() : null, key: key.trim(), models: modelList });
|
|
11564
|
+
}
|
|
11565
|
+
if (accounts.length > 0)
|
|
11566
|
+
parsed[provider] = accounts;
|
|
11567
|
+
}
|
|
11568
|
+
return parsed;
|
|
11569
|
+
}
|
|
11570
|
+
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;
|
|
11571
|
+
var init_provider_accounts = __esm({
|
|
11572
|
+
"../shared/dist/provider-accounts.js"() {
|
|
11573
|
+
"use strict";
|
|
11574
|
+
init_api_model_catalog();
|
|
11575
|
+
DEFAULT_PROVIDER_ACCOUNT_ID = "primary";
|
|
11576
|
+
PROVIDER_ACCOUNT_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
11577
|
+
MAX_PROVIDER_ACCOUNTS = 10;
|
|
11578
|
+
MAX_PROVIDER_ACCOUNT_MODELS = 50;
|
|
11579
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,120}$/;
|
|
11580
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS = [
|
|
11581
|
+
"deepseek-v4.1-flash",
|
|
11582
|
+
"deepseek-v4-pro",
|
|
11583
|
+
"glm-5.3-flash",
|
|
11584
|
+
"glm-5.3",
|
|
11585
|
+
"glm-5.2"
|
|
11586
|
+
];
|
|
11587
|
+
HOST_PREFIXES = ["opencode-go:", "zai:", "openrouter:"];
|
|
10910
11588
|
}
|
|
10911
11589
|
});
|
|
10912
11590
|
|
|
@@ -11025,6 +11703,25 @@ var init_project_engine_overrides = __esm({
|
|
|
11025
11703
|
}
|
|
11026
11704
|
});
|
|
11027
11705
|
|
|
11706
|
+
// ../shared/dist/trailing-slashes.js
|
|
11707
|
+
function stripTrailingSlashes(value) {
|
|
11708
|
+
let end = value.length;
|
|
11709
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
11710
|
+
end--;
|
|
11711
|
+
return end === value.length ? value : value.slice(0, end);
|
|
11712
|
+
}
|
|
11713
|
+
function stripTrailingChars(value, isTrailing) {
|
|
11714
|
+
let end = value.length;
|
|
11715
|
+
while (end > 0 && isTrailing.test(value[end - 1]))
|
|
11716
|
+
end--;
|
|
11717
|
+
return end === value.length ? value : value.slice(0, end);
|
|
11718
|
+
}
|
|
11719
|
+
var init_trailing_slashes = __esm({
|
|
11720
|
+
"../shared/dist/trailing-slashes.js"() {
|
|
11721
|
+
"use strict";
|
|
11722
|
+
}
|
|
11723
|
+
});
|
|
11724
|
+
|
|
11028
11725
|
// ../shared/dist/gemini-visual.js
|
|
11029
11726
|
function visualProDailyBudget(raw) {
|
|
11030
11727
|
const parsed = raw && /^\s*\d{1,6}\s*$/.test(raw) ? Number(raw.trim()) : NaN;
|
|
@@ -11038,7 +11735,7 @@ function isRetiredGeminiModel(id) {
|
|
|
11038
11735
|
}
|
|
11039
11736
|
function geminiNativeModelsUrl(base = process.env.GEMINI_API_BASE) {
|
|
11040
11737
|
const raw = base && base.trim() || GEMINI_OPENAI_BASE;
|
|
11041
|
-
const native = raw.replace(/\/openai\/?$/, "/")
|
|
11738
|
+
const native = stripTrailingSlashes(raw.replace(/\/openai\/?$/, "/"));
|
|
11042
11739
|
return `${native}/models?pageSize=1000`;
|
|
11043
11740
|
}
|
|
11044
11741
|
function asRecord(value) {
|
|
@@ -11158,6 +11855,7 @@ var KNOWN_INPUT_USD_PER_M, GEMINI_OPENAI_BASE, DEFAULT_GEMINI_SCREEN_MODEL, DEFA
|
|
|
11158
11855
|
var init_gemini_visual = __esm({
|
|
11159
11856
|
"../shared/dist/gemini-visual.js"() {
|
|
11160
11857
|
"use strict";
|
|
11858
|
+
init_trailing_slashes();
|
|
11161
11859
|
KNOWN_INPUT_USD_PER_M = {
|
|
11162
11860
|
"gemini-2.5-flash-lite": 0.1,
|
|
11163
11861
|
"gemini-3.1-flash-lite": 0.25,
|
|
@@ -12500,12 +13198,13 @@ function truncateAtWord(text, max) {
|
|
|
12500
13198
|
const slice = trimmed.slice(0, room + 1);
|
|
12501
13199
|
const lastSpace = slice.lastIndexOf(" ");
|
|
12502
13200
|
const cut = lastSpace > room * 0.5 ? slice.slice(0, lastSpace) : trimmed.slice(0, room);
|
|
12503
|
-
return `${cut
|
|
13201
|
+
return `${stripTrailingChars(cut, TRAILING_PUNCTUATION)}\u2026`;
|
|
12504
13202
|
}
|
|
12505
|
-
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;
|
|
13203
|
+
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;
|
|
12506
13204
|
var init_canvas_support = __esm({
|
|
12507
13205
|
"../shared/dist/canvas-support.js"() {
|
|
12508
13206
|
"use strict";
|
|
13207
|
+
init_trailing_slashes();
|
|
12509
13208
|
CANVAS_UNSUPPORTED_CODE = "canvas_unsupported";
|
|
12510
13209
|
CANVAS_UNSUPPORTED_TITLE = "Games and canvas apps aren't supported yet";
|
|
12511
13210
|
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.";
|
|
@@ -12630,6 +13329,7 @@ var init_canvas_support = __esm({
|
|
|
12630
13329
|
TOUCH_NONE_RE = /touch-action\s{0,8}:\s{0,8}none/;
|
|
12631
13330
|
CODE_TAGS = /* @__PURE__ */ new Set(["script", "link", "flt-glass-pane", "flutter-view", "flt-scene-host"]);
|
|
12632
13331
|
STATIC_STANDARD_MIN_INTERACTIVE = 3;
|
|
13332
|
+
TRAILING_PUNCTUATION = /[\s,;:.\-–—]/u;
|
|
12633
13333
|
}
|
|
12634
13334
|
});
|
|
12635
13335
|
|
|
@@ -12812,22 +13512,22 @@ function joinChainedLines(code) {
|
|
|
12812
13512
|
const trimmed = lines[i].trimStart();
|
|
12813
13513
|
if (last !== -1 && trimmed.startsWith(".") && !trimmed.startsWith("...")) {
|
|
12814
13514
|
if (!lastStripped) {
|
|
12815
|
-
lines[last] =
|
|
13515
|
+
lines[last] = stripLineComment3(lines[last]).trimEnd();
|
|
12816
13516
|
lastStripped = true;
|
|
12817
13517
|
}
|
|
12818
13518
|
if (lines[last].length <= MAX_LINE_CHARS)
|
|
12819
|
-
lines[last] = `${lines[last]} ${
|
|
13519
|
+
lines[last] = `${lines[last]} ${stripLineComment3(trimmed).trimEnd()}`;
|
|
12820
13520
|
lines[i] = "";
|
|
12821
13521
|
continue;
|
|
12822
13522
|
}
|
|
12823
|
-
if (
|
|
13523
|
+
if (stripLineComment3(lines[i]).trim()) {
|
|
12824
13524
|
last = i;
|
|
12825
13525
|
lastStripped = false;
|
|
12826
13526
|
}
|
|
12827
13527
|
}
|
|
12828
13528
|
return lines.join("\n");
|
|
12829
13529
|
}
|
|
12830
|
-
function
|
|
13530
|
+
function stripLineComment3(rawLine) {
|
|
12831
13531
|
if (rawLine.trimStart().startsWith("//"))
|
|
12832
13532
|
return "";
|
|
12833
13533
|
const at = rawLine.indexOf(" // ");
|
|
@@ -12876,7 +13576,7 @@ function analyzeReadinessPolling(rawCode) {
|
|
|
12876
13576
|
offset += rawLine.length + 1;
|
|
12877
13577
|
if (rawLine.length > MAX_LINE_CHARS)
|
|
12878
13578
|
continue;
|
|
12879
|
-
const line =
|
|
13579
|
+
const line = stripLineComment3(rawLine);
|
|
12880
13580
|
if (!line.trim())
|
|
12881
13581
|
continue;
|
|
12882
13582
|
const literals = literalsOf(line);
|
|
@@ -12988,7 +13688,7 @@ function blankBlockComments2(code) {
|
|
|
12988
13688
|
from = close + 2;
|
|
12989
13689
|
}
|
|
12990
13690
|
}
|
|
12991
|
-
function
|
|
13691
|
+
function stripLineComment4(rawLine) {
|
|
12992
13692
|
if (rawLine.trimStart().startsWith("//"))
|
|
12993
13693
|
return "";
|
|
12994
13694
|
const at = rawLine.indexOf(" // ");
|
|
@@ -12999,7 +13699,7 @@ function logicalLines(code) {
|
|
|
12999
13699
|
for (const raw of code.split("\n")) {
|
|
13000
13700
|
if (raw.length > MAX_LINE_CHARS2)
|
|
13001
13701
|
continue;
|
|
13002
|
-
const line =
|
|
13702
|
+
const line = stripLineComment4(raw).trimEnd();
|
|
13003
13703
|
if (!line.trim())
|
|
13004
13704
|
continue;
|
|
13005
13705
|
const trimmed = line.trimStart();
|
|
@@ -13361,8 +14061,19 @@ function short4(text, max) {
|
|
|
13361
14061
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
13362
14062
|
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
13363
14063
|
}
|
|
14064
|
+
function stripFractionZeros(s) {
|
|
14065
|
+
let end = s.length;
|
|
14066
|
+
while (end > 0 && s[end - 1] === "0")
|
|
14067
|
+
end--;
|
|
14068
|
+
if (end === s.length)
|
|
14069
|
+
return s;
|
|
14070
|
+
const dot = s.lastIndexOf(".");
|
|
14071
|
+
if (dot < 0)
|
|
14072
|
+
return s;
|
|
14073
|
+
return s.slice(0, end === dot + 1 ? dot : end);
|
|
14074
|
+
}
|
|
13364
14075
|
function digitsOf(token) {
|
|
13365
|
-
return token.replace(/[^\d.]/g, "")
|
|
14076
|
+
return stripFractionZeros(token.replace(/[^\d.]/g, "")).replace(/^0+(?=\d)/, "");
|
|
13366
14077
|
}
|
|
13367
14078
|
function computes(line) {
|
|
13368
14079
|
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX").replace(LITERAL_ARITH_RE, "N");
|
|
@@ -13580,7 +14291,7 @@ function findExpectCalls(code) {
|
|
|
13580
14291
|
if (!subj)
|
|
13581
14292
|
continue;
|
|
13582
14293
|
const rest = code.slice(subj.end + 1, subj.end + 1 + 80);
|
|
13583
|
-
const mm = /^\s*((?:\.\s*not)
|
|
14294
|
+
const mm = /^\s*((?:\.\s*not\s*)?\.\s*(\w+))\s{0,20}\(/.exec(rest);
|
|
13584
14295
|
if (!mm)
|
|
13585
14296
|
continue;
|
|
13586
14297
|
const argStart = subj.end + 1 + mm[0].length;
|
|
@@ -15530,6 +16241,28 @@ function startsWithRegexLiteral(text) {
|
|
|
15530
16241
|
const t = text.trimStart();
|
|
15531
16242
|
return t[0] === "/" && t[1] !== "/" && t[1] !== "*" && regexLiteralEnd4(t, 0) !== -1;
|
|
15532
16243
|
}
|
|
16244
|
+
function isBareRegexLiteral(text) {
|
|
16245
|
+
const t = text.trimStart();
|
|
16246
|
+
if (t[0] !== "/" || t[1] === "/" || t[1] === "*")
|
|
16247
|
+
return false;
|
|
16248
|
+
const end = regexLiteralEnd4(t, 0);
|
|
16249
|
+
if (end === -1)
|
|
16250
|
+
return false;
|
|
16251
|
+
let i = end;
|
|
16252
|
+
while (i < t.length && /[a-z]/.test(t[i]))
|
|
16253
|
+
i++;
|
|
16254
|
+
while (i < t.length && /\s/.test(t[i]))
|
|
16255
|
+
i++;
|
|
16256
|
+
return i >= t.length || t[i] === ",";
|
|
16257
|
+
}
|
|
16258
|
+
function regexDeclaredNames(code) {
|
|
16259
|
+
const names = /* @__PURE__ */ new Set();
|
|
16260
|
+
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;
|
|
16261
|
+
let m;
|
|
16262
|
+
while ((m = decl.exec(code)) !== null)
|
|
16263
|
+
names.add(m[1]);
|
|
16264
|
+
return names;
|
|
16265
|
+
}
|
|
15533
16266
|
function afterFirstArg(args) {
|
|
15534
16267
|
let depth = 0;
|
|
15535
16268
|
let quote = null;
|
|
@@ -15567,6 +16300,7 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15567
16300
|
let examined = 0;
|
|
15568
16301
|
let line = 1;
|
|
15569
16302
|
let lineAt2 = 0;
|
|
16303
|
+
let regexNames;
|
|
15570
16304
|
while ((m = re.exec(code)) !== null && examined++ < MAX_CALLS && out.length < MAX_REGEX_MATCHER_FINDINGS) {
|
|
15571
16305
|
const subj = readBalanced(code, m.index + m[0].length);
|
|
15572
16306
|
if (!subj)
|
|
@@ -15578,10 +16312,18 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15578
16312
|
if (!args)
|
|
15579
16313
|
continue;
|
|
15580
16314
|
const expected = mm[2] === "toHaveJSProperty" ? afterFirstArg(args.text) : args.text;
|
|
15581
|
-
if (!
|
|
15582
|
-
continue;
|
|
15583
|
-
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain" && (startsWithRegexLiteral(subj.text) || /^new\s+RegExp\b/.test(subj.text.trim())))
|
|
16315
|
+
if (!isBareRegexLiteral(expected))
|
|
15584
16316
|
continue;
|
|
16317
|
+
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain") {
|
|
16318
|
+
const subject = subj.text.trim();
|
|
16319
|
+
if (startsWithRegexLiteral(subject) || /^new\s+RegExp\b/.test(subject))
|
|
16320
|
+
continue;
|
|
16321
|
+
if (/^[A-Za-z_$][\w$]{0,80}$/.test(subject)) {
|
|
16322
|
+
regexNames ??= regexDeclaredNames(code);
|
|
16323
|
+
if (regexNames.has(subject))
|
|
16324
|
+
continue;
|
|
16325
|
+
}
|
|
16326
|
+
}
|
|
15585
16327
|
for (let i = code.indexOf("\n", lineAt2); i !== -1 && i < m.index; i = code.indexOf("\n", i + 1)) {
|
|
15586
16328
|
line++;
|
|
15587
16329
|
lineAt2 = i + 1;
|
|
@@ -15591,9 +16333,12 @@ function analyzeRegexMatchers(rawCode) {
|
|
|
15591
16333
|
return out;
|
|
15592
16334
|
}
|
|
15593
16335
|
function formatRegexMatcherNote(findings) {
|
|
15594
|
-
const lines = findings.map((f) =>
|
|
16336
|
+
const lines = findings.map((f) => {
|
|
16337
|
+
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";
|
|
16338
|
+
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"}.`;
|
|
16339
|
+
});
|
|
15595
16340
|
return `${lines.join("\n")}
|
|
15596
|
-
A regex only works in toMatch, toHaveText, toContainText, toHaveValue and similar text matchers. For
|
|
16341
|
+
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.`;
|
|
15597
16342
|
}
|
|
15598
16343
|
function lintTestQuality(rawCode, opts = {}) {
|
|
15599
16344
|
if (!rawCode || typeof rawCode !== "string")
|
|
@@ -16342,19 +17087,6 @@ var init_fence_runs = __esm({
|
|
|
16342
17087
|
}
|
|
16343
17088
|
});
|
|
16344
17089
|
|
|
16345
|
-
// ../shared/dist/trailing-slashes.js
|
|
16346
|
-
function stripTrailingSlashes(value) {
|
|
16347
|
-
let end = value.length;
|
|
16348
|
-
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
16349
|
-
end--;
|
|
16350
|
-
return end === value.length ? value : value.slice(0, end);
|
|
16351
|
-
}
|
|
16352
|
-
var init_trailing_slashes = __esm({
|
|
16353
|
-
"../shared/dist/trailing-slashes.js"() {
|
|
16354
|
-
"use strict";
|
|
16355
|
-
}
|
|
16356
|
-
});
|
|
16357
|
-
|
|
16358
17090
|
// ../shared/dist/survey-bug-signature.js
|
|
16359
17091
|
function normalizeWords(text) {
|
|
16360
17092
|
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();
|
|
@@ -16378,14 +17110,17 @@ function requestSignatures(text) {
|
|
|
16378
17110
|
const statuses = [...text.matchAll(HTTP_STATUS)].map((m) => ({ status: m[1], at: m.index ?? 0, end: (m.index ?? 0) + m[0].length }));
|
|
16379
17111
|
if (statuses.length === 0)
|
|
16380
17112
|
return [];
|
|
16381
|
-
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) =>
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
17113
|
+
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) => {
|
|
17114
|
+
const rawPath = stripTrailingChars(m[2] ?? m[3] ?? "", PATH_TRAILING_PUNCTUATION);
|
|
17115
|
+
return {
|
|
17116
|
+
method: m[1] ?? null,
|
|
17117
|
+
path: normalizeBugPath(rawPath),
|
|
17118
|
+
// Before normalisation, which turns a segment with a digit (favicon-32x32.png) into :id.
|
|
17119
|
+
incidental: isIncidentalAssetPath(rawPath.split(/[?#]/, 1)[0].toLowerCase()),
|
|
17120
|
+
at: m.index ?? 0,
|
|
17121
|
+
end: (m.index ?? 0) + m[0].length
|
|
17122
|
+
};
|
|
17123
|
+
}).filter((p) => p.path.length > 1);
|
|
16389
17124
|
const out = /* @__PURE__ */ new Map();
|
|
16390
17125
|
for (const { status, at, end } of statuses) {
|
|
16391
17126
|
const lead = STATUS_TO_PATH.exec(text.slice(end, end + 40));
|
|
@@ -16495,11 +17230,12 @@ function dedupeSiteWideSuspectedBugs(drafts) {
|
|
|
16495
17230
|
delete plans.suspectedBugs;
|
|
16496
17231
|
}
|
|
16497
17232
|
}
|
|
16498
|
-
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;
|
|
17233
|
+
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;
|
|
16499
17234
|
var init_survey_bug_signature = __esm({
|
|
16500
17235
|
"../shared/dist/survey-bug-signature.js"() {
|
|
16501
17236
|
"use strict";
|
|
16502
17237
|
init_trailing_slashes();
|
|
17238
|
+
PATH_TRAILING_PUNCTUATION = /[.,;:]/;
|
|
16503
17239
|
SIGNATURE_SOURCE_MAX_CHARS = 800;
|
|
16504
17240
|
UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g;
|
|
16505
17241
|
PREFIXED_ID = /\b[a-z]{1,8}[-_]\d+\b/g;
|
|
@@ -17830,7 +18566,7 @@ function pathIdsIn(text) {
|
|
|
17830
18566
|
function findCounterIdPins(code) {
|
|
17831
18567
|
if (code.length > CLOCK_MAX_CODE_CHARS)
|
|
17832
18568
|
return [];
|
|
17833
|
-
const
|
|
18569
|
+
const clean3 = stripLineComments(blankBlockComments3(code));
|
|
17834
18570
|
const fillValues = [];
|
|
17835
18571
|
const candidates = [];
|
|
17836
18572
|
let seenWrite = false;
|
|
@@ -17838,24 +18574,24 @@ function findCounterIdPins(code) {
|
|
|
17838
18574
|
CALL_RE.lastIndex = 0;
|
|
17839
18575
|
let m;
|
|
17840
18576
|
let calls = 0;
|
|
17841
|
-
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(
|
|
18577
|
+
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(clean3)) !== null) {
|
|
17842
18578
|
const name = m[1];
|
|
17843
18579
|
const open = m.index + m[0].length - 1;
|
|
17844
18580
|
if (VALUE_WRITES.has(name)) {
|
|
17845
18581
|
seenWrite = true;
|
|
17846
|
-
const args2 = argsAt(
|
|
18582
|
+
const args2 = argsAt(clean3, open);
|
|
17847
18583
|
if (args2 !== null)
|
|
17848
18584
|
fillValues.push(...staticStrings(args2));
|
|
17849
18585
|
continue;
|
|
17850
18586
|
}
|
|
17851
18587
|
if (createIndex === -1) {
|
|
17852
|
-
if (name === "click" && seenWrite && isCreateClick(
|
|
18588
|
+
if (name === "click" && seenWrite && isCreateClick(clean3, m.index))
|
|
17853
18589
|
createIndex = m.index;
|
|
17854
18590
|
continue;
|
|
17855
18591
|
}
|
|
17856
18592
|
if (name === "click")
|
|
17857
18593
|
continue;
|
|
17858
|
-
const args = argsAt(
|
|
18594
|
+
const args = argsAt(clean3, open);
|
|
17859
18595
|
if (args === null)
|
|
17860
18596
|
continue;
|
|
17861
18597
|
const isUrl = URL_SINKS.has(name);
|
|
@@ -17874,7 +18610,7 @@ function findCounterIdPins(code) {
|
|
|
17874
18610
|
}
|
|
17875
18611
|
if (createIndex === -1)
|
|
17876
18612
|
return [];
|
|
17877
|
-
const before =
|
|
18613
|
+
const before = clean3.slice(0, createIndex);
|
|
17878
18614
|
let pathIdsBefore = null;
|
|
17879
18615
|
const findings = [];
|
|
17880
18616
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -17898,7 +18634,7 @@ function findCounterIdPins(code) {
|
|
|
17898
18634
|
continue;
|
|
17899
18635
|
}
|
|
17900
18636
|
}
|
|
17901
|
-
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(
|
|
18637
|
+
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(clean3, c.index) });
|
|
17902
18638
|
}
|
|
17903
18639
|
return findings;
|
|
17904
18640
|
}
|
|
@@ -18193,7 +18929,7 @@ var init_suspicious_expectation = __esm({
|
|
|
18193
18929
|
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;
|
|
18194
18930
|
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;
|
|
18195
18931
|
STUCK_VETO_RE = new RegExp(`${NOT_STUCK_RE.source}|${LISTS_STUCK_RE.source}`, "i");
|
|
18196
|
-
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*)
|
|
18932
|
+
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;
|
|
18197
18933
|
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)";
|
|
18198
18934
|
ELLIPSIS = "(?:\\.{3}|\u2026)";
|
|
18199
18935
|
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;
|
|
@@ -18349,7 +19085,7 @@ function outcomeNamedByAssertion(outcome, code) {
|
|
|
18349
19085
|
function namedByStatements(outcome, statements) {
|
|
18350
19086
|
const text = outcomeText(outcome);
|
|
18351
19087
|
if (outcome.type === "url") {
|
|
18352
|
-
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => r
|
|
19088
|
+
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => stripTrailingChars(r, ROUTE_TRAILING_PUNCTUATION)).filter((r) => r.length > 1);
|
|
18353
19089
|
return statements.some((stmt) => {
|
|
18354
19090
|
if (!/\.(?:waitForURL|toHaveURL)\s{0,20}\(/.test(stmt))
|
|
18355
19091
|
return false;
|
|
@@ -18521,7 +19257,7 @@ function evaluatePromotionGate(input, checks = PROMOTION_QUALITY_CHECKS) {
|
|
|
18521
19257
|
...suspiciousTagged ? { suspiciousPass: { mode: suspicious, covered: suspiciousCovered, wouldHold: suspiciousHold } } : {}
|
|
18522
19258
|
};
|
|
18523
19259
|
}
|
|
18524
|
-
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;
|
|
19260
|
+
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;
|
|
18525
19261
|
var init_promotion_quality_gate = __esm({
|
|
18526
19262
|
"../shared/dist/promotion-quality-gate.js"() {
|
|
18527
19263
|
"use strict";
|
|
@@ -18536,11 +19272,12 @@ var init_promotion_quality_gate = __esm({
|
|
|
18536
19272
|
init_run_classification();
|
|
18537
19273
|
init_expected_outcome_coverage();
|
|
18538
19274
|
init_expect_call();
|
|
19275
|
+
init_trailing_slashes();
|
|
18539
19276
|
SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
|
|
18540
19277
|
strengthCheck = {
|
|
18541
19278
|
id: "assertion-strength",
|
|
18542
|
-
run({ code, tags, strengthGate, flagContradictedAdditions }) {
|
|
18543
|
-
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true });
|
|
19279
|
+
run({ code, tags, strengthGate, flagContradictedAdditions, lastActionProof }) {
|
|
19280
|
+
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true, lastActionProof });
|
|
18544
19281
|
if (verdict.severity === "route-bug")
|
|
18545
19282
|
return [{ check: "route-bug" }];
|
|
18546
19283
|
const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
|
|
@@ -18558,7 +19295,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
18558
19295
|
MAX_STATEMENTS = 500;
|
|
18559
19296
|
MAX_STATEMENT_CHARS = 400;
|
|
18560
19297
|
LITERAL_OR_IDENTIFIER = /'(?:[^'\\\n]|\\.){0,500}'|"(?:[^"\\\n]|\\.){0,500}"|`(?:[^`\\]|\\.){0,2000}`|(?<![\w$.])[A-Za-z_$][\w$]{0,60}/g;
|
|
18561
|
-
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}\(/;
|
|
19298
|
+
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}\(/;
|
|
18562
19299
|
FEEDBACK_REGION = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/i;
|
|
18563
19300
|
ONE_SHOT_MESSAGE_REASON = "one-shot success/error banner text";
|
|
18564
19301
|
FEEDBACK_REGION_ALL = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/gi;
|
|
@@ -18617,6 +19354,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
18617
19354
|
"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}\)/
|
|
18618
19355
|
};
|
|
18619
19356
|
ROUTE_TERM = /\/[A-Za-z0-9_./?&=#-]{1,200}/g;
|
|
19357
|
+
ROUTE_TRAILING_PUNCTUATION = /[.,;:!?)]/;
|
|
18620
19358
|
QUOTED_LITERAL = /'([^'\\\n]{3,200})'|"([^"\\\n]{3,200})"|`([^`\\$\n]{3,200})`/g;
|
|
18621
19359
|
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;
|
|
18622
19360
|
MAX_OUTCOME_STATEMENTS = 300;
|
|
@@ -18736,8 +19474,8 @@ ${goalText}`);
|
|
|
18736
19474
|
return count3 > 0 ? [{ check: "locator-fragment", detail: String(count3), soft: true }] : [];
|
|
18737
19475
|
}
|
|
18738
19476
|
};
|
|
18739
|
-
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;
|
|
18740
|
-
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|selectOption|setInputFiles|dragTo|clear)\s*\(/;
|
|
19477
|
+
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;
|
|
19478
|
+
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|dragAndDrop|clear)\s*\(/;
|
|
18741
19479
|
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;
|
|
18742
19480
|
MAX_FILTER_LINES = 2e3;
|
|
18743
19481
|
MAX_FILTER_LINE_CHARS = 600;
|
|
@@ -18852,7 +19590,7 @@ ${goalText}`);
|
|
|
18852
19590
|
});
|
|
18853
19591
|
|
|
18854
19592
|
// ../shared/dist/regex-alternation.js
|
|
18855
|
-
function
|
|
19593
|
+
function closingParens2(source) {
|
|
18856
19594
|
const close = new Int32Array(source.length).fill(-1);
|
|
18857
19595
|
const open = [];
|
|
18858
19596
|
let inClass = false;
|
|
@@ -18877,7 +19615,7 @@ function closingParens(source) {
|
|
|
18877
19615
|
return close;
|
|
18878
19616
|
}
|
|
18879
19617
|
function alternatesAtTop(source) {
|
|
18880
|
-
const close =
|
|
19618
|
+
const close = closingParens2(source);
|
|
18881
19619
|
let start = source.startsWith("^") ? 1 : 0;
|
|
18882
19620
|
let end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
18883
19621
|
while (start < end && source[start] === "(" && close[start] === end - 1) {
|
|
@@ -18926,6 +19664,124 @@ var init_page_evidence = __esm({
|
|
|
18926
19664
|
}
|
|
18927
19665
|
});
|
|
18928
19666
|
|
|
19667
|
+
// ../shared/dist/stated-limits.js
|
|
19668
|
+
function validDate(v) {
|
|
19669
|
+
const [y, m, d] = v.split("-").map(Number);
|
|
19670
|
+
const t = new Date(Date.UTC(y, m - 1, d));
|
|
19671
|
+
return t.getUTCFullYear() === y && t.getUTCMonth() === m - 1 && t.getUTCDate() === d;
|
|
19672
|
+
}
|
|
19673
|
+
function isoFor(type, v) {
|
|
19674
|
+
const re = DATE_RE[type];
|
|
19675
|
+
if (!re || !re.test(v))
|
|
19676
|
+
return false;
|
|
19677
|
+
if (type === "date")
|
|
19678
|
+
return validDate(v);
|
|
19679
|
+
if (type === "datetime-local")
|
|
19680
|
+
return validDate(v.slice(0, 10)) && Number(v.slice(11, 13)) < 24 && Number(v.slice(14, 16)) < 60;
|
|
19681
|
+
if (type === "time")
|
|
19682
|
+
return Number(v.slice(0, 2)) < 24 && Number(v.slice(3, 5)) < 60;
|
|
19683
|
+
if (type === "month")
|
|
19684
|
+
return Number(v.slice(5, 7)) >= 1 && Number(v.slice(5, 7)) <= 12;
|
|
19685
|
+
return Number(v.slice(6, 8)) >= 1 && Number(v.slice(6, 8)) <= 53;
|
|
19686
|
+
}
|
|
19687
|
+
function clean2(raw) {
|
|
19688
|
+
return typeof raw === "string" ? raw.trim() : "";
|
|
19689
|
+
}
|
|
19690
|
+
function statedLimitsFromAttrs(attrs, inputType) {
|
|
19691
|
+
const type = (inputType ?? "").trim().toLowerCase();
|
|
19692
|
+
const limits = [];
|
|
19693
|
+
const add = (k, v) => {
|
|
19694
|
+
limits.push({ k, v });
|
|
19695
|
+
};
|
|
19696
|
+
if (NUMBER_TYPES.has(type)) {
|
|
19697
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
19698
|
+
const v = clean2(attrs[attr]);
|
|
19699
|
+
if (NUMBER_RE.test(v))
|
|
19700
|
+
add(k, v);
|
|
19701
|
+
}
|
|
19702
|
+
const step = clean2(attrs.step);
|
|
19703
|
+
if (NUMBER_RE.test(step) && Number(step) > 0)
|
|
19704
|
+
add("step", step);
|
|
19705
|
+
} else if (type in DATE_RE) {
|
|
19706
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
19707
|
+
const v = clean2(attrs[attr]);
|
|
19708
|
+
if (isoFor(type, v))
|
|
19709
|
+
add(k, v);
|
|
19710
|
+
}
|
|
19711
|
+
} else if (TEXT_TYPES.has(type)) {
|
|
19712
|
+
for (const [attr, k] of [["minlength", "minLength"], ["maxlength", "maxLength"]]) {
|
|
19713
|
+
const v = clean2(attrs[attr]);
|
|
19714
|
+
if (LENGTH_RE.test(v))
|
|
19715
|
+
add(k, String(Number(v)));
|
|
19716
|
+
}
|
|
19717
|
+
const pattern = cleanPattern(clean2(attrs.pattern).slice(0, STATED_PATTERN_MAX));
|
|
19718
|
+
if (pattern)
|
|
19719
|
+
add("pattern", pattern);
|
|
19720
|
+
}
|
|
19721
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
19722
|
+
}
|
|
19723
|
+
function cleanPattern(text) {
|
|
19724
|
+
return text.replace(/[\u0000-\u001f\u007f]/g, "").replace(/[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/g, "");
|
|
19725
|
+
}
|
|
19726
|
+
function readStatedLimits(stored) {
|
|
19727
|
+
if (!stored || typeof stored !== "object" || Array.isArray(stored))
|
|
19728
|
+
return [];
|
|
19729
|
+
const rec = stored;
|
|
19730
|
+
if (rec.v !== STATED_LIMITS_VERSION || !Array.isArray(rec.limits))
|
|
19731
|
+
return [];
|
|
19732
|
+
const out = [];
|
|
19733
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19734
|
+
for (const item of rec.limits.slice(0, MAX_LIMITS * 2)) {
|
|
19735
|
+
if (!item || typeof item !== "object")
|
|
19736
|
+
continue;
|
|
19737
|
+
const { k, v } = item;
|
|
19738
|
+
if (typeof k !== "string" || typeof v !== "string" || !KINDS.includes(k) || seen.has(k))
|
|
19739
|
+
continue;
|
|
19740
|
+
if (v.length === 0 || v.length > STATED_PATTERN_MAX)
|
|
19741
|
+
continue;
|
|
19742
|
+
const text = k === "pattern" ? cleanPattern(v) : v;
|
|
19743
|
+
if (text === "")
|
|
19744
|
+
continue;
|
|
19745
|
+
if (k === "minLength" || k === "maxLength") {
|
|
19746
|
+
if (!LENGTH_RE.test(v))
|
|
19747
|
+
continue;
|
|
19748
|
+
} else if (k === "step") {
|
|
19749
|
+
if (!NUMBER_RE.test(v))
|
|
19750
|
+
continue;
|
|
19751
|
+
} else if (k === "min" || k === "max") {
|
|
19752
|
+
if (!NUMBER_RE.test(v) && !Object.values(DATE_RE).some((re) => re.test(v)))
|
|
19753
|
+
continue;
|
|
19754
|
+
}
|
|
19755
|
+
seen.add(k);
|
|
19756
|
+
out.push({ k, v: text });
|
|
19757
|
+
}
|
|
19758
|
+
return out;
|
|
19759
|
+
}
|
|
19760
|
+
function statedLimitsRecord(limits) {
|
|
19761
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
19762
|
+
}
|
|
19763
|
+
var STATED_LIMITS_VERSION, STATED_PATTERN_MAX, KINDS, MAX_LIMITS, TEXT_TYPES, NUMBER_TYPES, DATE_RE, NUMBER_RE, LENGTH_RE;
|
|
19764
|
+
var init_stated_limits = __esm({
|
|
19765
|
+
"../shared/dist/stated-limits.js"() {
|
|
19766
|
+
"use strict";
|
|
19767
|
+
STATED_LIMITS_VERSION = 1;
|
|
19768
|
+
STATED_PATTERN_MAX = 200;
|
|
19769
|
+
KINDS = ["min", "max", "minLength", "maxLength", "step", "pattern"];
|
|
19770
|
+
MAX_LIMITS = KINDS.length;
|
|
19771
|
+
TEXT_TYPES = /* @__PURE__ */ new Set(["text", "search", "email", "url", "tel", "password", "textarea", ""]);
|
|
19772
|
+
NUMBER_TYPES = /* @__PURE__ */ new Set(["number", "range"]);
|
|
19773
|
+
DATE_RE = {
|
|
19774
|
+
date: /^\d{4}-\d{2}-\d{2}$/,
|
|
19775
|
+
"datetime-local": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/,
|
|
19776
|
+
time: /^\d{2}:\d{2}(?::\d{2})?$/,
|
|
19777
|
+
month: /^\d{4}-\d{2}$/,
|
|
19778
|
+
week: /^\d{4}-W\d{2}$/
|
|
19779
|
+
};
|
|
19780
|
+
NUMBER_RE = /^-?\d{1,15}(?:\.\d{1,10})?$/;
|
|
19781
|
+
LENGTH_RE = /^\d{1,7}$/;
|
|
19782
|
+
}
|
|
19783
|
+
});
|
|
19784
|
+
|
|
18929
19785
|
// ../shared/dist/index.js
|
|
18930
19786
|
var dist_exports = {};
|
|
18931
19787
|
__export(dist_exports, {
|
|
@@ -18933,9 +19789,11 @@ __export(dist_exports, {
|
|
|
18933
19789
|
ACTION_BATCH_MAX_SIZE: () => ACTION_BATCH_MAX_SIZE,
|
|
18934
19790
|
ADDON_DEFINITIONS: () => ADDON_DEFINITIONS,
|
|
18935
19791
|
ADMIN_EMAIL_LIMITS: () => ADMIN_EMAIL_LIMITS,
|
|
19792
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR: () => ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
18936
19793
|
ADMIN_VIEW_DEFAULT_RETURN_TO: () => ADMIN_VIEW_DEFAULT_RETURN_TO,
|
|
18937
19794
|
AGENT_AI_PROVIDER_PREFIXES: () => AGENT_AI_PROVIDER_PREFIXES,
|
|
18938
19795
|
AI_CREDIT_MARGIN: () => AI_CREDIT_MARGIN,
|
|
19796
|
+
ALLOWED_PROVIDER_CHAIN_HOPS: () => ALLOWED_PROVIDER_CHAIN_HOPS,
|
|
18939
19797
|
API_AUTH_HEADERS_ENV_KEY: () => API_AUTH_HEADERS_ENV_KEY,
|
|
18940
19798
|
API_MODEL_CATALOG: () => API_MODEL_CATALOG,
|
|
18941
19799
|
API_MODEL_FIELDS: () => API_MODEL_FIELDS,
|
|
@@ -18975,12 +19833,14 @@ __export(dist_exports, {
|
|
|
18975
19833
|
BUG_TEST_BROKEN_REASON: () => BUG_TEST_BROKEN_REASON,
|
|
18976
19834
|
BUG_TEST_BROKEN_TAG: () => BUG_TEST_BROKEN_TAG,
|
|
18977
19835
|
CACHE_PRICE_PER_M: () => CACHE_PRICE_PER_M,
|
|
19836
|
+
CANCELLED_REASON_PREFIXES: () => CANCELLED_REASON_PREFIXES,
|
|
18978
19837
|
CANVAS_UNSUPPORTED_BODY: () => CANVAS_UNSUPPORTED_BODY,
|
|
18979
19838
|
CANVAS_UNSUPPORTED_CODE: () => CANVAS_UNSUPPORTED_CODE,
|
|
18980
19839
|
CANVAS_UNSUPPORTED_NOT_CHARGED: () => CANVAS_UNSUPPORTED_NOT_CHARGED,
|
|
18981
19840
|
CANVAS_UNSUPPORTED_OVERRIDE_HINT: () => CANVAS_UNSUPPORTED_OVERRIDE_HINT,
|
|
18982
19841
|
CANVAS_UNSUPPORTED_TITLE: () => CANVAS_UNSUPPORTED_TITLE,
|
|
18983
19842
|
CAPTURE_JSON_STRUCTURE_LIMITS: () => CAPTURE_JSON_STRUCTURE_LIMITS,
|
|
19843
|
+
CHAIN_CANCELLED_RUN_ERROR: () => CHAIN_CANCELLED_RUN_ERROR,
|
|
18984
19844
|
CHAT_FAILOVER_KEY: () => CHAT_FAILOVER_KEY,
|
|
18985
19845
|
CLAUDE_CLI_DEFAULT_EFFORT: () => CLAUDE_CLI_DEFAULT_EFFORT,
|
|
18986
19846
|
CLAUDE_CLI_DEFAULT_MODEL: () => CLAUDE_CLI_DEFAULT_MODEL,
|
|
@@ -19017,6 +19877,7 @@ __export(dist_exports, {
|
|
|
19017
19877
|
DEFAULT_GEMINI_SCREEN_MODEL: () => DEFAULT_GEMINI_SCREEN_MODEL,
|
|
19018
19878
|
DEFAULT_JSON_STRUCTURE_LIMITS: () => DEFAULT_JSON_STRUCTURE_LIMITS,
|
|
19019
19879
|
DEFAULT_PLATFORM_DB_POOL_SIZE: () => DEFAULT_PLATFORM_DB_POOL_SIZE,
|
|
19880
|
+
DEFAULT_PROVIDER_ACCOUNT_ID: () => DEFAULT_PROVIDER_ACCOUNT_ID,
|
|
19020
19881
|
DEFAULT_SHARED_DB_POOL_SIZE: () => DEFAULT_SHARED_DB_POOL_SIZE,
|
|
19021
19882
|
DEFAULT_STT_MODEL: () => DEFAULT_STT_MODEL,
|
|
19022
19883
|
DEFAULT_STT_MODEL_BY_PROVIDER: () => DEFAULT_STT_MODEL_BY_PROVIDER,
|
|
@@ -19033,6 +19894,7 @@ __export(dist_exports, {
|
|
|
19033
19894
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES: () => ENVIRONMENTAL_ERROR_STORED_PREFIXES,
|
|
19034
19895
|
EVIDENCE_NOTE_PREFIXES: () => EVIDENCE_NOTE_PREFIXES,
|
|
19035
19896
|
EXPECT_CALL_RE: () => EXPECT_CALL_RE,
|
|
19897
|
+
FEATURE_ROW_RUN_WINDOW: () => FEATURE_ROW_RUN_WINDOW,
|
|
19036
19898
|
FLOW_PHASE_LABELS: () => FLOW_PHASE_LABELS,
|
|
19037
19899
|
FLOW_PHASE_TYPES: () => FLOW_PHASE_TYPES,
|
|
19038
19900
|
FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
|
|
@@ -19100,6 +19962,8 @@ __export(dist_exports, {
|
|
|
19100
19962
|
MAX_ORG_NAME_LENGTH: () => MAX_ORG_NAME_LENGTH,
|
|
19101
19963
|
MAX_PASSWORD_BYTES: () => MAX_PASSWORD_BYTES,
|
|
19102
19964
|
MAX_PLAYWRIGHT_CODE_LENGTH: () => MAX_PLAYWRIGHT_CODE_LENGTH,
|
|
19965
|
+
MAX_PROVIDER_ACCOUNTS: () => MAX_PROVIDER_ACCOUNTS,
|
|
19966
|
+
MAX_PROVIDER_ACCOUNT_MODELS: () => MAX_PROVIDER_ACCOUNT_MODELS,
|
|
19103
19967
|
MAX_SURVEY_ENTRY_URLS: () => MAX_SURVEY_ENTRY_URLS,
|
|
19104
19968
|
MAX_SURVEY_ENTRY_URL_LENGTH: () => MAX_SURVEY_ENTRY_URL_LENGTH,
|
|
19105
19969
|
MCP_ARMY_LIMITS: () => MCP_ARMY_LIMITS,
|
|
@@ -19135,7 +19999,7 @@ __export(dist_exports, {
|
|
|
19135
19999
|
MUSE_ENGINE_DEFAULT_MODEL: () => MUSE_ENGINE_DEFAULT_MODEL,
|
|
19136
20000
|
MUSE_ENGINE_MODELS: () => MUSE_ENGINE_MODELS,
|
|
19137
20001
|
NOREPLY_EMAIL: () => NOREPLY_EMAIL,
|
|
19138
|
-
|
|
20002
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS: () => OPENCODE_GO_DEEPSEEK_GLM_MODELS,
|
|
19139
20003
|
OPENCODE_GO_MODEL_PATTERN: () => OPENCODE_GO_MODEL_PATTERN,
|
|
19140
20004
|
OPENCODE_GO_PREFIX: () => OPENCODE_GO_PREFIX,
|
|
19141
20005
|
OPENROUTER_MAX_CALL_COST_USD: () => OPENROUTER_MAX_CALL_COST_USD,
|
|
@@ -19155,10 +20019,12 @@ __export(dist_exports, {
|
|
|
19155
20019
|
PLAN_FEATURES: () => PLAN_FEATURES,
|
|
19156
20020
|
PLAN_FEATURE_LOCKED_CODE: () => PLAN_FEATURE_LOCKED_CODE,
|
|
19157
20021
|
PLAN_ORDER: () => PLAN_ORDER,
|
|
20022
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR: () => PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
19158
20023
|
PLATFORM_ADMIN_EMAIL: () => PLATFORM_ADMIN_EMAIL,
|
|
19159
20024
|
PLATFORM_DEFAULT_PROVIDER: () => PLATFORM_DEFAULT_PROVIDER,
|
|
19160
20025
|
PLATFORM_PLAN_BILLING: () => PLATFORM_PLAN_BILLING,
|
|
19161
20026
|
PLATFORM_SERVER_APPLICATION_NAME: () => PLATFORM_SERVER_APPLICATION_NAME,
|
|
20027
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR: () => PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
19162
20028
|
POST_SPECIAL_TRIAL_DAYS: () => POST_SPECIAL_TRIAL_DAYS,
|
|
19163
20029
|
PRESET_DIRECT_FALLBACK: () => PRESET_DIRECT_FALLBACK,
|
|
19164
20030
|
PRODUCTION_READ_ONLY_GUARD_TEMPLATE: () => PRODUCTION_READ_ONLY_GUARD_TEMPLATE,
|
|
@@ -19170,8 +20036,12 @@ __export(dist_exports, {
|
|
|
19170
20036
|
PROJECT_OVERRIDE_FIELDS: () => PROJECT_OVERRIDE_FIELDS,
|
|
19171
20037
|
PROMOTION_GATE_MAX_CODE_CHARS: () => PROMOTION_GATE_MAX_CODE_CHARS,
|
|
19172
20038
|
PROMOTION_QUALITY_CHECKS: () => PROMOTION_QUALITY_CHECKS,
|
|
20039
|
+
PROVIDER_ACCOUNT_ID_PATTERN: () => PROVIDER_ACCOUNT_ID_PATTERN,
|
|
20040
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN: () => PROVIDER_ACCOUNT_MODEL_PATTERN,
|
|
19173
20041
|
PROVIDER_CHAINS: () => PROVIDER_CHAINS,
|
|
20042
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS: () => PROVIDER_CHAINS_SETTING_MAX_CHARS,
|
|
19174
20043
|
PROVIDER_CHAIN_LEADS: () => PROVIDER_CHAIN_LEADS,
|
|
20044
|
+
PROVIDER_CHAIN_MAX_ENTRIES: () => PROVIDER_CHAIN_MAX_ENTRIES,
|
|
19175
20045
|
PROVIDER_HOST_NOT_OFFERED: () => PROVIDER_HOST_NOT_OFFERED,
|
|
19176
20046
|
PUBLIC_PLANS: () => PUBLIC_PLANS,
|
|
19177
20047
|
QUARANTINE_CLOSE_TAGS: () => QUARANTINE_CLOSE_TAGS,
|
|
@@ -19179,10 +20049,12 @@ __export(dist_exports, {
|
|
|
19179
20049
|
READ_ONLY_TAGS: () => READ_ONLY_TAGS,
|
|
19180
20050
|
RECHECKED_NOTES: () => RECHECKED_NOTES,
|
|
19181
20051
|
RECORDING_VALUE_PLACEHOLDERS: () => RECORDING_VALUE_PLACEHOLDERS,
|
|
20052
|
+
RENDER_IDENTITY_MAX_LENGTH: () => RENDER_IDENTITY_MAX_LENGTH,
|
|
19182
20053
|
REPOSITORY_CLIS: () => REPOSITORY_CLIS,
|
|
19183
20054
|
RESERVED_PROJECT_KEYS: () => RESERVED_PROJECT_KEYS,
|
|
19184
20055
|
RESULT_STRUCTURE_TOO_COSTLY_CODE: () => RESULT_STRUCTURE_TOO_COSTLY_CODE,
|
|
19185
20056
|
RETRIED_ATTEMPTS_KEY: () => RETRIED_ATTEMPTS_KEY,
|
|
20057
|
+
RETRY_HELD_RUN_ERROR: () => RETRY_HELD_RUN_ERROR,
|
|
19186
20058
|
RUNNER_INTERRUPT_ERROR_PREFIX: () => RUNNER_INTERRUPT_ERROR_PREFIX,
|
|
19187
20059
|
RUN_INTERRUPTED_ERROR_PREFIXES: () => RUN_INTERRUPTED_ERROR_PREFIXES,
|
|
19188
20060
|
RUN_INTERRUPTION_NOT_RETRIED_MARKERS: () => RUN_INTERRUPTION_NOT_RETRIED_MARKERS,
|
|
@@ -19195,6 +20067,8 @@ __export(dist_exports, {
|
|
|
19195
20067
|
SHARED_SERVER_APPLICATION_NAME: () => SHARED_SERVER_APPLICATION_NAME,
|
|
19196
20068
|
SPEND_SOURCE_KEY: () => SPEND_SOURCE_KEY,
|
|
19197
20069
|
SPEND_SOURCE_SERVER: () => SPEND_SOURCE_SERVER,
|
|
20070
|
+
STATED_LIMITS_VERSION: () => STATED_LIMITS_VERSION,
|
|
20071
|
+
STATED_PATTERN_MAX: () => STATED_PATTERN_MAX,
|
|
19198
20072
|
STATIC_STANDARD_MIN_INTERACTIVE: () => STATIC_STANDARD_MIN_INTERACTIVE,
|
|
19199
20073
|
STT_MODEL_OPTIONS: () => STT_MODEL_OPTIONS,
|
|
19200
20074
|
SUCCESS_NOTICE_TEXT: () => SUCCESS_NOTICE_TEXT,
|
|
@@ -19224,14 +20098,20 @@ __export(dist_exports, {
|
|
|
19224
20098
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
19225
20099
|
UNEXPECTED_PASS_ERROR_PREFIX: () => UNEXPECTED_PASS_ERROR_PREFIX,
|
|
19226
20100
|
USER_CANCELLED_RUN_ERROR: () => USER_CANCELLED_RUN_ERROR,
|
|
20101
|
+
VISUAL_MASK_SELECTORS_MAX: () => VISUAL_MASK_SELECTORS_MAX,
|
|
20102
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN: () => VISUAL_MASK_SELECTOR_FORBIDDEN,
|
|
20103
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH: () => VISUAL_MASK_SELECTOR_MAX_LENGTH,
|
|
20104
|
+
VISUAL_V1_IDENTITY: () => VISUAL_V1_IDENTITY,
|
|
19227
20105
|
VOICE_PREVIEW_SAMPLE: () => VOICE_PREVIEW_SAMPLE,
|
|
19228
20106
|
WEB_PROXY_CHAIN_HEADER: () => WEB_PROXY_CHAIN_HEADER,
|
|
19229
20107
|
WITHHELD_CREDENTIAL_TEXT: () => WITHHELD_CREDENTIAL_TEXT,
|
|
19230
20108
|
ZAI_MODEL_PATTERN: () => ZAI_MODEL_PATTERN,
|
|
19231
20109
|
ZAI_PREFIX: () => ZAI_PREFIX,
|
|
20110
|
+
accountServesModel: () => accountServesModel,
|
|
19232
20111
|
accumulateStatements: () => accumulateStatements,
|
|
19233
20112
|
adoptBrokerFailover: () => adoptBrokerFailover,
|
|
19234
20113
|
aiCostToCreditCents: () => aiCostToCreditCents,
|
|
20114
|
+
allowedProviderChainHosts: () => allowedProviderChainHosts,
|
|
19235
20115
|
alternatesAtTop: () => alternatesAtTop,
|
|
19236
20116
|
analyzeDerivedValues: () => analyzeDerivedValues,
|
|
19237
20117
|
analyzeMobileSelectorQuality: () => analyzeMobileSelectorQuality,
|
|
@@ -19244,6 +20124,7 @@ __export(dist_exports, {
|
|
|
19244
20124
|
analyzeUnreachedUrlWaits: () => analyzeUnreachedUrlWaits,
|
|
19245
20125
|
analyzeUrlWaits: () => analyzeUrlWaits,
|
|
19246
20126
|
analyzeWriteResponse: () => analyzeWriteResponse,
|
|
20127
|
+
androidResourceOwners: () => androidResourceOwners,
|
|
19247
20128
|
apiModelCardsFromConfig: () => apiModelCardsFromConfig,
|
|
19248
20129
|
apiModelsForProvider: () => apiModelsForProvider,
|
|
19249
20130
|
apiProviderModelLabel: () => apiProviderModelLabel,
|
|
@@ -19254,6 +20135,7 @@ __export(dist_exports, {
|
|
|
19254
20135
|
applyLaunchSpecialPlan: () => applyLaunchSpecialPlan,
|
|
19255
20136
|
asPlainExpect: () => asPlainExpect,
|
|
19256
20137
|
assertionOnlyCode: () => assertionOnlyCode,
|
|
20138
|
+
assertionStrengthHoistedReadsOn: () => assertionStrengthHoistedReadsOn,
|
|
19257
20139
|
assertionsReadVisibleContent: () => assertionsReadVisibleContent,
|
|
19258
20140
|
assessCodeOutcomeCoverage: () => assessCodeOutcomeCoverage,
|
|
19259
20141
|
assessTitleCoverage: () => assessTitleCoverage,
|
|
@@ -19337,6 +20219,7 @@ __export(dist_exports, {
|
|
|
19337
20219
|
deepgramSpeak: () => deepgramSpeak,
|
|
19338
20220
|
deepgramTranscribe: () => deepgramTranscribe,
|
|
19339
20221
|
defaultConfirmModel: () => defaultConfirmModel,
|
|
20222
|
+
defaultProviderChainEntries: () => defaultProviderChainEntries,
|
|
19340
20223
|
defaultScreenModel: () => defaultScreenModel,
|
|
19341
20224
|
defaultVoiceForTtsModel: () => defaultVoiceForTtsModel,
|
|
19342
20225
|
deriveAuthPlan: () => deriveAuthPlan,
|
|
@@ -19379,6 +20262,7 @@ __export(dist_exports, {
|
|
|
19379
20262
|
extractOutcomeSearchTerms: () => extractOutcomeSearchTerms,
|
|
19380
20263
|
featureForAiCallType: () => featureForAiCallType,
|
|
19381
20264
|
featureForMcpTool: () => featureForMcpTool,
|
|
20265
|
+
featureRowRunStatus: () => featureRowRunStatus,
|
|
19382
20266
|
findBracedClause: () => findBracedClause,
|
|
19383
20267
|
findCounterIdPins: () => findCounterIdPins,
|
|
19384
20268
|
findCredentialTextLeftover: () => findCredentialTextLeftover,
|
|
@@ -19427,6 +20311,7 @@ __export(dist_exports, {
|
|
|
19427
20311
|
getPlanChangeType: () => getPlanChangeType,
|
|
19428
20312
|
getPlanDefinition: () => getPlanDefinition,
|
|
19429
20313
|
getPlanLabel: () => getPlanLabel,
|
|
20314
|
+
getProviderChainOverrides: () => getProviderChainOverrides,
|
|
19430
20315
|
getTrialDaysRemaining: () => getTrialDaysRemaining,
|
|
19431
20316
|
googleBrokerNavigationUrl: () => googleBrokerNavigationUrl,
|
|
19432
20317
|
googleBrokerUnavailableLine: () => googleBrokerUnavailableLine,
|
|
@@ -19440,10 +20325,10 @@ __export(dist_exports, {
|
|
|
19440
20325
|
hasEncodedRequestBody: () => hasEncodedRequestBody,
|
|
19441
20326
|
hasEngineSpecParts: () => hasEngineSpecParts,
|
|
19442
20327
|
hasOnlyConstantAssertions: () => hasOnlyConstantAssertions,
|
|
19443
|
-
hasOpenCodeGo2Prefix: () => hasOpenCodeGo2Prefix,
|
|
19444
20328
|
hasOpenCodeGoPrefix: () => hasOpenCodeGoPrefix,
|
|
19445
20329
|
hasOpenRouterPrefix: () => hasOpenRouterPrefix,
|
|
19446
20330
|
hasPlatformLocator: () => hasPlatformLocator,
|
|
20331
|
+
hasProviderChainLeadsByDefault: () => hasProviderChainLeadsByDefault,
|
|
19447
20332
|
hasReadOnlyMarker: () => hasReadOnlyMarker,
|
|
19448
20333
|
hasSurveyNotes: () => hasSurveyNotes,
|
|
19449
20334
|
hasTestFailContract: () => hasTestFailContract,
|
|
@@ -19469,8 +20354,11 @@ __export(dist_exports, {
|
|
|
19469
20354
|
isAuthTokenName: () => isAuthTokenName,
|
|
19470
20355
|
isBlockedEnvVar: () => isBlockedEnvVar,
|
|
19471
20356
|
isBrowserCliEngine: () => isBrowserCliEngine,
|
|
20357
|
+
isBrowserVersion: () => isBrowserVersion,
|
|
19472
20358
|
isBugTestBrokenError: () => isBugTestBrokenError,
|
|
20359
|
+
isCancelledReason: () => isCancelledReason,
|
|
19473
20360
|
isCanvasUnsupportedMessage: () => isCanvasUnsupportedMessage,
|
|
20361
|
+
isChainablePrimary: () => isChainablePrimary,
|
|
19474
20362
|
isCliEngineModelId: () => isCliEngineModelId,
|
|
19475
20363
|
isCliEngineSpec: () => isCliEngineSpec,
|
|
19476
20364
|
isCodeFactNote: () => isCodeFactNote,
|
|
@@ -19494,6 +20382,7 @@ __export(dist_exports, {
|
|
|
19494
20382
|
isIdentityMobileXpath: () => isIdentityMobileXpath,
|
|
19495
20383
|
isIdentityProviderSurface: () => isIdentityProviderSurface,
|
|
19496
20384
|
isIncidentalAssetPath: () => isIncidentalAssetPath,
|
|
20385
|
+
isIntentionalNegativeAuthTest: () => isIntentionalNegativeAuthTest,
|
|
19497
20386
|
isIpOrLocalhost: () => isIpOrLocalhost,
|
|
19498
20387
|
isKnownPageType: () => isKnownPageType,
|
|
19499
20388
|
isLaunchSpecialActive: () => isLaunchSpecialActive,
|
|
@@ -19521,6 +20410,7 @@ __export(dist_exports, {
|
|
|
19521
20410
|
isRunInterruptedError: () => isRunInterruptedError,
|
|
19522
20411
|
isRunnableStep: () => isRunnableStep,
|
|
19523
20412
|
isSafeDeepLink: () => isSafeDeepLink,
|
|
20413
|
+
isSafeMaskSelector: () => isSafeMaskSelector,
|
|
19524
20414
|
isSameRegistrableDomainHost: () => isSameRegistrableDomainHost,
|
|
19525
20415
|
isSelectableApiModel: () => isSelectableApiModel,
|
|
19526
20416
|
isSelfServePlan: () => isSelfServePlan,
|
|
@@ -19584,6 +20474,7 @@ __export(dist_exports, {
|
|
|
19584
20474
|
normalizeFinishReason: () => normalizeFinishReason,
|
|
19585
20475
|
normalizeNoteText: () => normalizeNoteText,
|
|
19586
20476
|
normalizePageType: () => normalizePageType,
|
|
20477
|
+
normalizeProviderAccountModels: () => normalizeProviderAccountModels,
|
|
19587
20478
|
normalizeTtsModel: () => normalizeTtsModel,
|
|
19588
20479
|
normalizeTtsVoiceId: () => normalizeTtsVoiceId,
|
|
19589
20480
|
noteChatFailover: () => noteChatFailover,
|
|
@@ -19608,13 +20499,18 @@ __export(dist_exports, {
|
|
|
19608
20499
|
parseGeminiModelsPayload: () => parseGeminiModelsPayload,
|
|
19609
20500
|
parseGoogleAuthorizeUrl: () => parseGoogleAuthorizeUrl,
|
|
19610
20501
|
parseGoogleGisRequestUrl: () => parseGoogleGisRequestUrl,
|
|
20502
|
+
parseLastActionProofMode: () => parseLastActionProofMode,
|
|
19611
20503
|
parseLimitParam: () => parseLimitParam,
|
|
19612
20504
|
parseOffsetParam: () => parseOffsetParam,
|
|
19613
20505
|
parsePageParam: () => parsePageParam,
|
|
19614
20506
|
parsePgIntSetting: () => parsePgIntSetting,
|
|
19615
20507
|
parseProjectEngineOverrides: () => parseProjectEngineOverrides,
|
|
19616
20508
|
parsePromotionGateMode: () => parsePromotionGateMode,
|
|
20509
|
+
parseProviderAccountLists: () => parseProviderAccountLists,
|
|
20510
|
+
parseProviderChainOverrides: () => parseProviderChainOverrides,
|
|
19617
20511
|
parseRecheckClearMode: () => parseRecheckClearMode,
|
|
20512
|
+
parseRenderIdentity: () => parseRenderIdentity,
|
|
20513
|
+
parseStoredProviderChainOverrides: () => parseStoredProviderChainOverrides,
|
|
19618
20514
|
parseSurveyEntryUrls: () => parseSurveyEntryUrls,
|
|
19619
20515
|
parseSuspiciousPassMode: () => parseSuspiciousPassMode,
|
|
19620
20516
|
parseTaskModelUpdate: () => parseTaskModelUpdate,
|
|
@@ -19645,7 +20541,9 @@ __export(dist_exports, {
|
|
|
19645
20541
|
projectAppHosts: () => projectAppHosts,
|
|
19646
20542
|
providerChainFor: () => providerChainFor,
|
|
19647
20543
|
providerChainHostOf: () => providerChainHostOf,
|
|
20544
|
+
providerChainHostProvider: () => providerChainHostProvider,
|
|
19648
20545
|
providerChainLeadsFor: () => providerChainLeadsFor,
|
|
20546
|
+
providerChainModelKey: () => providerChainModelKey,
|
|
19649
20547
|
providerChainPrimariesForHop: () => providerChainPrimariesForHop,
|
|
19650
20548
|
providerHostPlan: () => providerHostPlan,
|
|
19651
20549
|
readBalanced: () => readBalanced,
|
|
@@ -19655,6 +20553,7 @@ __export(dist_exports, {
|
|
|
19655
20553
|
readEnabledEngines: () => readEnabledEngines,
|
|
19656
20554
|
readProjectEngineOverrides: () => readProjectEngineOverrides,
|
|
19657
20555
|
readRetriedAttempts: () => readRetriedAttempts,
|
|
20556
|
+
readStatedLimits: () => readStatedLimits,
|
|
19658
20557
|
readStaticPageCanvasSignals: () => readStaticPageCanvasSignals,
|
|
19659
20558
|
readSurveyEntryUrls: () => readSurveyEntryUrls,
|
|
19660
20559
|
readSurveyNotes: () => readSurveyNotes,
|
|
@@ -19667,6 +20566,7 @@ __export(dist_exports, {
|
|
|
19667
20566
|
regexLiteralEnd: () => regexLiteralEnd2,
|
|
19668
20567
|
regexOpensAfter: () => regexOpensAfter,
|
|
19669
20568
|
registrableDomain: () => registrableDomain,
|
|
20569
|
+
renderIdentity: () => renderIdentity,
|
|
19670
20570
|
renderSurveyNotesForPrompt: () => renderSurveyNotesForPrompt,
|
|
19671
20571
|
repairPageType: () => repairPageType,
|
|
19672
20572
|
replaceBlockComments: () => replaceBlockComments,
|
|
@@ -19714,11 +20614,14 @@ __export(dist_exports, {
|
|
|
19714
20614
|
selectorCandidatesForStep: () => selectorCandidatesForStep,
|
|
19715
20615
|
selectorForValue: () => selectorForValue,
|
|
19716
20616
|
setAgenticCliRuntime: () => setAgenticCliRuntime,
|
|
20617
|
+
setProviderChainOverrides: () => setProviderChainOverrides,
|
|
19717
20618
|
signupPlanFor: () => signupPlanFor,
|
|
19718
20619
|
simplifyMobileWanderingInPlace: () => simplifyMobileWanderingInPlace,
|
|
19719
20620
|
siteOf: () => siteOf,
|
|
19720
20621
|
specItemsFromTestPlans: () => specItemsFromTestPlans,
|
|
19721
20622
|
splitAnswerLines: () => splitAnswerLines,
|
|
20623
|
+
statedLimitsFromAttrs: () => statedLimitsFromAttrs,
|
|
20624
|
+
statedLimitsRecord: () => statedLimitsRecord,
|
|
19722
20625
|
stepAppliesToPlatform: () => stepAppliesToPlatform,
|
|
19723
20626
|
stepConsoleLines: () => stepConsoleLines,
|
|
19724
20627
|
stepIsDivergentForPlatform: () => stepIsDivergentForPlatform,
|
|
@@ -19730,7 +20633,10 @@ __export(dist_exports, {
|
|
|
19730
20633
|
stripCodeFactPrefix: () => stripCodeFactPrefix,
|
|
19731
20634
|
stripCoverageComments: () => stripCoverageComments,
|
|
19732
20635
|
stripEnvironmentalPrefix: () => stripEnvironmentalPrefix,
|
|
20636
|
+
stripFractionZeros: () => stripFractionZeros,
|
|
20637
|
+
stripLineComment: () => stripLineComment,
|
|
19733
20638
|
stripLoginScaffolding: () => stripLoginScaffolding,
|
|
20639
|
+
stripTrailingChars: () => stripTrailingChars,
|
|
19734
20640
|
stripTrailingSlashes: () => stripTrailingSlashes,
|
|
19735
20641
|
strongerNeedsReviewSource: () => strongerNeedsReviewSource,
|
|
19736
20642
|
sttModelsForProvider: () => sttModelsForProvider,
|
|
@@ -19748,10 +20654,14 @@ __export(dist_exports, {
|
|
|
19748
20654
|
ttsFallbackModel: () => ttsFallbackModel,
|
|
19749
20655
|
ttsProviderForModel: () => ttsProviderForModel,
|
|
19750
20656
|
unexpectedPassError: () => unexpectedPassError,
|
|
20657
|
+
v1RenderIdentity: () => v1RenderIdentity,
|
|
19751
20658
|
validateAppMapDocument: () => validateAppMapDocument,
|
|
19752
20659
|
validateAssertionStrength: () => validateAssertionStrength,
|
|
19753
20660
|
validateEngineSpec: () => validateEngineSpec,
|
|
20661
|
+
validateProviderChainEntries: () => validateProviderChainEntries,
|
|
20662
|
+
validateProviderChainsSetting: () => validateProviderChainsSetting,
|
|
19754
20663
|
validateTaskModelId: () => validateTaskModelId,
|
|
20664
|
+
visualBaselinesEnabled: () => visualBaselinesEnabled,
|
|
19755
20665
|
visualProDailyBudget: () => visualProDailyBudget,
|
|
19756
20666
|
voiceMatchesTtsModel: () => voiceMatchesTtsModel,
|
|
19757
20667
|
voicesForTtsModel: () => voicesForTtsModel,
|
|
@@ -19814,11 +20724,14 @@ var init_dist = __esm({
|
|
|
19814
20724
|
init_deepgram_voices();
|
|
19815
20725
|
init_feature_flags();
|
|
19816
20726
|
init_env_flags();
|
|
20727
|
+
init_visual_compare_limits();
|
|
20728
|
+
init_visual_baseline_identity();
|
|
19817
20729
|
init_analytics_url();
|
|
19818
20730
|
init_agentic_cli_runtime();
|
|
19819
20731
|
init_api_model_catalog();
|
|
19820
20732
|
init_engine_spec();
|
|
19821
20733
|
init_provider_chains();
|
|
20734
|
+
init_provider_accounts();
|
|
19822
20735
|
init_project_engine_overrides();
|
|
19823
20736
|
init_ai_profiles();
|
|
19824
20737
|
init_openrouter_usage();
|
|
@@ -19860,6 +20773,7 @@ var init_dist = __esm({
|
|
|
19860
20773
|
init_regex_alternation();
|
|
19861
20774
|
init_page_evidence();
|
|
19862
20775
|
init_trailing_slashes();
|
|
20776
|
+
init_stated_limits();
|
|
19863
20777
|
}
|
|
19864
20778
|
});
|
|
19865
20779
|
|
|
@@ -19888,11 +20802,11 @@ export {
|
|
|
19888
20802
|
stepsNeedingReviewForPlatform,
|
|
19889
20803
|
parseBoolFlag,
|
|
19890
20804
|
decideHarPosted,
|
|
20805
|
+
deriveAuthPlan,
|
|
19891
20806
|
isConfigLikeReason,
|
|
19892
20807
|
classifyErrorMessage,
|
|
19893
20808
|
isAppOriginResolutionEnabled,
|
|
19894
20809
|
resolveCrossOriginConfigOverride,
|
|
19895
|
-
deriveAuthPlan,
|
|
19896
20810
|
isSharedAuthInjectEnabled,
|
|
19897
20811
|
isRepositoryCli,
|
|
19898
20812
|
repositoryCliLabel,
|