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