@guidelytech/shared 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-TGIUEYXM.js +1937 -0
- package/dist/chunk-TGIUEYXM.js.map +1 -0
- package/dist/chunk-XJXXVV3C.js +1941 -0
- package/dist/chunk-XJXXVV3C.js.map +1 -0
- package/dist/index.cjs +1655 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +763 -3956
- package/dist/index.d.ts +763 -3956
- package/dist/index.js +538 -62
- package/dist/index.js.map +1 -1
- package/dist/runtime-BM5cztmJ.d.cts +5234 -0
- package/dist/runtime-BM5cztmJ.d.ts +5234 -0
- package/dist/runtime-BeSHQtNX.d.cts +5263 -0
- package/dist/runtime-BeSHQtNX.d.ts +5263 -0
- package/dist/runtime.cjs +1218 -7
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +2 -511
- package/dist/runtime.d.ts +2 -511
- package/dist/runtime.js +159 -1
- package/package.json +1 -1
package/dist/runtime.cjs
CHANGED
|
@@ -20,16 +20,33 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/runtime.ts
|
|
21
21
|
var runtime_exports = {};
|
|
22
22
|
__export(runtime_exports, {
|
|
23
|
+
AGENT_METADATA_MAX_BYTES: () => AGENT_METADATA_MAX_BYTES,
|
|
24
|
+
AGENT_METADATA_MAX_KEYS: () => AGENT_METADATA_MAX_KEYS,
|
|
25
|
+
AGENT_OUTCOMES: () => AGENT_OUTCOMES,
|
|
26
|
+
AGENT_TOOL_CALLS_PER_TURN: () => AGENT_TOOL_CALLS_PER_TURN,
|
|
27
|
+
AGENT_TOOL_STATUSES: () => AGENT_TOOL_STATUSES,
|
|
28
|
+
AGENT_TURNS_PER_BATCH: () => AGENT_TURNS_PER_BATCH,
|
|
29
|
+
AGENT_TURN_MAX_TEXT: () => AGENT_TURN_MAX_TEXT,
|
|
30
|
+
AGENT_TURN_ROLES: () => AGENT_TURN_ROLES,
|
|
23
31
|
ARTICLE_VISIBILITIES: () => ARTICLE_VISIBILITIES,
|
|
24
32
|
CAPTURE_PARAM: () => CAPTURE_PARAM,
|
|
25
33
|
CAPTURE_SCREENSHOT_MAX_BYTES: () => CAPTURE_SCREENSHOT_MAX_BYTES,
|
|
34
|
+
COMMON_LOCALES: () => COMMON_LOCALES,
|
|
26
35
|
COMPLAINT_EVENTS: () => COMPLAINT_EVENTS,
|
|
27
36
|
COMPLAINT_FIELD_TYPES: () => COMPLAINT_FIELD_TYPES,
|
|
28
37
|
COMPLAINT_STATUSES: () => COMPLAINT_STATUSES,
|
|
38
|
+
CONTROL_VARIANT_ID: () => CONTROL_VARIANT_ID,
|
|
39
|
+
DEFAULT_FEATURE_ATTRIBUTE: () => DEFAULT_FEATURE_ATTRIBUTE,
|
|
40
|
+
DEFAULT_LOCALE: () => DEFAULT_LOCALE,
|
|
29
41
|
DEFAULT_PLATFORMS: () => DEFAULT_PLATFORMS,
|
|
30
42
|
EMBED_IFRAME_ATTRS: () => EMBED_IFRAME_ATTRS,
|
|
43
|
+
FEATURE_ATTRIBUTE_PATTERN: () => FEATURE_ATTRIBUTE_PATTERN,
|
|
44
|
+
FEATURE_RULE_LIMITS: () => FEATURE_RULE_LIMITS,
|
|
31
45
|
FILE_LINK_CLASS: () => FILE_LINK_CLASS,
|
|
32
46
|
GUIDELY_ID_ATTRIBUTE: () => GUIDELY_ID_ATTRIBUTE,
|
|
47
|
+
GUIDE_EXPERIMENT_GOALS: () => GUIDE_EXPERIMENT_GOALS,
|
|
48
|
+
GUIDE_EXPERIMENT_GOAL_LABELS: () => GUIDE_EXPERIMENT_GOAL_LABELS,
|
|
49
|
+
GUIDE_EXPERIMENT_STATUSES: () => GUIDE_EXPERIMENT_STATUSES,
|
|
33
50
|
GUIDE_VISIBILITIES: () => GUIDE_VISIBILITIES,
|
|
34
51
|
LOGGED_IN_AUDIENCE: () => LOGGED_IN_AUDIENCE,
|
|
35
52
|
MAX_COLLECTION_DEPTH: () => MAX_COLLECTION_DEPTH,
|
|
@@ -38,6 +55,7 @@ __export(runtime_exports, {
|
|
|
38
55
|
MAX_COMPLAINT_CHOICES: () => MAX_COMPLAINT_CHOICES,
|
|
39
56
|
MAX_COMPLAINT_FIELDS: () => MAX_COMPLAINT_FIELDS,
|
|
40
57
|
MAX_COMPLAINT_LENGTH: () => MAX_COMPLAINT_LENGTH,
|
|
58
|
+
MAX_CUSTOM_CSS: () => MAX_CUSTOM_CSS,
|
|
41
59
|
MAX_PROPERTY_BYTES: () => MAX_PROPERTY_BYTES,
|
|
42
60
|
MAX_STACK_FRAMES: () => MAX_STACK_FRAMES,
|
|
43
61
|
MEDIA_FILE_MAX_BYTES: () => MEDIA_FILE_MAX_BYTES,
|
|
@@ -48,38 +66,65 @@ __export(runtime_exports, {
|
|
|
48
66
|
MEDIA_VIDEO_MAX_BYTES: () => MEDIA_VIDEO_MAX_BYTES,
|
|
49
67
|
MEDIA_VIDEO_TYPES: () => MEDIA_VIDEO_TYPES,
|
|
50
68
|
NETWORK_PLUGIN: () => NETWORK_PLUGIN,
|
|
69
|
+
NOISY_DATA_ATTR: () => NOISY_DATA_ATTR,
|
|
70
|
+
PAGE_RULE_LIMITS: () => PAGE_RULE_LIMITS,
|
|
51
71
|
PATH_ID_PATTERN: () => PATH_ID_PATTERN,
|
|
52
72
|
PDF_BLOCK_CLASS: () => PDF_BLOCK_CLASS,
|
|
53
73
|
PDF_MAX_PAGES: () => PDF_MAX_PAGES,
|
|
54
74
|
PDF_PAGES_CLASS: () => PDF_PAGES_CLASS,
|
|
55
75
|
PLATFORMS: () => PLATFORMS,
|
|
76
|
+
RC_MODULE_IDS: () => RC_MODULE_IDS,
|
|
77
|
+
RC_MODULE_LABELS: () => RC_MODULE_LABELS,
|
|
56
78
|
RULE_FIELDS: () => RULE_FIELDS,
|
|
57
79
|
RULE_OPERATORS: () => RULE_OPERATORS,
|
|
80
|
+
SCOUT_AGENT_ID: () => SCOUT_AGENT_ID,
|
|
58
81
|
SENSITIVE_HEADER_PATTERN: () => SENSITIVE_HEADER_PATTERN,
|
|
59
82
|
SENSITIVE_PARAM_PATTERN: () => SENSITIVE_PARAM_PATTERN,
|
|
60
83
|
SENSITIVE_PROPERTY_PATTERN: () => SENSITIVE_PROPERTY_PATTERN,
|
|
61
84
|
SERVER_ASSISTED_FIELDS: () => SERVER_ASSISTED_FIELDS,
|
|
62
85
|
SHOW_ME_CLASS: () => SHOW_ME_CLASS,
|
|
63
86
|
SHOW_ME_HREF_PREFIX: () => SHOW_ME_HREF_PREFIX,
|
|
87
|
+
SNAPSHOT_ATTRS: () => SNAPSHOT_ATTRS,
|
|
88
|
+
SNAPSHOT_LIMITS: () => SNAPSHOT_LIMITS,
|
|
64
89
|
SOURCEMAP_MAX_FILES_PER_UPLOAD: () => SOURCEMAP_MAX_FILES_PER_UPLOAD,
|
|
65
90
|
SOURCEMAP_MAX_FILE_BYTES: () => SOURCEMAP_MAX_FILE_BYTES,
|
|
91
|
+
SelectorSyntaxError: () => SelectorSyntaxError,
|
|
92
|
+
TAG_PROPERTY_LIMITS: () => TAG_PROPERTY_LIMITS,
|
|
66
93
|
VIDEO_ATTRS: () => VIDEO_ATTRS,
|
|
94
|
+
WCAG_AA_LARGE: () => WCAG_AA_LARGE,
|
|
95
|
+
WCAG_AA_TEXT: () => WCAG_AA_TEXT,
|
|
67
96
|
WS_MAX_MESSAGES_PER_SOCKET: () => WS_MAX_MESSAGES_PER_SOCKET,
|
|
68
97
|
WS_MAX_MESSAGE_BYTES: () => WS_MAX_MESSAGE_BYTES,
|
|
98
|
+
applyGuideTranslations: () => applyGuideTranslations,
|
|
99
|
+
articleTextEntries: () => articleTextEntries,
|
|
100
|
+
assignGuideVariant: () => assignGuideVariant,
|
|
101
|
+
baseLanguage: () => baseLanguage,
|
|
69
102
|
clamp: () => clamp,
|
|
70
103
|
compare: () => compare,
|
|
71
104
|
compareVersions: () => compareVersions,
|
|
72
105
|
complaintReference: () => complaintReference,
|
|
106
|
+
compoundMatches: () => compoundMatches,
|
|
107
|
+
contrastIssues: () => contrastIssues,
|
|
108
|
+
contrastRatio: () => contrastRatio,
|
|
109
|
+
cssSelectorError: () => cssSelectorError,
|
|
73
110
|
describeRule: () => describeRule,
|
|
74
111
|
emptyRuleGroup: () => emptyRuleGroup,
|
|
75
112
|
evaluateRule: () => evaluateRule,
|
|
76
113
|
evaluateRules: () => evaluateRules,
|
|
114
|
+
evenWeights: () => evenWeights,
|
|
115
|
+
experimentBucketRules: () => experimentBucketRules,
|
|
116
|
+
experimentSalt: () => experimentSalt,
|
|
117
|
+
featureCssSelectors: () => featureCssSelectors,
|
|
118
|
+
featureRuleError: () => featureRuleError,
|
|
119
|
+
featureRuleMatchesClick: () => featureRuleMatchesClick,
|
|
77
120
|
fingerprintError: () => fingerprintError,
|
|
78
121
|
firstNameFromTraits: () => firstNameFromTraits,
|
|
79
122
|
fnv1a: () => fnv1a,
|
|
80
123
|
foldPathIds: () => foldPathIds,
|
|
81
124
|
getPath: () => getPath,
|
|
125
|
+
guideLocales: () => guideLocales,
|
|
82
126
|
guidePlatforms: () => guidePlatforms,
|
|
127
|
+
guideTextEntries: () => guideTextEntries,
|
|
83
128
|
guidelyIdFromSelector: () => guidelyIdFromSelector,
|
|
84
129
|
hasVideoMedia: () => hasVideoMedia,
|
|
85
130
|
isAllowedEmbedSrc: () => isAllowedEmbedSrc,
|
|
@@ -92,32 +137,66 @@ __export(runtime_exports, {
|
|
|
92
137
|
isRuleGroup: () => isRuleGroup,
|
|
93
138
|
isSafeMediaUrl: () => isSafeMediaUrl,
|
|
94
139
|
isVideoContentType: () => isVideoContentType,
|
|
140
|
+
localeName: () => localeName,
|
|
141
|
+
localizeAnnouncement: () => localizeAnnouncement,
|
|
142
|
+
localizeArticle: () => localizeArticle,
|
|
143
|
+
localizeGuide: () => localizeGuide,
|
|
144
|
+
localizeResourceCenter: () => localizeResourceCenter,
|
|
145
|
+
matchCssSelector: () => matchCssSelector,
|
|
95
146
|
matchUrlPattern: () => matchUrlPattern,
|
|
96
147
|
matchesAudiences: () => matchesAudiences,
|
|
97
148
|
matchesHelpQuery: () => matchesHelpQuery,
|
|
98
149
|
mediaKind: () => mediaKind,
|
|
99
150
|
mediaMaxBytes: () => mediaMaxBytes,
|
|
151
|
+
needsReview: () => needsReview,
|
|
100
152
|
normalizeErrorMessage: () => normalizeErrorMessage,
|
|
101
153
|
normalizeFrameFile: () => normalizeFrameFile,
|
|
154
|
+
normalizeLocale: () => normalizeLocale,
|
|
155
|
+
normalizeSnapshot: () => normalizeSnapshot,
|
|
156
|
+
orderedModules: () => orderedModules,
|
|
102
157
|
pageLabel: () => pageLabel,
|
|
158
|
+
pagePattern: () => pagePattern,
|
|
159
|
+
pageRuleError: () => pageRuleError,
|
|
160
|
+
pageRuleMatches: () => pageRuleMatches,
|
|
161
|
+
pageRulesMatch: () => pageRulesMatch,
|
|
103
162
|
pageTerms: () => pageTerms,
|
|
163
|
+
parseCssSelector: () => parseCssSelector,
|
|
164
|
+
parseHexColor: () => parseHexColor,
|
|
104
165
|
parseStack: () => parseStack,
|
|
166
|
+
propertyAttributeAllowed: () => propertyAttributeAllowed,
|
|
167
|
+
queryConditionRegex: () => queryConditionRegex,
|
|
105
168
|
randomId: () => randomId,
|
|
169
|
+
readableTextOn: () => readableTextOn,
|
|
170
|
+
relativeLuminance: () => relativeLuminance,
|
|
171
|
+
resolveLocale: () => resolveLocale,
|
|
172
|
+
resourceCenterLocales: () => resourceCenterLocales,
|
|
106
173
|
resourceCenterSections: () => resourceCenterSections,
|
|
174
|
+
resourceCenterTextEntries: () => resourceCenterTextEntries,
|
|
107
175
|
rolloutBucket: () => rolloutBucket,
|
|
108
176
|
safeRegExp: () => safeRegExp,
|
|
177
|
+
sanitizeCustomCss: () => sanitizeCustomCss,
|
|
109
178
|
sanitizeProperties: () => sanitizeProperties,
|
|
179
|
+
scopeCustomCss: () => scopeCustomCss,
|
|
110
180
|
screenPath: () => screenPath,
|
|
111
181
|
servedArticleAudiences: () => servedArticleAudiences,
|
|
112
182
|
showMeHref: () => showMeHref,
|
|
113
183
|
showMeKeyFromHref: () => showMeKeyFromHref,
|
|
114
184
|
showMeKeys: () => showMeKeys,
|
|
115
185
|
slugify: () => slugify,
|
|
186
|
+
snapshotFromSelector: () => snapshotFromSelector,
|
|
187
|
+
stableStringify: () => stableStringify,
|
|
116
188
|
stripOrigin: () => stripOrigin,
|
|
117
189
|
supportsPlatform: () => supportsPlatform,
|
|
118
190
|
toEmbedUrl: () => toEmbedUrl,
|
|
191
|
+
translationCoverage: () => translationCoverage,
|
|
192
|
+
unreadAnnouncements: () => unreadAnnouncements,
|
|
193
|
+
variantProblems: () => variantProblems,
|
|
194
|
+
variantRanges: () => variantRanges,
|
|
195
|
+
visibleAnnouncements: () => visibleAnnouncements,
|
|
119
196
|
visibleArticleIds: () => visibleArticleIds,
|
|
120
197
|
visitorAudiences: () => visitorAudiences,
|
|
198
|
+
visitorLocales: () => visitorLocales,
|
|
199
|
+
withExperimentBucket: () => withExperimentBucket,
|
|
121
200
|
withVisibility: () => withVisibility
|
|
122
201
|
});
|
|
123
202
|
module.exports = __toCommonJS(runtime_exports);
|
|
@@ -309,11 +388,15 @@ var RULE_FIELDS = [
|
|
|
309
388
|
"datetime.dayOfWeek",
|
|
310
389
|
"datetime.hour",
|
|
311
390
|
"rollout.percentage",
|
|
391
|
+
/** Guide A/B tests: the visitor's 0-99 bucket for the salt in `key` (see guide-experiments.ts). */
|
|
392
|
+
"experiment.bucket",
|
|
312
393
|
"environment",
|
|
313
394
|
"locale",
|
|
314
395
|
"app.platform",
|
|
315
396
|
"app.screen",
|
|
316
|
-
"app.version"
|
|
397
|
+
"app.version",
|
|
398
|
+
"page.views",
|
|
399
|
+
"feature.clicks"
|
|
317
400
|
];
|
|
318
401
|
function isRuleGroup(r) {
|
|
319
402
|
return r.rules !== void 0;
|
|
@@ -373,6 +456,8 @@ function resolveField(rule, ctx) {
|
|
|
373
456
|
return ctx.now.getHours();
|
|
374
457
|
case "rollout.percentage":
|
|
375
458
|
return rolloutBucket(ctx.userId || ctx.anonymousId, ctx.rolloutSalt || "guidely");
|
|
459
|
+
case "experiment.bucket":
|
|
460
|
+
return rule.key ? rolloutBucket(ctx.userId || ctx.anonymousId, rule.key) : void 0;
|
|
376
461
|
case "environment":
|
|
377
462
|
return ctx.environment;
|
|
378
463
|
case "locale":
|
|
@@ -383,6 +468,9 @@ function resolveField(rule, ctx) {
|
|
|
383
468
|
return ctx.screen;
|
|
384
469
|
case "app.version":
|
|
385
470
|
return ctx.appVersion;
|
|
471
|
+
case "page.views":
|
|
472
|
+
case "feature.clicks":
|
|
473
|
+
return rule.key ? ctx.tagUsage?.[rule.key] ?? 0 : 0;
|
|
386
474
|
default:
|
|
387
475
|
return void 0;
|
|
388
476
|
}
|
|
@@ -482,7 +570,7 @@ function evaluateRules(group, ctx) {
|
|
|
482
570
|
const value = group.op === "and" ? results.every(Boolean) : results.some(Boolean);
|
|
483
571
|
return group.negate ? !value : value;
|
|
484
572
|
}
|
|
485
|
-
var SERVER_ASSISTED_FIELDS = ["audience.member", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed"];
|
|
573
|
+
var SERVER_ASSISTED_FIELDS = ["audience.member", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed", "page.views", "feature.clicks"];
|
|
486
574
|
var GUIDE_VISIBILITIES = ["everyone", "identified", "anonymous"];
|
|
487
575
|
function withVisibility(targeting, visibility) {
|
|
488
576
|
if (!visibility || visibility === "everyone") return targeting;
|
|
@@ -504,8 +592,8 @@ function sanitizeProperties(props) {
|
|
|
504
592
|
for (const [k, v] of Object.entries(props)) {
|
|
505
593
|
if (SENSITIVE_PROPERTY_PATTERN.test(k)) continue;
|
|
506
594
|
if (typeof v === "function" || typeof v === "symbol") continue;
|
|
507
|
-
const
|
|
508
|
-
size += k.length + (
|
|
595
|
+
const str2 = typeof v === "string" ? v : JSON.stringify(v ?? null);
|
|
596
|
+
size += k.length + (str2?.length ?? 0);
|
|
509
597
|
if (size > MAX_PROPERTY_BYTES) break;
|
|
510
598
|
out[k.slice(0, 100)] = typeof v === "string" ? v.slice(0, 1e3) : v;
|
|
511
599
|
}
|
|
@@ -542,7 +630,7 @@ function normalizeFrameFile(file) {
|
|
|
542
630
|
}
|
|
543
631
|
return path.replace(/[.-][0-9a-f]{6,}(?=\.\w+$)/i, "").replace(/\/\d+\//g, "/<n>/");
|
|
544
632
|
}
|
|
545
|
-
var SOURCEMAP_MAX_FILE_BYTES =
|
|
633
|
+
var SOURCEMAP_MAX_FILE_BYTES = 100 * 1024 * 1024;
|
|
546
634
|
var SOURCEMAP_MAX_FILES_PER_UPLOAD = 200;
|
|
547
635
|
function fingerprintError(input) {
|
|
548
636
|
const top = (input.frames ?? []).find((f) => f.file);
|
|
@@ -783,6 +871,32 @@ function matchesHelpQuery(text, query) {
|
|
|
783
871
|
const have = words(hay);
|
|
784
872
|
return terms.every((t) => have.some((w) => w.startsWith(t) || t.length > 3 && t.endsWith("s") && w.startsWith(t.slice(0, -1))));
|
|
785
873
|
}
|
|
874
|
+
var RC_MODULE_IDS = ["announcements", "search", "checklists", "guides", "articles", "links", "faqs"];
|
|
875
|
+
var RC_MODULE_LABELS = {
|
|
876
|
+
announcements: "What's new",
|
|
877
|
+
search: "Search",
|
|
878
|
+
checklists: "Checklists",
|
|
879
|
+
guides: "Guides & tours",
|
|
880
|
+
articles: "Articles",
|
|
881
|
+
links: "Links",
|
|
882
|
+
faqs: "FAQs"
|
|
883
|
+
};
|
|
884
|
+
function orderedModules(modules) {
|
|
885
|
+
const known = (modules ?? []).filter((m, i, all) => RC_MODULE_IDS.includes(m.id) && all.findIndex((x) => x.id === m.id) === i);
|
|
886
|
+
const missing = RC_MODULE_IDS.filter((id) => !known.some((m) => m.id === id)).map((id) => ({ id, enabled: true }));
|
|
887
|
+
return [...known, ...missing];
|
|
888
|
+
}
|
|
889
|
+
function visibleAnnouncements(items, member, now = Date.now()) {
|
|
890
|
+
return (items ?? []).filter((a) => {
|
|
891
|
+
const t = Date.parse(a.publishedAt);
|
|
892
|
+
return !Number.isNaN(t) && t <= now && matchesAudiences(a.audienceIds, member);
|
|
893
|
+
}).sort((a, b) => Date.parse(b.publishedAt) - Date.parse(a.publishedAt));
|
|
894
|
+
}
|
|
895
|
+
function unreadAnnouncements(items, lastSeenAt) {
|
|
896
|
+
const seen = lastSeenAt ? Date.parse(lastSeenAt) : NaN;
|
|
897
|
+
if (Number.isNaN(seen)) return items.length;
|
|
898
|
+
return items.filter((a) => Date.parse(a.publishedAt) > seen).length;
|
|
899
|
+
}
|
|
786
900
|
|
|
787
901
|
// src/howto-limits.ts
|
|
788
902
|
var CAPTURE_PARAM = "guidely_capture";
|
|
@@ -812,12 +926,556 @@ function pageLabel(path) {
|
|
|
812
926
|
}
|
|
813
927
|
function firstNameFromTraits(traits) {
|
|
814
928
|
if (!traits) return null;
|
|
815
|
-
const
|
|
816
|
-
const first =
|
|
929
|
+
const pick2 = (v) => typeof v === "string" ? v.trim() : "";
|
|
930
|
+
const first = pick2(traits.firstName) || pick2(traits.first_name) || pick2(traits.firstname) || pick2(traits.name).split(/\s+/)[0] || "";
|
|
817
931
|
if (!first || first.length > 40 || first.includes("@") || !/\p{L}/u.test(first)) return null;
|
|
818
932
|
return first;
|
|
819
933
|
}
|
|
820
934
|
|
|
935
|
+
// src/tagging.ts
|
|
936
|
+
var SNAPSHOT_LIMITS = { classes: 8, className: 60, attrs: 6, attrValue: 100, ancestors: 5, hosts: 3, tag: 40, id: 80 };
|
|
937
|
+
var SNAPSHOT_ATTRS = ["role", "name", "type", "aria-label", "title", "alt", "for", "href"];
|
|
938
|
+
var NOISY_DATA_ATTR = /^data-(state|v-|react|radix|headlessui|svelte|orientation|highlighted|focus|key|index|side|align|disabled|selected|active|open|rbd|dnd|sveltekit|guidely-(mask|ignore|block))/i;
|
|
939
|
+
var DEFAULT_FEATURE_ATTRIBUTE = "data-guidely-feature";
|
|
940
|
+
var FEATURE_ATTRIBUTE_PATTERN = /^data-[a-z0-9][a-z0-9_.-]{0,60}$/;
|
|
941
|
+
function str(v, max) {
|
|
942
|
+
return typeof v === "string" && v ? v.slice(0, max) : void 0;
|
|
943
|
+
}
|
|
944
|
+
function cleanNode(raw) {
|
|
945
|
+
if (!raw || typeof raw !== "object") return null;
|
|
946
|
+
const r = raw;
|
|
947
|
+
const t = str(r.t, SNAPSHOT_LIMITS.tag)?.toLowerCase();
|
|
948
|
+
if (!t || !/^[a-z][a-z0-9-]*$/.test(t)) return null;
|
|
949
|
+
const node = { t };
|
|
950
|
+
const id = str(r.id, SNAPSHOT_LIMITS.id);
|
|
951
|
+
if (id) node.id = id;
|
|
952
|
+
if (Array.isArray(r.c)) {
|
|
953
|
+
const c = r.c.filter((x) => typeof x === "string" && !!x && x.length <= SNAPSHOT_LIMITS.className && !/\s/.test(x)).slice(0, SNAPSHOT_LIMITS.classes);
|
|
954
|
+
if (c.length) node.c = c;
|
|
955
|
+
}
|
|
956
|
+
if (r.a && typeof r.a === "object" && !Array.isArray(r.a)) {
|
|
957
|
+
const a = {};
|
|
958
|
+
for (const [k, v] of Object.entries(r.a)) {
|
|
959
|
+
if (Object.keys(a).length >= SNAPSHOT_LIMITS.attrs) break;
|
|
960
|
+
const key = k.toLowerCase();
|
|
961
|
+
if (typeof v !== "string" || !(key.startsWith("data-") || SNAPSHOT_ATTRS.includes(key)) || key === "value" || key.length > 60) continue;
|
|
962
|
+
a[key] = v.slice(0, SNAPSHOT_LIMITS.attrValue);
|
|
963
|
+
}
|
|
964
|
+
if (Object.keys(a).length) node.a = a;
|
|
965
|
+
}
|
|
966
|
+
if (typeof r.n === "number" && Number.isInteger(r.n) && r.n >= 1 && r.n <= 1e4) node.n = r.n;
|
|
967
|
+
return node;
|
|
968
|
+
}
|
|
969
|
+
function normalizeSnapshot(raw) {
|
|
970
|
+
const el = cleanNode(raw);
|
|
971
|
+
if (!el) return null;
|
|
972
|
+
const r = raw;
|
|
973
|
+
const out = el;
|
|
974
|
+
if (Array.isArray(r.p)) {
|
|
975
|
+
const p = r.p.slice(0, SNAPSHOT_LIMITS.ancestors).map(cleanNode);
|
|
976
|
+
const cut = p.indexOf(null);
|
|
977
|
+
const list = cut === -1 ? p : p.slice(0, cut);
|
|
978
|
+
if (list.length) out.p = list;
|
|
979
|
+
}
|
|
980
|
+
if (Array.isArray(r.h)) {
|
|
981
|
+
const h = r.h.slice(0, SNAPSHOT_LIMITS.hosts).map(cleanNode).filter((x) => !!x);
|
|
982
|
+
if (h.length) out.h = h;
|
|
983
|
+
}
|
|
984
|
+
return out;
|
|
985
|
+
}
|
|
986
|
+
function stableStringify(v) {
|
|
987
|
+
if (Array.isArray(v)) return `[${v.map(stableStringify).join(",")}]`;
|
|
988
|
+
if (v && typeof v === "object") {
|
|
989
|
+
const o = v;
|
|
990
|
+
return `{${Object.keys(o).filter((k) => o[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(o[k])}`).join(",")}}`;
|
|
991
|
+
}
|
|
992
|
+
return JSON.stringify(v ?? null);
|
|
993
|
+
}
|
|
994
|
+
var SelectorSyntaxError = class extends Error {
|
|
995
|
+
};
|
|
996
|
+
var IDENT_START = /[A-Za-z_\u00a0-\uffff-]/;
|
|
997
|
+
var IDENT_CHAR = /[A-Za-z0-9_\u00a0-\uffff-]/;
|
|
998
|
+
function parseCssSelector(input) {
|
|
999
|
+
const s = input.trim();
|
|
1000
|
+
if (!s) throw new SelectorSyntaxError("Empty selector");
|
|
1001
|
+
if (s.length > 1e3) throw new SelectorSyntaxError("Selector is too long");
|
|
1002
|
+
let i = 0;
|
|
1003
|
+
const peek = () => s[i];
|
|
1004
|
+
const eof = () => i >= s.length;
|
|
1005
|
+
const fail = (msg) => {
|
|
1006
|
+
throw new SelectorSyntaxError(`${msg} at position ${i + 1}`);
|
|
1007
|
+
};
|
|
1008
|
+
const ws = () => {
|
|
1009
|
+
let any = false;
|
|
1010
|
+
while (!eof() && /\s/.test(s[i])) {
|
|
1011
|
+
i++;
|
|
1012
|
+
any = true;
|
|
1013
|
+
}
|
|
1014
|
+
return any;
|
|
1015
|
+
};
|
|
1016
|
+
const escape = () => {
|
|
1017
|
+
i++;
|
|
1018
|
+
const hex = /^[0-9a-fA-F]{1,6}/.exec(s.slice(i));
|
|
1019
|
+
if (hex) {
|
|
1020
|
+
i += hex[0].length;
|
|
1021
|
+
if (s[i] === " ") i++;
|
|
1022
|
+
return String.fromCodePoint(parseInt(hex[0], 16));
|
|
1023
|
+
}
|
|
1024
|
+
if (eof()) fail("Unfinished escape");
|
|
1025
|
+
return s[i++];
|
|
1026
|
+
};
|
|
1027
|
+
const ident = () => {
|
|
1028
|
+
let out = "";
|
|
1029
|
+
if (s[i] === "\\") out += escape();
|
|
1030
|
+
else if (!eof() && IDENT_START.test(s[i])) out += s[i++];
|
|
1031
|
+
else fail("Expected a name");
|
|
1032
|
+
while (!eof()) {
|
|
1033
|
+
if (s[i] === "\\") out += escape();
|
|
1034
|
+
else if (IDENT_CHAR.test(s[i])) out += s[i++];
|
|
1035
|
+
else break;
|
|
1036
|
+
}
|
|
1037
|
+
return out;
|
|
1038
|
+
};
|
|
1039
|
+
const quoted = () => {
|
|
1040
|
+
const q = s[i++];
|
|
1041
|
+
let out = "";
|
|
1042
|
+
while (!eof() && s[i] !== q) {
|
|
1043
|
+
if (s[i] === "\\") out += escape();
|
|
1044
|
+
else out += s[i++];
|
|
1045
|
+
}
|
|
1046
|
+
if (eof()) fail("Unterminated string");
|
|
1047
|
+
i++;
|
|
1048
|
+
return out;
|
|
1049
|
+
};
|
|
1050
|
+
const compound = () => {
|
|
1051
|
+
const c = { classes: [], attrs: [] };
|
|
1052
|
+
let any = false;
|
|
1053
|
+
if (peek() === "*") {
|
|
1054
|
+
i++;
|
|
1055
|
+
any = true;
|
|
1056
|
+
} else if (!eof() && (IDENT_START.test(peek()) || peek() === "\\")) {
|
|
1057
|
+
c.tag = ident().toLowerCase();
|
|
1058
|
+
any = true;
|
|
1059
|
+
}
|
|
1060
|
+
for (; ; ) {
|
|
1061
|
+
const ch = peek();
|
|
1062
|
+
if (ch === "#") {
|
|
1063
|
+
i++;
|
|
1064
|
+
c.id = ident();
|
|
1065
|
+
} else if (ch === ".") {
|
|
1066
|
+
i++;
|
|
1067
|
+
c.classes.push(ident());
|
|
1068
|
+
} else if (ch === "[") {
|
|
1069
|
+
i++;
|
|
1070
|
+
ws();
|
|
1071
|
+
const name = ident().toLowerCase();
|
|
1072
|
+
ws();
|
|
1073
|
+
let op = "exists";
|
|
1074
|
+
let value;
|
|
1075
|
+
let insensitive = false;
|
|
1076
|
+
if (peek() !== "]") {
|
|
1077
|
+
const m = /^(=|\^=|\$=|\*=|~=|\|=)/.exec(s.slice(i));
|
|
1078
|
+
if (!m) fail("Unsupported attribute operator");
|
|
1079
|
+
op = m[1];
|
|
1080
|
+
i += m[1].length;
|
|
1081
|
+
ws();
|
|
1082
|
+
value = peek() === '"' || peek() === "'" ? quoted() : ident();
|
|
1083
|
+
ws();
|
|
1084
|
+
if (peek() === "i" || peek() === "I") {
|
|
1085
|
+
i++;
|
|
1086
|
+
insensitive = true;
|
|
1087
|
+
ws();
|
|
1088
|
+
} else if (peek() === "s" || peek() === "S") {
|
|
1089
|
+
i++;
|
|
1090
|
+
ws();
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (peek() !== "]") fail("Expected ]");
|
|
1094
|
+
i++;
|
|
1095
|
+
c.attrs.push({ name, op, ...value !== void 0 ? { value } : {}, ...insensitive ? { insensitive } : {} });
|
|
1096
|
+
} else if (ch === ":") {
|
|
1097
|
+
i++;
|
|
1098
|
+
if (peek() === ":") fail("Pseudo-elements are not supported");
|
|
1099
|
+
const name = ident().toLowerCase();
|
|
1100
|
+
if (name === "first-of-type") c.nth = { a: 0, b: 1 };
|
|
1101
|
+
else if (name === "nth-of-type") {
|
|
1102
|
+
if (peek() !== "(") fail("Expected (");
|
|
1103
|
+
i++;
|
|
1104
|
+
ws();
|
|
1105
|
+
const m = /^(odd|even|\d+)/i.exec(s.slice(i));
|
|
1106
|
+
if (!m) fail("Only :nth-of-type(n), odd or even are supported");
|
|
1107
|
+
i += m[0].length;
|
|
1108
|
+
ws();
|
|
1109
|
+
if (peek() !== ")") fail("Expected )");
|
|
1110
|
+
i++;
|
|
1111
|
+
const v = m[0].toLowerCase();
|
|
1112
|
+
c.nth = v === "odd" ? { a: 2, b: 1 } : v === "even" ? { a: 2, b: 0 } : { a: 0, b: Number(v) };
|
|
1113
|
+
} else fail(`Unsupported pseudo-class :${name}`);
|
|
1114
|
+
} else break;
|
|
1115
|
+
any = true;
|
|
1116
|
+
}
|
|
1117
|
+
return any ? c : null;
|
|
1118
|
+
};
|
|
1119
|
+
const list = [];
|
|
1120
|
+
for (; ; ) {
|
|
1121
|
+
ws();
|
|
1122
|
+
const sel = { compounds: [], combinators: [] };
|
|
1123
|
+
const first = compound();
|
|
1124
|
+
if (!first) fail("Expected a selector");
|
|
1125
|
+
sel.compounds.push(first);
|
|
1126
|
+
for (; ; ) {
|
|
1127
|
+
const hadWs = ws();
|
|
1128
|
+
if (eof() || peek() === ",") break;
|
|
1129
|
+
let comb = " ";
|
|
1130
|
+
if (s.startsWith(">>>", i)) {
|
|
1131
|
+
comb = ">>>";
|
|
1132
|
+
i += 3;
|
|
1133
|
+
ws();
|
|
1134
|
+
} else if (peek() === ">") {
|
|
1135
|
+
comb = ">";
|
|
1136
|
+
i++;
|
|
1137
|
+
ws();
|
|
1138
|
+
} else if (peek() === "+" || peek() === "~") fail("Sibling combinators are not supported");
|
|
1139
|
+
else if (!hadWs) fail("Unexpected character");
|
|
1140
|
+
const next = compound();
|
|
1141
|
+
if (!next) fail("Expected a selector after the combinator");
|
|
1142
|
+
sel.compounds.push(next);
|
|
1143
|
+
sel.combinators.push(comb);
|
|
1144
|
+
}
|
|
1145
|
+
list.push(sel);
|
|
1146
|
+
if (eof()) break;
|
|
1147
|
+
i++;
|
|
1148
|
+
}
|
|
1149
|
+
return list;
|
|
1150
|
+
}
|
|
1151
|
+
function cssSelectorError(selector) {
|
|
1152
|
+
try {
|
|
1153
|
+
parseCssSelector(selector);
|
|
1154
|
+
return null;
|
|
1155
|
+
} catch (e) {
|
|
1156
|
+
return e instanceof Error ? e.message : "Invalid selector";
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
function attrMatches(test, node) {
|
|
1160
|
+
let actual;
|
|
1161
|
+
if (test.name === "id") actual = node.id;
|
|
1162
|
+
else if (test.name === "class") actual = node.c?.join(" ");
|
|
1163
|
+
else actual = node.a?.[test.name];
|
|
1164
|
+
if (actual === void 0) return false;
|
|
1165
|
+
if (test.op === "exists") return true;
|
|
1166
|
+
let v = test.value ?? "";
|
|
1167
|
+
if (test.insensitive) {
|
|
1168
|
+
actual = actual.toLowerCase();
|
|
1169
|
+
v = v.toLowerCase();
|
|
1170
|
+
}
|
|
1171
|
+
switch (test.op) {
|
|
1172
|
+
case "=":
|
|
1173
|
+
return actual === v;
|
|
1174
|
+
case "^=":
|
|
1175
|
+
return !!v && actual.startsWith(v);
|
|
1176
|
+
case "$=":
|
|
1177
|
+
return !!v && actual.endsWith(v);
|
|
1178
|
+
case "*=":
|
|
1179
|
+
return !!v && actual.includes(v);
|
|
1180
|
+
case "~=":
|
|
1181
|
+
return !!v && actual.split(/\s+/).includes(v);
|
|
1182
|
+
case "|=":
|
|
1183
|
+
return actual === v || actual.startsWith(`${v}-`);
|
|
1184
|
+
default:
|
|
1185
|
+
return false;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
function compoundMatches(c, node) {
|
|
1189
|
+
if (c.tag && c.tag !== node.t) return false;
|
|
1190
|
+
if (c.id !== void 0 && node.id !== c.id) return false;
|
|
1191
|
+
for (const cls of c.classes) if (!node.c?.includes(cls)) return false;
|
|
1192
|
+
for (const a of c.attrs) if (!attrMatches(a, node)) return false;
|
|
1193
|
+
if (c.nth) {
|
|
1194
|
+
if (!node.n) return false;
|
|
1195
|
+
const { a, b } = c.nth;
|
|
1196
|
+
if (a === 0 ? node.n !== b : (node.n - b) % a !== 0 || (node.n - b) / a < 0) return false;
|
|
1197
|
+
}
|
|
1198
|
+
return true;
|
|
1199
|
+
}
|
|
1200
|
+
function chainMatches(compounds, combinators, nodes, ci = compounds.length - 1, ni = 0) {
|
|
1201
|
+
if (!compoundMatches(compounds[ci], nodes[ni])) return false;
|
|
1202
|
+
if (ci === 0) return true;
|
|
1203
|
+
const comb = combinators[ci - 1];
|
|
1204
|
+
if (comb === ">") return ni + 1 < nodes.length && chainMatches(compounds, combinators, nodes, ci - 1, ni + 1);
|
|
1205
|
+
for (let k = ni + 1; k < nodes.length; k++) if (chainMatches(compounds, combinators, nodes, ci - 1, k)) return true;
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
function complexMatches(sel, snap) {
|
|
1209
|
+
const segments = [{ compounds: [sel.compounds[0]], combinators: [] }];
|
|
1210
|
+
sel.combinators.forEach((comb, k) => {
|
|
1211
|
+
const next = sel.compounds[k + 1];
|
|
1212
|
+
if (comb === ">>>") segments.push({ compounds: [next], combinators: [] });
|
|
1213
|
+
else {
|
|
1214
|
+
const seg = segments[segments.length - 1];
|
|
1215
|
+
seg.compounds.push(next);
|
|
1216
|
+
seg.combinators.push(comb);
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
const last = segments.pop();
|
|
1220
|
+
const nodes = [snap, ...snap.p ?? []];
|
|
1221
|
+
if (!chainMatches(last.compounds, last.combinators, nodes)) return false;
|
|
1222
|
+
const hosts = snap.h ?? [];
|
|
1223
|
+
let from = 0;
|
|
1224
|
+
for (let k = segments.length - 1; k >= 0; k--) {
|
|
1225
|
+
const target = segments[k].compounds[segments[k].compounds.length - 1];
|
|
1226
|
+
let found = -1;
|
|
1227
|
+
for (let j = from; j < hosts.length; j++) {
|
|
1228
|
+
if (compoundMatches(target, hosts[j])) {
|
|
1229
|
+
found = j;
|
|
1230
|
+
break;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (found === -1) return false;
|
|
1234
|
+
from = found + 1;
|
|
1235
|
+
}
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
var parsedCache = /* @__PURE__ */ new Map();
|
|
1239
|
+
function matchCssSelector(selector, snap) {
|
|
1240
|
+
let list;
|
|
1241
|
+
if (typeof selector === "string") {
|
|
1242
|
+
if (!parsedCache.has(selector)) {
|
|
1243
|
+
if (parsedCache.size > 500) parsedCache.clear();
|
|
1244
|
+
try {
|
|
1245
|
+
parsedCache.set(selector, parseCssSelector(selector));
|
|
1246
|
+
} catch {
|
|
1247
|
+
parsedCache.set(selector, null);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
list = parsedCache.get(selector);
|
|
1251
|
+
} else list = selector;
|
|
1252
|
+
return !!list && list.some((sel) => complexMatches(sel, snap));
|
|
1253
|
+
}
|
|
1254
|
+
function nodeOfCompound(c) {
|
|
1255
|
+
const node = { t: c.tag ?? "*" };
|
|
1256
|
+
if (c.id) node.id = c.id;
|
|
1257
|
+
if (c.classes.length) node.c = c.classes.slice(0, SNAPSHOT_LIMITS.classes);
|
|
1258
|
+
const a = {};
|
|
1259
|
+
for (const t of c.attrs) if (t.op === "=" && t.value !== void 0) a[t.name] = t.value;
|
|
1260
|
+
if (Object.keys(a).length) node.a = a;
|
|
1261
|
+
if (c.nth && c.nth.a === 0) node.n = c.nth.b;
|
|
1262
|
+
return node;
|
|
1263
|
+
}
|
|
1264
|
+
function snapshotFromSelector(selector, tag) {
|
|
1265
|
+
let list;
|
|
1266
|
+
try {
|
|
1267
|
+
list = parseCssSelector(selector);
|
|
1268
|
+
} catch {
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
if (list.length !== 1) return null;
|
|
1272
|
+
const sel = list[0];
|
|
1273
|
+
const segments = [[sel.compounds[0]]];
|
|
1274
|
+
sel.combinators.forEach((comb, k) => {
|
|
1275
|
+
if (comb === ">>>") segments.push([sel.compounds[k + 1]]);
|
|
1276
|
+
else segments[segments.length - 1].push(sel.compounds[k + 1]);
|
|
1277
|
+
});
|
|
1278
|
+
const own = segments.pop();
|
|
1279
|
+
const el = nodeOfCompound(own[own.length - 1]);
|
|
1280
|
+
if (el.t === "*" && tag && /^[a-z][a-z0-9-]*$/i.test(tag)) el.t = tag.toLowerCase();
|
|
1281
|
+
const snap = el;
|
|
1282
|
+
const p = own.slice(0, -1).reverse().map(nodeOfCompound);
|
|
1283
|
+
if (p.length) snap.p = p.slice(0, SNAPSHOT_LIMITS.ancestors);
|
|
1284
|
+
const h = segments.reverse().map((seg) => nodeOfCompound(seg[seg.length - 1]));
|
|
1285
|
+
if (h.length) snap.h = h.slice(0, SNAPSHOT_LIMITS.hosts);
|
|
1286
|
+
return snap;
|
|
1287
|
+
}
|
|
1288
|
+
var PAGE_RULE_LIMITS = { rules: 20, value: 500, query: 5 };
|
|
1289
|
+
var escapeRe = (s) => s.replace(/[.+?^${}()|[\]\\*]/g, "\\$&");
|
|
1290
|
+
function globToRegex(pattern) {
|
|
1291
|
+
let out = "";
|
|
1292
|
+
for (let k = 0; k < pattern.length; k++) {
|
|
1293
|
+
const ch = pattern[k];
|
|
1294
|
+
if (ch === "*") {
|
|
1295
|
+
if (pattern[k + 1] === "*") {
|
|
1296
|
+
out += ".*";
|
|
1297
|
+
k++;
|
|
1298
|
+
} else out += "[^/]*";
|
|
1299
|
+
} else if (ch === ":" && (k === 0 || pattern[k - 1] === "/") && /[A-Za-z_]/.test(pattern[k + 1] ?? "")) {
|
|
1300
|
+
let j = k + 1;
|
|
1301
|
+
while (j < pattern.length && /[\w]/.test(pattern[j])) j++;
|
|
1302
|
+
out += "[^/]+";
|
|
1303
|
+
k = j - 1;
|
|
1304
|
+
} else out += escapeRe(ch);
|
|
1305
|
+
}
|
|
1306
|
+
return out;
|
|
1307
|
+
}
|
|
1308
|
+
function pagePattern(raw) {
|
|
1309
|
+
let p = raw.trim();
|
|
1310
|
+
const query = [];
|
|
1311
|
+
const hash = p.indexOf("#");
|
|
1312
|
+
if (hash !== -1) p = p.slice(0, hash);
|
|
1313
|
+
const q = p.indexOf("?");
|
|
1314
|
+
if (q !== -1) {
|
|
1315
|
+
for (const part of p.slice(q + 1).split("&")) {
|
|
1316
|
+
if (!part) continue;
|
|
1317
|
+
const eq = part.indexOf("=");
|
|
1318
|
+
const name = decodeSafe(eq === -1 ? part : part.slice(0, eq));
|
|
1319
|
+
const value = eq === -1 ? void 0 : decodeSafe(part.slice(eq + 1));
|
|
1320
|
+
if (!name) continue;
|
|
1321
|
+
query.push(value === void 0 || value === "*" ? { name, op: "exists" } : { name, op: "equals", value });
|
|
1322
|
+
}
|
|
1323
|
+
p = p.slice(0, q);
|
|
1324
|
+
}
|
|
1325
|
+
let target = "path";
|
|
1326
|
+
if (p.startsWith("//*")) p = p.slice(3);
|
|
1327
|
+
let prefix = "";
|
|
1328
|
+
const abs = /^(https?:)?\/\/([^/]+)(.*)$/i.exec(p);
|
|
1329
|
+
if (abs) {
|
|
1330
|
+
target = "url";
|
|
1331
|
+
prefix = `https?://${globToRegex(abs[2].toLowerCase())}`;
|
|
1332
|
+
p = abs[3] || "/";
|
|
1333
|
+
}
|
|
1334
|
+
if (!p.startsWith("/")) p = `/${p}`;
|
|
1335
|
+
const body = p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
1336
|
+
const src = body === "/" ? "/?" : `${globToRegex(body)}/?`;
|
|
1337
|
+
return { source: `^${prefix}${src}$`, target, query: query.slice(0, PAGE_RULE_LIMITS.query) };
|
|
1338
|
+
}
|
|
1339
|
+
function decodeSafe(s) {
|
|
1340
|
+
try {
|
|
1341
|
+
return decodeURIComponent(s.replace(/\+/g, " "));
|
|
1342
|
+
} catch {
|
|
1343
|
+
return s;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
function queryConditionRegex(c) {
|
|
1347
|
+
const name = escapeRe(c.name);
|
|
1348
|
+
switch (c.op) {
|
|
1349
|
+
case "equals":
|
|
1350
|
+
return `[?&]${name}=${escapeRe(encodeLoose(c.value ?? ""))}(&|#|$)`;
|
|
1351
|
+
case "contains":
|
|
1352
|
+
return `[?&]${name}=[^&#]*${escapeRe(encodeLoose(c.value ?? ""))}`;
|
|
1353
|
+
default:
|
|
1354
|
+
return `[?&]${name}(=|&|#|$)`;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
function encodeLoose(v) {
|
|
1358
|
+
return encodeURIComponent(v).replace(/%2F/gi, "/").replace(/%3A/gi, ":").replace(/%2C/gi, ",").replace(/%40/gi, "@");
|
|
1359
|
+
}
|
|
1360
|
+
function pathOnly(ctx) {
|
|
1361
|
+
if (ctx.path) return ctx.path.split("?")[0] || "/";
|
|
1362
|
+
if (!ctx.url) return null;
|
|
1363
|
+
try {
|
|
1364
|
+
return new URL(ctx.url, "http://x.invalid").pathname;
|
|
1365
|
+
} catch {
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
function regexOrNull(source) {
|
|
1370
|
+
try {
|
|
1371
|
+
return new RegExp(source, "i");
|
|
1372
|
+
} catch {
|
|
1373
|
+
return null;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
function pageRuleMatches(rule, ctx) {
|
|
1377
|
+
const path = pathOnly(ctx);
|
|
1378
|
+
if (rule.type === "title") {
|
|
1379
|
+
const t = (ctx.title ?? "").toLowerCase();
|
|
1380
|
+
const v = rule.value.toLowerCase();
|
|
1381
|
+
return !!t && (rule.op === "contains" ? t.includes(v) : t === v);
|
|
1382
|
+
}
|
|
1383
|
+
if (rule.type === "regex") {
|
|
1384
|
+
const re2 = regexOrNull(rule.value);
|
|
1385
|
+
return !!re2 && path !== null && re2.test(path);
|
|
1386
|
+
}
|
|
1387
|
+
const pat = pagePattern(rule.value);
|
|
1388
|
+
const re = regexOrNull(pat.source);
|
|
1389
|
+
if (!re) return false;
|
|
1390
|
+
let subject = path;
|
|
1391
|
+
if (pat.target === "url") {
|
|
1392
|
+
if (!ctx.url) return false;
|
|
1393
|
+
subject = ctx.url.split(/[?#]/)[0];
|
|
1394
|
+
}
|
|
1395
|
+
if (subject === null || !re.test(subject)) return false;
|
|
1396
|
+
const conds = [...pat.query, ...rule.query ?? []];
|
|
1397
|
+
for (const c of conds) {
|
|
1398
|
+
const hit = !!ctx.url && new RegExp(queryConditionRegex(c), "i").test(ctx.url);
|
|
1399
|
+
if (c.op === "absent" ? hit : !hit) return false;
|
|
1400
|
+
}
|
|
1401
|
+
return true;
|
|
1402
|
+
}
|
|
1403
|
+
function pageRulesMatch(rules, ctx) {
|
|
1404
|
+
const include = rules.filter((r) => !r.exclude);
|
|
1405
|
+
if (!include.length || !include.some((r) => pageRuleMatches(r, ctx))) return false;
|
|
1406
|
+
return !rules.some((r) => r.exclude && pageRuleMatches(r, ctx));
|
|
1407
|
+
}
|
|
1408
|
+
function pageRuleError(rule) {
|
|
1409
|
+
const v = rule.value?.trim();
|
|
1410
|
+
if (!v) return "A rule needs a value";
|
|
1411
|
+
if (v.length > PAGE_RULE_LIMITS.value) return "The rule is too long";
|
|
1412
|
+
if (rule.type === "regex") {
|
|
1413
|
+
if (!regexOrNull(v)) return `"${v}" is not a valid regular expression`;
|
|
1414
|
+
if (/\(\?[<=!]/.test(v) || /\\[1-9]/.test(v)) return "Look-arounds and back-references are not supported";
|
|
1415
|
+
}
|
|
1416
|
+
if (rule.type === "url" && !regexOrNull(pagePattern(v).source)) return `"${v}" is not a valid URL rule`;
|
|
1417
|
+
for (const q of rule.query ?? []) if (!/^[A-Za-z0-9_.\-[\]]{1,60}$/.test(q.name)) return `"${q.name}" is not a query parameter name`;
|
|
1418
|
+
return null;
|
|
1419
|
+
}
|
|
1420
|
+
var FEATURE_RULE_LIMITS = { rules: 20, value: 1e3 };
|
|
1421
|
+
function globMatch(pattern, value) {
|
|
1422
|
+
const re = new RegExp(`^${pattern.split("*").map(escapeRe).join(".*")}$`, "s");
|
|
1423
|
+
return re.test(value);
|
|
1424
|
+
}
|
|
1425
|
+
function featureRuleMatchesClick(rule, click, css) {
|
|
1426
|
+
if (!rule.selector && !rule.text && !rule.tag && !rule.href) return false;
|
|
1427
|
+
if (rule.selector) {
|
|
1428
|
+
const sel = click.selector ?? "";
|
|
1429
|
+
const v = rule.selector.value;
|
|
1430
|
+
const ok = rule.selector.op === "css" ? css(v) : rule.selector.op === "exact" ? sel === v : rule.selector.op === "prefix" ? sel.startsWith(v) : rule.selector.op === "contains" ? sel.includes(v) : globMatch(v, sel);
|
|
1431
|
+
if (!ok) return false;
|
|
1432
|
+
}
|
|
1433
|
+
if (rule.text) {
|
|
1434
|
+
const t = (click.text ?? "").toLowerCase();
|
|
1435
|
+
const v = rule.text.value.toLowerCase();
|
|
1436
|
+
if (rule.text.op === "contains" ? !t.includes(v) : t !== v) return false;
|
|
1437
|
+
}
|
|
1438
|
+
if (rule.tag && (click.tag ?? "").toLowerCase() !== rule.tag.toLowerCase()) return false;
|
|
1439
|
+
if (rule.href) {
|
|
1440
|
+
const h = click.href ?? "";
|
|
1441
|
+
const v = rule.href.value;
|
|
1442
|
+
if (rule.href.op === "equals" ? h !== v : rule.href.op === "prefix" ? !h.startsWith(v) : !h.includes(v)) return false;
|
|
1443
|
+
}
|
|
1444
|
+
if (rule.platform && (click.platform ?? "web") !== rule.platform) return false;
|
|
1445
|
+
return true;
|
|
1446
|
+
}
|
|
1447
|
+
function featureRuleError(rule) {
|
|
1448
|
+
if (!rule.selector && !rule.text && !rule.tag && !rule.href) return "A feature rule needs a selector, text, tag or link condition";
|
|
1449
|
+
if (rule.selector) {
|
|
1450
|
+
const v = rule.selector.value?.trim();
|
|
1451
|
+
if (!v) return "The selector is empty";
|
|
1452
|
+
if (v.length > FEATURE_RULE_LIMITS.value) return "The selector is too long";
|
|
1453
|
+
if (rule.selector.op === "css") {
|
|
1454
|
+
const err = cssSelectorError(v);
|
|
1455
|
+
if (err) return `Unsupported CSS selector: ${err}`;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
if (rule.text && !rule.text.value.trim()) return "The text condition is empty";
|
|
1459
|
+
if (rule.href && !rule.href.value.trim()) return "The link condition is empty";
|
|
1460
|
+
if (rule.tag && !/^[a-z][a-z0-9-]{0,40}$/i.test(rule.tag)) return "The tag is not an element name";
|
|
1461
|
+
if (rule.page?.pattern) return pageRuleError({ type: "url", value: rule.page.pattern });
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1464
|
+
function featureCssSelectors(rules) {
|
|
1465
|
+
const out = [];
|
|
1466
|
+
for (const r of rules) {
|
|
1467
|
+
if (r.exclude || !r.selector) continue;
|
|
1468
|
+
if ((r.selector.op === "css" || r.selector.op === "exact") && !cssSelectorError(r.selector.value)) out.push(r.selector.value);
|
|
1469
|
+
}
|
|
1470
|
+
return out;
|
|
1471
|
+
}
|
|
1472
|
+
var TAG_PROPERTY_LIMITS = { perTag: 10, total: 50, value: 100 };
|
|
1473
|
+
function propertyAttributeAllowed(name) {
|
|
1474
|
+
const n = name.toLowerCase();
|
|
1475
|
+
if (n === "value" || n.startsWith("on") || n === "style" || n === "srcdoc") return false;
|
|
1476
|
+
return /^[a-z][a-z0-9_:.-]{0,60}$/.test(n);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
821
1479
|
// src/complaints-limits.ts
|
|
822
1480
|
var COMPLAINT_STATUSES = ["open", "in_review", "resolved"];
|
|
823
1481
|
var COMPLAINT_EVENTS = ["complaint.filed", "complaint.status_changed", "complaint.replied", "complaint.resolved"];
|
|
@@ -828,18 +1486,509 @@ var MAX_COMPLAINT_LENGTH = 4e3;
|
|
|
828
1486
|
var MAX_COMPLAINT_ANSWER_LENGTH = 500;
|
|
829
1487
|
var MAX_COMPLAINT_ATTACHMENT_BYTES = 2 * 1024 * 1024;
|
|
830
1488
|
var complaintReference = (number) => `CMP-${number}`;
|
|
1489
|
+
|
|
1490
|
+
// src/agents-limits.ts
|
|
1491
|
+
var AGENT_TURN_ROLES = ["user", "assistant", "tool", "system"];
|
|
1492
|
+
var AGENT_OUTCOMES = ["success", "failure", "escalated", "abandoned"];
|
|
1493
|
+
var AGENT_TOOL_STATUSES = ["ok", "error"];
|
|
1494
|
+
var AGENT_TURN_MAX_TEXT = 2e4;
|
|
1495
|
+
var AGENT_TURNS_PER_BATCH = 100;
|
|
1496
|
+
var AGENT_TOOL_CALLS_PER_TURN = 50;
|
|
1497
|
+
var AGENT_METADATA_MAX_KEYS = 30;
|
|
1498
|
+
var AGENT_METADATA_MAX_BYTES = 4096;
|
|
1499
|
+
var SCOUT_AGENT_ID = "scout";
|
|
1500
|
+
|
|
1501
|
+
// src/localization.ts
|
|
1502
|
+
function needsReview(state) {
|
|
1503
|
+
return !!state && (state.origin === "machine" && !state.approved || state.outdated);
|
|
1504
|
+
}
|
|
1505
|
+
var DEFAULT_LOCALE = "en";
|
|
1506
|
+
var COMMON_LOCALES = [
|
|
1507
|
+
{ code: "en", name: "English" },
|
|
1508
|
+
{ code: "en-GB", name: "English (UK)" },
|
|
1509
|
+
{ code: "fr", name: "French" },
|
|
1510
|
+
{ code: "fr-CA", name: "French (Canada)" },
|
|
1511
|
+
{ code: "de", name: "German" },
|
|
1512
|
+
{ code: "es", name: "Spanish" },
|
|
1513
|
+
{ code: "es-MX", name: "Spanish (Mexico)" },
|
|
1514
|
+
{ code: "it", name: "Italian" },
|
|
1515
|
+
{ code: "pt", name: "Portuguese" },
|
|
1516
|
+
{ code: "pt-BR", name: "Portuguese (Brazil)" },
|
|
1517
|
+
{ code: "nl", name: "Dutch" },
|
|
1518
|
+
{ code: "sv", name: "Swedish" },
|
|
1519
|
+
{ code: "da", name: "Danish" },
|
|
1520
|
+
{ code: "nb", name: "Norwegian" },
|
|
1521
|
+
{ code: "fi", name: "Finnish" },
|
|
1522
|
+
{ code: "pl", name: "Polish" },
|
|
1523
|
+
{ code: "cs", name: "Czech" },
|
|
1524
|
+
{ code: "tr", name: "Turkish" },
|
|
1525
|
+
{ code: "ru", name: "Russian" },
|
|
1526
|
+
{ code: "uk", name: "Ukrainian" },
|
|
1527
|
+
{ code: "ar", name: "Arabic" },
|
|
1528
|
+
{ code: "he", name: "Hebrew" },
|
|
1529
|
+
{ code: "hi", name: "Hindi" },
|
|
1530
|
+
{ code: "ja", name: "Japanese" },
|
|
1531
|
+
{ code: "ko", name: "Korean" },
|
|
1532
|
+
{ code: "zh-Hans", name: "Chinese (Simplified)" },
|
|
1533
|
+
{ code: "zh-Hant", name: "Chinese (Traditional)" },
|
|
1534
|
+
{ code: "id", name: "Indonesian" },
|
|
1535
|
+
{ code: "th", name: "Thai" },
|
|
1536
|
+
{ code: "vi", name: "Vietnamese" }
|
|
1537
|
+
];
|
|
1538
|
+
function localeName(code) {
|
|
1539
|
+
const exact = COMMON_LOCALES.find((l) => l.code.toLowerCase() === code.toLowerCase());
|
|
1540
|
+
if (exact) return exact.name;
|
|
1541
|
+
const base = COMMON_LOCALES.find((l) => l.code.toLowerCase() === baseLanguage(code));
|
|
1542
|
+
return base ? `${base.name} (${code})` : code;
|
|
1543
|
+
}
|
|
1544
|
+
function normalizeLocale(input) {
|
|
1545
|
+
if (typeof input !== "string") return "";
|
|
1546
|
+
const parts = input.trim().replace(/_/g, "-").split("-").filter(Boolean);
|
|
1547
|
+
if (!parts.length || !/^[a-zA-Z]{2,3}$/.test(parts[0])) return "";
|
|
1548
|
+
return parts.slice(0, 3).map((p, i) => i === 0 ? p.toLowerCase() : p.length === 4 ? p[0].toUpperCase() + p.slice(1).toLowerCase() : p.length === 2 ? p.toUpperCase() : p).join("-");
|
|
1549
|
+
}
|
|
1550
|
+
function baseLanguage(locale) {
|
|
1551
|
+
return normalizeLocale(locale).split("-")[0] ?? "";
|
|
1552
|
+
}
|
|
1553
|
+
function resolveLocale(requested, available, defaultLocale = DEFAULT_LOCALE) {
|
|
1554
|
+
const def = normalizeLocale(defaultLocale) || DEFAULT_LOCALE;
|
|
1555
|
+
const avail = available.map(normalizeLocale).filter(Boolean);
|
|
1556
|
+
const all = [def, ...avail.filter((a) => a.toLowerCase() !== def.toLowerCase())];
|
|
1557
|
+
for (const raw of requested) {
|
|
1558
|
+
const want = normalizeLocale(raw);
|
|
1559
|
+
if (!want) continue;
|
|
1560
|
+
const exact = all.find((a) => a.toLowerCase() === want.toLowerCase());
|
|
1561
|
+
if (exact) return exact;
|
|
1562
|
+
const base = baseLanguage(want);
|
|
1563
|
+
const sameBase = all.find((a) => a.toLowerCase() === base) ?? all.find((a) => baseLanguage(a) === base);
|
|
1564
|
+
if (sameBase) return sameBase;
|
|
1565
|
+
}
|
|
1566
|
+
return def;
|
|
1567
|
+
}
|
|
1568
|
+
function visitorLocales(explicit, traits, platform = []) {
|
|
1569
|
+
const out = [];
|
|
1570
|
+
const push = (v) => {
|
|
1571
|
+
const n = normalizeLocale(v);
|
|
1572
|
+
if (n && !out.includes(n)) out.push(n);
|
|
1573
|
+
};
|
|
1574
|
+
push(explicit);
|
|
1575
|
+
push(traits?.language);
|
|
1576
|
+
push(traits?.locale);
|
|
1577
|
+
for (const p of platform) push(p);
|
|
1578
|
+
return out;
|
|
1579
|
+
}
|
|
1580
|
+
function guideTextEntries(config) {
|
|
1581
|
+
const out = [];
|
|
1582
|
+
const add = (key, source, kind, label) => {
|
|
1583
|
+
if (source && source.trim()) out.push({ key, source, kind, label });
|
|
1584
|
+
};
|
|
1585
|
+
config.steps.forEach((s, i) => {
|
|
1586
|
+
const at = `Step ${i + 1}`;
|
|
1587
|
+
add(`steps.${s.id}.title`, s.title, "text", `${at} \xB7 Title`);
|
|
1588
|
+
add(`steps.${s.id}.body`, s.body, "html", `${at} \xB7 Body`);
|
|
1589
|
+
add(`steps.${s.id}.customHtml`, s.customHtml, "html", `${at} \xB7 Custom HTML`);
|
|
1590
|
+
add(`steps.${s.id}.imageAlt`, s.imageAlt, "text", `${at} \xB7 Image description`);
|
|
1591
|
+
s.buttons.forEach((b) => add(`steps.${s.id}.buttons.${b.id}.label`, b.label, "text", `${at} \xB7 Button \u201C${b.label}\u201D`));
|
|
1592
|
+
});
|
|
1593
|
+
const c = config.checklist;
|
|
1594
|
+
if (c) {
|
|
1595
|
+
add("checklist.launcherLabel", c.launcherLabel, "text", "Checklist \xB7 Launcher label");
|
|
1596
|
+
add("checklist.completionTitle", c.completionTitle, "text", "Checklist \xB7 Completion title");
|
|
1597
|
+
add("checklist.completionBody", c.completionBody, "html", "Checklist \xB7 Completion message");
|
|
1598
|
+
c.tasks.forEach((t, i) => {
|
|
1599
|
+
add(`checklist.tasks.${t.id}.title`, t.title, "text", `Task ${i + 1} \xB7 Title`);
|
|
1600
|
+
add(`checklist.tasks.${t.id}.description`, t.description, "html", `Task ${i + 1} \xB7 Description`);
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
const sv = config.survey;
|
|
1604
|
+
if (sv) {
|
|
1605
|
+
sv.questions.forEach((q, i) => {
|
|
1606
|
+
const at = `Question ${i + 1}`;
|
|
1607
|
+
add(`survey.questions.${q.id}.title`, q.title, "text", `${at} \xB7 Question`);
|
|
1608
|
+
add(`survey.questions.${q.id}.description`, q.description, "text", `${at} \xB7 Description`);
|
|
1609
|
+
add(`survey.questions.${q.id}.placeholder`, q.placeholder, "text", `${at} \xB7 Placeholder`);
|
|
1610
|
+
add(`survey.questions.${q.id}.lowLabel`, q.lowLabel, "text", `${at} \xB7 Low label`);
|
|
1611
|
+
add(`survey.questions.${q.id}.highLabel`, q.highLabel, "text", `${at} \xB7 High label`);
|
|
1612
|
+
q.options.forEach((o) => add(`survey.questions.${q.id}.options.${o.id}.label`, o.label, "text", `${at} \xB7 Option \u201C${o.label}\u201D`));
|
|
1613
|
+
});
|
|
1614
|
+
add("survey.thankYouTitle", sv.thankYouTitle, "text", "Survey \xB7 Thank-you title");
|
|
1615
|
+
add("survey.thankYouBody", sv.thankYouBody, "html", "Survey \xB7 Thank-you message");
|
|
1616
|
+
}
|
|
1617
|
+
return out;
|
|
1618
|
+
}
|
|
1619
|
+
function guideLocales(config) {
|
|
1620
|
+
const t = config.localization?.translations ?? {};
|
|
1621
|
+
return Object.keys(t).filter((l) => Object.values(t[l] ?? {}).some((v) => typeof v === "string" && v.trim() !== ""));
|
|
1622
|
+
}
|
|
1623
|
+
function pick(map, key, fallback) {
|
|
1624
|
+
const v = map?.[key];
|
|
1625
|
+
return typeof v === "string" && v.trim() !== "" ? v : fallback;
|
|
1626
|
+
}
|
|
1627
|
+
function applyGuideTranslations(config, map) {
|
|
1628
|
+
if (!map || !Object.keys(map).length) return config;
|
|
1629
|
+
return {
|
|
1630
|
+
...config,
|
|
1631
|
+
steps: config.steps.map((s) => ({
|
|
1632
|
+
...s,
|
|
1633
|
+
title: pick(map, `steps.${s.id}.title`, s.title),
|
|
1634
|
+
body: pick(map, `steps.${s.id}.body`, s.body),
|
|
1635
|
+
customHtml: pick(map, `steps.${s.id}.customHtml`, s.customHtml),
|
|
1636
|
+
imageAlt: pick(map, `steps.${s.id}.imageAlt`, s.imageAlt),
|
|
1637
|
+
buttons: s.buttons.map((b) => ({ ...b, label: pick(map, `steps.${s.id}.buttons.${b.id}.label`, b.label) }))
|
|
1638
|
+
})),
|
|
1639
|
+
checklist: config.checklist ? {
|
|
1640
|
+
...config.checklist,
|
|
1641
|
+
launcherLabel: pick(map, "checklist.launcherLabel", config.checklist.launcherLabel),
|
|
1642
|
+
completionTitle: pick(map, "checklist.completionTitle", config.checklist.completionTitle),
|
|
1643
|
+
completionBody: pick(map, "checklist.completionBody", config.checklist.completionBody),
|
|
1644
|
+
tasks: config.checklist.tasks.map((t) => ({ ...t, title: pick(map, `checklist.tasks.${t.id}.title`, t.title), description: pick(map, `checklist.tasks.${t.id}.description`, t.description) }))
|
|
1645
|
+
} : config.checklist,
|
|
1646
|
+
survey: config.survey ? {
|
|
1647
|
+
...config.survey,
|
|
1648
|
+
thankYouTitle: pick(map, "survey.thankYouTitle", config.survey.thankYouTitle),
|
|
1649
|
+
thankYouBody: pick(map, "survey.thankYouBody", config.survey.thankYouBody),
|
|
1650
|
+
questions: config.survey.questions.map((q) => ({
|
|
1651
|
+
...q,
|
|
1652
|
+
title: pick(map, `survey.questions.${q.id}.title`, q.title),
|
|
1653
|
+
description: pick(map, `survey.questions.${q.id}.description`, q.description),
|
|
1654
|
+
placeholder: pick(map, `survey.questions.${q.id}.placeholder`, q.placeholder),
|
|
1655
|
+
lowLabel: pick(map, `survey.questions.${q.id}.lowLabel`, q.lowLabel),
|
|
1656
|
+
highLabel: pick(map, `survey.questions.${q.id}.highLabel`, q.highLabel),
|
|
1657
|
+
options: q.options.map((o) => ({ ...o, label: pick(map, `survey.questions.${q.id}.options.${o.id}.label`, o.label) }))
|
|
1658
|
+
}))
|
|
1659
|
+
} : config.survey
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
function localizeGuide(guide, requested, defaultLocale = DEFAULT_LOCALE) {
|
|
1663
|
+
const translations = guide.config.localization?.translations ?? {};
|
|
1664
|
+
const locale = resolveLocale(requested, guideLocales(guide.config), defaultLocale);
|
|
1665
|
+
const key = Object.keys(translations).find((l) => normalizeLocale(l).toLowerCase() === locale.toLowerCase());
|
|
1666
|
+
if (!key) return { ...guide, locale };
|
|
1667
|
+
return { ...guide, locale, config: applyGuideTranslations(guide.config, translations[key]) };
|
|
1668
|
+
}
|
|
1669
|
+
function translationCoverage(entries, map, locale) {
|
|
1670
|
+
const keys = new Set(entries.map((e) => e.key));
|
|
1671
|
+
const missing = entries.filter((e) => !pick(map, e.key, void 0)).map((e) => e.key);
|
|
1672
|
+
const stale = Object.keys(map ?? {}).filter((k) => !keys.has(k) && (map?.[k] ?? "").trim() !== "");
|
|
1673
|
+
return { locale, total: entries.length, translated: entries.length - missing.length, missing, stale };
|
|
1674
|
+
}
|
|
1675
|
+
function resourceCenterTextEntries(rc) {
|
|
1676
|
+
const out = [];
|
|
1677
|
+
const add = (key, source, kind, label) => {
|
|
1678
|
+
if (source && source.trim()) out.push({ key, source, kind, label });
|
|
1679
|
+
};
|
|
1680
|
+
add("title", rc.title, "text", "Title");
|
|
1681
|
+
add("launcher.label", rc.launcher?.label, "text", "Launcher label");
|
|
1682
|
+
rc.collections.forEach((c) => {
|
|
1683
|
+
add(`collections.${c.id}.name`, c.name, "text", `Collection \u201C${c.name}\u201D`);
|
|
1684
|
+
add(`collections.${c.id}.description`, c.description, "text", `Collection \u201C${c.name}\u201D \xB7 Description`);
|
|
1685
|
+
});
|
|
1686
|
+
rc.links.forEach((l) => add(`links.${l.id}.label`, l.label, "text", `Link \u201C${l.label}\u201D`));
|
|
1687
|
+
rc.faqs.forEach((f, i) => {
|
|
1688
|
+
add(`faqs.${f.id}.question`, f.question, "text", `FAQ ${i + 1} \xB7 Question`);
|
|
1689
|
+
add(`faqs.${f.id}.answer`, f.answer, "html", `FAQ ${i + 1} \xB7 Answer`);
|
|
1690
|
+
});
|
|
1691
|
+
return out;
|
|
1692
|
+
}
|
|
1693
|
+
function articleTextEntries(a) {
|
|
1694
|
+
const out = [];
|
|
1695
|
+
if (a.title.trim()) out.push({ key: "title", source: a.title, kind: "text", label: "Title" });
|
|
1696
|
+
if (a.summary?.trim()) out.push({ key: "summary", source: a.summary, kind: "text", label: "Summary" });
|
|
1697
|
+
if (a.body?.trim()) out.push({ key: "body", source: a.body, kind: "html", label: "Body" });
|
|
1698
|
+
return out;
|
|
1699
|
+
}
|
|
1700
|
+
function resourceCenterLocales(rc) {
|
|
1701
|
+
const set = new Set(Object.keys(rc.translations ?? {}));
|
|
1702
|
+
for (const a of rc.articles) for (const l of Object.keys(a.translations ?? {})) set.add(l);
|
|
1703
|
+
for (const a of rc.announcements ?? []) for (const l of Object.keys(a.translations ?? {})) set.add(l);
|
|
1704
|
+
return [...set];
|
|
1705
|
+
}
|
|
1706
|
+
function translationFor(map, locale) {
|
|
1707
|
+
if (!map) return void 0;
|
|
1708
|
+
const key = Object.keys(map).find((l) => normalizeLocale(l).toLowerCase() === locale.toLowerCase());
|
|
1709
|
+
return key ? map[key] : void 0;
|
|
1710
|
+
}
|
|
1711
|
+
function localizeArticle(a, locale) {
|
|
1712
|
+
const t = translationFor(a.translations, locale);
|
|
1713
|
+
if (!t) return a;
|
|
1714
|
+
const body = t.body?.trim() ? t.body : a.body;
|
|
1715
|
+
return { ...a, title: t.title?.trim() ? t.title : a.title, summary: t.summary?.trim() ? t.summary : a.summary, body, ...t.bodyOmitted ? { bodyOmitted: true } : {} };
|
|
1716
|
+
}
|
|
1717
|
+
function localizeAnnouncement(a, locale) {
|
|
1718
|
+
const t = translationFor(a.translations, locale);
|
|
1719
|
+
if (!t) return a;
|
|
1720
|
+
return { ...a, title: t.title?.trim() ? t.title : a.title, body: t.body?.trim() ? t.body : a.body };
|
|
1721
|
+
}
|
|
1722
|
+
function localizeResourceCenter(rc, requested, defaultLocale = DEFAULT_LOCALE) {
|
|
1723
|
+
const locale = resolveLocale(requested, resourceCenterLocales(rc), defaultLocale);
|
|
1724
|
+
if (locale.toLowerCase() === normalizeLocale(defaultLocale).toLowerCase()) return { ...rc, locale };
|
|
1725
|
+
const map = translationFor(rc.translations, locale);
|
|
1726
|
+
return {
|
|
1727
|
+
...rc,
|
|
1728
|
+
locale,
|
|
1729
|
+
title: pick(map, "title", rc.title),
|
|
1730
|
+
launcher: { ...rc.launcher, label: pick(map, "launcher.label", rc.launcher.label) },
|
|
1731
|
+
collections: rc.collections.map((c) => ({ ...c, name: pick(map, `collections.${c.id}.name`, c.name), description: pick(map, `collections.${c.id}.description`, c.description) })),
|
|
1732
|
+
links: rc.links.map((l) => ({ ...l, label: pick(map, `links.${l.id}.label`, l.label) })),
|
|
1733
|
+
faqs: rc.faqs.map((f) => ({ ...f, question: pick(map, `faqs.${f.id}.question`, f.question), answer: pick(map, `faqs.${f.id}.answer`, f.answer) })),
|
|
1734
|
+
articles: rc.articles.map((a) => localizeArticle(a, locale)),
|
|
1735
|
+
announcements: rc.announcements?.map((a) => localizeAnnouncement(a, locale))
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// src/guide-experiments.ts
|
|
1740
|
+
var CONTROL_VARIANT_ID = "control";
|
|
1741
|
+
var GUIDE_EXPERIMENT_STATUSES = ["draft", "running", "completed"];
|
|
1742
|
+
var GUIDE_EXPERIMENT_GOALS = ["guide_completed", "event", "page_visit", "click_text"];
|
|
1743
|
+
var GUIDE_EXPERIMENT_GOAL_LABELS = {
|
|
1744
|
+
guide_completed: "Completes the guide",
|
|
1745
|
+
event: "Tracks an event",
|
|
1746
|
+
page_visit: "Visits a page",
|
|
1747
|
+
click_text: "Clicks an element with text"
|
|
1748
|
+
};
|
|
1749
|
+
function experimentSalt(experimentId) {
|
|
1750
|
+
return `gx:${experimentId}`;
|
|
1751
|
+
}
|
|
1752
|
+
function variantRanges(variants) {
|
|
1753
|
+
let at = 0;
|
|
1754
|
+
return variants.map((v) => {
|
|
1755
|
+
const from = at;
|
|
1756
|
+
at = Math.min(100, at + Math.max(0, Math.round(v.weight)));
|
|
1757
|
+
return { id: v.id, from, to: at };
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
function assignGuideVariant(variants, experimentId, subject) {
|
|
1761
|
+
const bucket = rolloutBucket(subject, experimentSalt(experimentId));
|
|
1762
|
+
return variantRanges(variants).find((r) => bucket >= r.from && bucket < r.to)?.id ?? null;
|
|
1763
|
+
}
|
|
1764
|
+
function experimentBucketRules(salt, from, to) {
|
|
1765
|
+
return [
|
|
1766
|
+
{ id: "experiment-from", field: "experiment.bucket", key: salt, op: "gte", value: from },
|
|
1767
|
+
{ id: "experiment-to", field: "experiment.bucket", key: salt, op: "lt", value: to }
|
|
1768
|
+
];
|
|
1769
|
+
}
|
|
1770
|
+
function withExperimentBucket(targeting, salt, from, to) {
|
|
1771
|
+
return { id: "experiment", op: "and", rules: [...experimentBucketRules(salt, from, to), targeting] };
|
|
1772
|
+
}
|
|
1773
|
+
function variantProblems(variants) {
|
|
1774
|
+
const problems = [];
|
|
1775
|
+
if (variants.length < 2) problems.push("An A/B test needs at least two variants.");
|
|
1776
|
+
if (variants.length > 5) problems.push("An A/B test can have at most five variants.");
|
|
1777
|
+
const guides = variants.filter((v) => v.guideId);
|
|
1778
|
+
if (guides.length === 0) problems.push("At least one variant must show a guide.");
|
|
1779
|
+
if (variants.filter((v) => !v.guideId).length > 1) problems.push("Only one variant can be the control group (no guide).");
|
|
1780
|
+
if (new Set(guides.map((v) => v.guideId)).size !== guides.length) problems.push("Each variant needs its own guide.");
|
|
1781
|
+
if (new Set(variants.map((v) => v.id)).size !== variants.length) problems.push("Variant ids must be unique.");
|
|
1782
|
+
if (variants.some((v) => !Number.isInteger(v.weight) || v.weight < 1)) problems.push("Every variant needs a whole-number share of at least 1%.");
|
|
1783
|
+
const total = variants.reduce((s, v) => s + v.weight, 0);
|
|
1784
|
+
if (total !== 100) problems.push(`Traffic shares must add up to 100% (now ${total}%).`);
|
|
1785
|
+
return problems;
|
|
1786
|
+
}
|
|
1787
|
+
function evenWeights(n) {
|
|
1788
|
+
if (n <= 0) return [];
|
|
1789
|
+
const base = Math.floor(100 / n);
|
|
1790
|
+
return Array.from({ length: n }, (_, i) => base + (i < 100 - base * n ? 1 : 0));
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// src/custom-css.ts
|
|
1794
|
+
var MAX_CUSTOM_CSS = 2e4;
|
|
1795
|
+
var BLOCKED_AT_RULES = /^@(import|charset|namespace|document|-moz-document)\b/i;
|
|
1796
|
+
var ALLOWED_AT_RULES = /^@(media|supports|container|layer|keyframes|-webkit-keyframes|font-face)\b/i;
|
|
1797
|
+
function splitBlocks(css) {
|
|
1798
|
+
const out = [];
|
|
1799
|
+
let i = 0;
|
|
1800
|
+
const n = css.length;
|
|
1801
|
+
while (i < n) {
|
|
1802
|
+
let prelude = "";
|
|
1803
|
+
let quote = null;
|
|
1804
|
+
while (i < n) {
|
|
1805
|
+
const ch = css[i];
|
|
1806
|
+
if (quote) {
|
|
1807
|
+
prelude += ch;
|
|
1808
|
+
if (ch === "\\") prelude += css[++i] ?? "";
|
|
1809
|
+
else if (ch === quote) quote = null;
|
|
1810
|
+
} else if (ch === '"' || ch === "'") {
|
|
1811
|
+
quote = ch;
|
|
1812
|
+
prelude += ch;
|
|
1813
|
+
} else if (ch === "{") break;
|
|
1814
|
+
else if (ch === ";") {
|
|
1815
|
+
prelude = "";
|
|
1816
|
+
} else if (ch === "}") {
|
|
1817
|
+
prelude = "";
|
|
1818
|
+
} else prelude += ch;
|
|
1819
|
+
i++;
|
|
1820
|
+
}
|
|
1821
|
+
if (i >= n) break;
|
|
1822
|
+
i++;
|
|
1823
|
+
let depth = 1;
|
|
1824
|
+
let body = "";
|
|
1825
|
+
quote = null;
|
|
1826
|
+
while (i < n && depth > 0) {
|
|
1827
|
+
const ch = css[i];
|
|
1828
|
+
if (quote) {
|
|
1829
|
+
body += ch;
|
|
1830
|
+
if (ch === "\\") body += css[++i] ?? "";
|
|
1831
|
+
else if (ch === quote) quote = null;
|
|
1832
|
+
} else if (ch === '"' || ch === "'") {
|
|
1833
|
+
quote = ch;
|
|
1834
|
+
body += ch;
|
|
1835
|
+
} else if (ch === "{") {
|
|
1836
|
+
depth++;
|
|
1837
|
+
body += ch;
|
|
1838
|
+
} else if (ch === "}") {
|
|
1839
|
+
depth--;
|
|
1840
|
+
if (depth > 0) body += ch;
|
|
1841
|
+
} else body += ch;
|
|
1842
|
+
i++;
|
|
1843
|
+
}
|
|
1844
|
+
out.push({ prelude: prelude.trim(), body });
|
|
1845
|
+
}
|
|
1846
|
+
return out;
|
|
1847
|
+
}
|
|
1848
|
+
function splitSelectors(list) {
|
|
1849
|
+
const out = [];
|
|
1850
|
+
let depth = 0;
|
|
1851
|
+
let cur = "";
|
|
1852
|
+
for (const ch of list) {
|
|
1853
|
+
if (ch === "(" || ch === "[") depth++;
|
|
1854
|
+
else if (ch === ")" || ch === "]") depth = Math.max(0, depth - 1);
|
|
1855
|
+
if (ch === "," && depth === 0) {
|
|
1856
|
+
out.push(cur.trim());
|
|
1857
|
+
cur = "";
|
|
1858
|
+
} else cur += ch;
|
|
1859
|
+
}
|
|
1860
|
+
if (cur.trim()) out.push(cur.trim());
|
|
1861
|
+
return out;
|
|
1862
|
+
}
|
|
1863
|
+
function safeUrl(raw) {
|
|
1864
|
+
const u = raw.trim().replace(/^['"]|['"]$/g, "").trim();
|
|
1865
|
+
return /^https:\/\//i.test(u) || /^data:image\/(png|jpe?g|gif|webp|svg\+xml)[;,]/i.test(u);
|
|
1866
|
+
}
|
|
1867
|
+
function cleanDeclarations(body) {
|
|
1868
|
+
return body.replace(/url\(([^)]*)\)/gi, (m, inner) => safeUrl(inner) ? m : "none").replace(/expression\s*\(/gi, "(").replace(/javascript\s*:/gi, "").replace(/(^|[;{\s])(-moz-binding|behavior)\s*:[^;]*;?/gi, "$1").replace(/[{}]/g, "").trim();
|
|
1869
|
+
}
|
|
1870
|
+
function sanitizeCustomCss(input) {
|
|
1871
|
+
if (!input) return "";
|
|
1872
|
+
let css = String(input).slice(0, MAX_CUSTOM_CSS);
|
|
1873
|
+
css = css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, "").replace(/<\/?[a-z!][^>]*>/gi, "").replace(/</g, "");
|
|
1874
|
+
return render(splitBlocks(css), 0);
|
|
1875
|
+
}
|
|
1876
|
+
function render(blocks, depth) {
|
|
1877
|
+
const parts = [];
|
|
1878
|
+
for (const b of blocks) {
|
|
1879
|
+
if (!b.prelude) continue;
|
|
1880
|
+
if (b.prelude.startsWith("@")) {
|
|
1881
|
+
if (BLOCKED_AT_RULES.test(b.prelude) || !ALLOWED_AT_RULES.test(b.prelude)) continue;
|
|
1882
|
+
if (/^@(-webkit-)?keyframes|^@font-face/i.test(b.prelude)) {
|
|
1883
|
+
const inner = /^@font-face/i.test(b.prelude) ? cleanDeclarations(b.body) : splitBlocks(b.body).map((k) => `${k.prelude}{${cleanDeclarations(k.body)}}`).join("");
|
|
1884
|
+
parts.push(`${b.prelude}{${inner}}`);
|
|
1885
|
+
} else if (depth < 3) parts.push(`${b.prelude}{${render(splitBlocks(b.body), depth + 1)}}`);
|
|
1886
|
+
continue;
|
|
1887
|
+
}
|
|
1888
|
+
const selectors = splitSelectors(b.prelude).filter((s) => !/:host|::slotted|::part/i.test(s));
|
|
1889
|
+
if (!selectors.length) continue;
|
|
1890
|
+
parts.push(`${selectors.join(",")}{${cleanDeclarations(b.body)}}`);
|
|
1891
|
+
}
|
|
1892
|
+
return parts.join("\n");
|
|
1893
|
+
}
|
|
1894
|
+
function scopeCustomCss(css, scope) {
|
|
1895
|
+
return scopeBlocks(splitBlocks(sanitizeCustomCss(css)), scope, 0);
|
|
1896
|
+
}
|
|
1897
|
+
function scopeBlocks(blocks, scope, depth) {
|
|
1898
|
+
const parts = [];
|
|
1899
|
+
for (const b of blocks) {
|
|
1900
|
+
if (b.prelude.startsWith("@")) {
|
|
1901
|
+
if (/^@(-webkit-)?keyframes|^@font-face/i.test(b.prelude)) parts.push(`${b.prelude}{${b.body}}`);
|
|
1902
|
+
else if (depth < 3) parts.push(`${b.prelude}{${scopeBlocks(splitBlocks(b.body), scope, depth + 1)}}`);
|
|
1903
|
+
continue;
|
|
1904
|
+
}
|
|
1905
|
+
const sels = splitSelectors(b.prelude).map((s) => {
|
|
1906
|
+
const self = s.match(/^(:root|html|body|:scope|&)(?![\w-])(.*)$/i);
|
|
1907
|
+
if (self) return `${scope}${self[2] ?? ""}`;
|
|
1908
|
+
return `${scope} ${s}`;
|
|
1909
|
+
});
|
|
1910
|
+
parts.push(`${sels.join(",")}{${b.body}}`);
|
|
1911
|
+
}
|
|
1912
|
+
return parts.join("\n");
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// src/contrast.ts
|
|
1916
|
+
var WCAG_AA_TEXT = 4.5;
|
|
1917
|
+
var WCAG_AA_LARGE = 3;
|
|
1918
|
+
function channel(c) {
|
|
1919
|
+
const s = c / 255;
|
|
1920
|
+
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
1921
|
+
}
|
|
1922
|
+
function parseHexColor(hex) {
|
|
1923
|
+
if (!hex) return null;
|
|
1924
|
+
const m = hex.trim().match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
|
1925
|
+
if (!m) return null;
|
|
1926
|
+
const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
|
|
1927
|
+
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
1928
|
+
}
|
|
1929
|
+
function relativeLuminance(hex) {
|
|
1930
|
+
const rgb = parseHexColor(hex);
|
|
1931
|
+
if (!rgb) return null;
|
|
1932
|
+
return 0.2126 * channel(rgb[0]) + 0.7152 * channel(rgb[1]) + 0.0722 * channel(rgb[2]);
|
|
1933
|
+
}
|
|
1934
|
+
function contrastRatio(a, b) {
|
|
1935
|
+
const la = relativeLuminance(a);
|
|
1936
|
+
const lb = relativeLuminance(b);
|
|
1937
|
+
if (la === null || lb === null) return null;
|
|
1938
|
+
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
1939
|
+
return Math.round((hi + 0.05) / (lo + 0.05) * 100) / 100;
|
|
1940
|
+
}
|
|
1941
|
+
function readableTextOn(background) {
|
|
1942
|
+
const white = contrastRatio(background, "#ffffff") ?? 0;
|
|
1943
|
+
const dark = contrastRatio(background, "#111827") ?? 0;
|
|
1944
|
+
return white >= dark ? "#ffffff" : "#111827";
|
|
1945
|
+
}
|
|
1946
|
+
function contrastIssues(colors) {
|
|
1947
|
+
const issues = [];
|
|
1948
|
+
const { primaryColor, backgroundColor, textColor } = colors;
|
|
1949
|
+
if (textColor && backgroundColor) {
|
|
1950
|
+
const r = contrastRatio(textColor, backgroundColor);
|
|
1951
|
+
if (r !== null && r < WCAG_AA_TEXT) issues.push({ pair: "text", ratio: r, required: WCAG_AA_TEXT, message: `Text on the background has a contrast of ${r}:1; WCAG AA needs ${WCAG_AA_TEXT}:1.` });
|
|
1952
|
+
}
|
|
1953
|
+
if (primaryColor) {
|
|
1954
|
+
const label = contrastRatio(primaryColor, readableTextOn(primaryColor));
|
|
1955
|
+
if (label !== null && label < WCAG_AA_TEXT) issues.push({ pair: "button", ratio: label, required: WCAG_AA_TEXT, message: `Button labels on the primary colour have a contrast of ${label}:1; WCAG AA needs ${WCAG_AA_TEXT}:1.` });
|
|
1956
|
+
if (backgroundColor) {
|
|
1957
|
+
const link = contrastRatio(primaryColor, backgroundColor);
|
|
1958
|
+
if (link !== null && link < WCAG_AA_LARGE) issues.push({ pair: "link", ratio: link, required: WCAG_AA_LARGE, message: `The primary colour on the background (links, outlined buttons) has a contrast of ${link}:1; WCAG AA needs ${WCAG_AA_LARGE}:1.` });
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
return issues;
|
|
1962
|
+
}
|
|
831
1963
|
// Annotate the CommonJS export names for ESM import in node:
|
|
832
1964
|
0 && (module.exports = {
|
|
1965
|
+
AGENT_METADATA_MAX_BYTES,
|
|
1966
|
+
AGENT_METADATA_MAX_KEYS,
|
|
1967
|
+
AGENT_OUTCOMES,
|
|
1968
|
+
AGENT_TOOL_CALLS_PER_TURN,
|
|
1969
|
+
AGENT_TOOL_STATUSES,
|
|
1970
|
+
AGENT_TURNS_PER_BATCH,
|
|
1971
|
+
AGENT_TURN_MAX_TEXT,
|
|
1972
|
+
AGENT_TURN_ROLES,
|
|
833
1973
|
ARTICLE_VISIBILITIES,
|
|
834
1974
|
CAPTURE_PARAM,
|
|
835
1975
|
CAPTURE_SCREENSHOT_MAX_BYTES,
|
|
1976
|
+
COMMON_LOCALES,
|
|
836
1977
|
COMPLAINT_EVENTS,
|
|
837
1978
|
COMPLAINT_FIELD_TYPES,
|
|
838
1979
|
COMPLAINT_STATUSES,
|
|
1980
|
+
CONTROL_VARIANT_ID,
|
|
1981
|
+
DEFAULT_FEATURE_ATTRIBUTE,
|
|
1982
|
+
DEFAULT_LOCALE,
|
|
839
1983
|
DEFAULT_PLATFORMS,
|
|
840
1984
|
EMBED_IFRAME_ATTRS,
|
|
1985
|
+
FEATURE_ATTRIBUTE_PATTERN,
|
|
1986
|
+
FEATURE_RULE_LIMITS,
|
|
841
1987
|
FILE_LINK_CLASS,
|
|
842
1988
|
GUIDELY_ID_ATTRIBUTE,
|
|
1989
|
+
GUIDE_EXPERIMENT_GOALS,
|
|
1990
|
+
GUIDE_EXPERIMENT_GOAL_LABELS,
|
|
1991
|
+
GUIDE_EXPERIMENT_STATUSES,
|
|
843
1992
|
GUIDE_VISIBILITIES,
|
|
844
1993
|
LOGGED_IN_AUDIENCE,
|
|
845
1994
|
MAX_COLLECTION_DEPTH,
|
|
@@ -848,6 +1997,7 @@ var complaintReference = (number) => `CMP-${number}`;
|
|
|
848
1997
|
MAX_COMPLAINT_CHOICES,
|
|
849
1998
|
MAX_COMPLAINT_FIELDS,
|
|
850
1999
|
MAX_COMPLAINT_LENGTH,
|
|
2000
|
+
MAX_CUSTOM_CSS,
|
|
851
2001
|
MAX_PROPERTY_BYTES,
|
|
852
2002
|
MAX_STACK_FRAMES,
|
|
853
2003
|
MEDIA_FILE_MAX_BYTES,
|
|
@@ -858,38 +2008,65 @@ var complaintReference = (number) => `CMP-${number}`;
|
|
|
858
2008
|
MEDIA_VIDEO_MAX_BYTES,
|
|
859
2009
|
MEDIA_VIDEO_TYPES,
|
|
860
2010
|
NETWORK_PLUGIN,
|
|
2011
|
+
NOISY_DATA_ATTR,
|
|
2012
|
+
PAGE_RULE_LIMITS,
|
|
861
2013
|
PATH_ID_PATTERN,
|
|
862
2014
|
PDF_BLOCK_CLASS,
|
|
863
2015
|
PDF_MAX_PAGES,
|
|
864
2016
|
PDF_PAGES_CLASS,
|
|
865
2017
|
PLATFORMS,
|
|
2018
|
+
RC_MODULE_IDS,
|
|
2019
|
+
RC_MODULE_LABELS,
|
|
866
2020
|
RULE_FIELDS,
|
|
867
2021
|
RULE_OPERATORS,
|
|
2022
|
+
SCOUT_AGENT_ID,
|
|
868
2023
|
SENSITIVE_HEADER_PATTERN,
|
|
869
2024
|
SENSITIVE_PARAM_PATTERN,
|
|
870
2025
|
SENSITIVE_PROPERTY_PATTERN,
|
|
871
2026
|
SERVER_ASSISTED_FIELDS,
|
|
872
2027
|
SHOW_ME_CLASS,
|
|
873
2028
|
SHOW_ME_HREF_PREFIX,
|
|
2029
|
+
SNAPSHOT_ATTRS,
|
|
2030
|
+
SNAPSHOT_LIMITS,
|
|
874
2031
|
SOURCEMAP_MAX_FILES_PER_UPLOAD,
|
|
875
2032
|
SOURCEMAP_MAX_FILE_BYTES,
|
|
2033
|
+
SelectorSyntaxError,
|
|
2034
|
+
TAG_PROPERTY_LIMITS,
|
|
876
2035
|
VIDEO_ATTRS,
|
|
2036
|
+
WCAG_AA_LARGE,
|
|
2037
|
+
WCAG_AA_TEXT,
|
|
877
2038
|
WS_MAX_MESSAGES_PER_SOCKET,
|
|
878
2039
|
WS_MAX_MESSAGE_BYTES,
|
|
2040
|
+
applyGuideTranslations,
|
|
2041
|
+
articleTextEntries,
|
|
2042
|
+
assignGuideVariant,
|
|
2043
|
+
baseLanguage,
|
|
879
2044
|
clamp,
|
|
880
2045
|
compare,
|
|
881
2046
|
compareVersions,
|
|
882
2047
|
complaintReference,
|
|
2048
|
+
compoundMatches,
|
|
2049
|
+
contrastIssues,
|
|
2050
|
+
contrastRatio,
|
|
2051
|
+
cssSelectorError,
|
|
883
2052
|
describeRule,
|
|
884
2053
|
emptyRuleGroup,
|
|
885
2054
|
evaluateRule,
|
|
886
2055
|
evaluateRules,
|
|
2056
|
+
evenWeights,
|
|
2057
|
+
experimentBucketRules,
|
|
2058
|
+
experimentSalt,
|
|
2059
|
+
featureCssSelectors,
|
|
2060
|
+
featureRuleError,
|
|
2061
|
+
featureRuleMatchesClick,
|
|
887
2062
|
fingerprintError,
|
|
888
2063
|
firstNameFromTraits,
|
|
889
2064
|
fnv1a,
|
|
890
2065
|
foldPathIds,
|
|
891
2066
|
getPath,
|
|
2067
|
+
guideLocales,
|
|
892
2068
|
guidePlatforms,
|
|
2069
|
+
guideTextEntries,
|
|
893
2070
|
guidelyIdFromSelector,
|
|
894
2071
|
hasVideoMedia,
|
|
895
2072
|
isAllowedEmbedSrc,
|
|
@@ -902,32 +2079,66 @@ var complaintReference = (number) => `CMP-${number}`;
|
|
|
902
2079
|
isRuleGroup,
|
|
903
2080
|
isSafeMediaUrl,
|
|
904
2081
|
isVideoContentType,
|
|
2082
|
+
localeName,
|
|
2083
|
+
localizeAnnouncement,
|
|
2084
|
+
localizeArticle,
|
|
2085
|
+
localizeGuide,
|
|
2086
|
+
localizeResourceCenter,
|
|
2087
|
+
matchCssSelector,
|
|
905
2088
|
matchUrlPattern,
|
|
906
2089
|
matchesAudiences,
|
|
907
2090
|
matchesHelpQuery,
|
|
908
2091
|
mediaKind,
|
|
909
2092
|
mediaMaxBytes,
|
|
2093
|
+
needsReview,
|
|
910
2094
|
normalizeErrorMessage,
|
|
911
2095
|
normalizeFrameFile,
|
|
2096
|
+
normalizeLocale,
|
|
2097
|
+
normalizeSnapshot,
|
|
2098
|
+
orderedModules,
|
|
912
2099
|
pageLabel,
|
|
2100
|
+
pagePattern,
|
|
2101
|
+
pageRuleError,
|
|
2102
|
+
pageRuleMatches,
|
|
2103
|
+
pageRulesMatch,
|
|
913
2104
|
pageTerms,
|
|
2105
|
+
parseCssSelector,
|
|
2106
|
+
parseHexColor,
|
|
914
2107
|
parseStack,
|
|
2108
|
+
propertyAttributeAllowed,
|
|
2109
|
+
queryConditionRegex,
|
|
915
2110
|
randomId,
|
|
2111
|
+
readableTextOn,
|
|
2112
|
+
relativeLuminance,
|
|
2113
|
+
resolveLocale,
|
|
2114
|
+
resourceCenterLocales,
|
|
916
2115
|
resourceCenterSections,
|
|
2116
|
+
resourceCenterTextEntries,
|
|
917
2117
|
rolloutBucket,
|
|
918
2118
|
safeRegExp,
|
|
2119
|
+
sanitizeCustomCss,
|
|
919
2120
|
sanitizeProperties,
|
|
2121
|
+
scopeCustomCss,
|
|
920
2122
|
screenPath,
|
|
921
2123
|
servedArticleAudiences,
|
|
922
2124
|
showMeHref,
|
|
923
2125
|
showMeKeyFromHref,
|
|
924
2126
|
showMeKeys,
|
|
925
2127
|
slugify,
|
|
2128
|
+
snapshotFromSelector,
|
|
2129
|
+
stableStringify,
|
|
926
2130
|
stripOrigin,
|
|
927
2131
|
supportsPlatform,
|
|
928
2132
|
toEmbedUrl,
|
|
2133
|
+
translationCoverage,
|
|
2134
|
+
unreadAnnouncements,
|
|
2135
|
+
variantProblems,
|
|
2136
|
+
variantRanges,
|
|
2137
|
+
visibleAnnouncements,
|
|
929
2138
|
visibleArticleIds,
|
|
930
2139
|
visitorAudiences,
|
|
2140
|
+
visitorLocales,
|
|
2141
|
+
withExperimentBucket,
|
|
931
2142
|
withVisibility
|
|
932
2143
|
});
|
|
933
2144
|
//# sourceMappingURL=runtime.cjs.map
|