@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/index.cjs CHANGED
@@ -21,9 +21,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ADVANCE_ON: () => ADVANCE_ON,
24
+ AGENT_METADATA_MAX_BYTES: () => AGENT_METADATA_MAX_BYTES,
25
+ AGENT_METADATA_MAX_KEYS: () => AGENT_METADATA_MAX_KEYS,
26
+ AGENT_OUTCOMES: () => AGENT_OUTCOMES,
27
+ AGENT_TOOL_CALLS_PER_TURN: () => AGENT_TOOL_CALLS_PER_TURN,
28
+ AGENT_TOOL_STATUSES: () => AGENT_TOOL_STATUSES,
29
+ AGENT_TURNS_PER_BATCH: () => AGENT_TURNS_PER_BATCH,
30
+ AGENT_TURN_MAX_TEXT: () => AGENT_TURN_MAX_TEXT,
31
+ AGENT_TURN_ROLES: () => AGENT_TURN_ROLES,
24
32
  ANNOTATION_COLORS: () => ANNOTATION_COLORS,
33
+ APP_LIFECYCLE_EVENTS: () => APP_LIFECYCLE_EVENTS,
25
34
  ARTICLE_VISIBILITIES: () => ARTICLE_VISIBILITIES,
26
35
  AUTOCAPTURE_EVENTS: () => AUTOCAPTURE_EVENTS,
36
+ AgentEventsRequestSchema: () => AgentEventsRequestSchema,
37
+ AgentMetadataSchema: () => AgentMetadataSchema,
38
+ AgentToolCallSchema: () => AgentToolCallSchema,
39
+ AgentTurnInputSchema: () => AgentTurnInputSchema,
27
40
  AppearanceSchema: () => AppearanceSchema,
28
41
  AuthoringPickSchema: () => AuthoringPickSchema,
29
42
  AutocaptureSettingsSchema: () => AutocaptureSettingsSchema,
@@ -31,9 +44,11 @@ __export(index_exports, {
31
44
  ButtonSchema: () => ButtonSchema,
32
45
  CAPTURE_PARAM: () => CAPTURE_PARAM,
33
46
  CAPTURE_SCREENSHOT_MAX_BYTES: () => CAPTURE_SCREENSHOT_MAX_BYTES,
47
+ COMMON_LOCALES: () => COMMON_LOCALES,
34
48
  COMPLAINT_EVENTS: () => COMPLAINT_EVENTS,
35
49
  COMPLAINT_FIELD_TYPES: () => COMPLAINT_FIELD_TYPES,
36
50
  COMPLAINT_STATUSES: () => COMPLAINT_STATUSES,
51
+ CONTROL_VARIANT_ID: () => CONTROL_VARIANT_ID,
37
52
  CaptureStepSchema: () => CaptureStepSchema,
38
53
  CapturedElementSchema: () => CapturedElementSchema,
39
54
  ChecklistConfigSchema: () => ChecklistConfigSchema,
@@ -42,28 +57,54 @@ __export(index_exports, {
42
57
  ConversationLookupSchema: () => ConversationLookupSchema,
43
58
  ConversationRatingSchema: () => ConversationRatingSchema,
44
59
  DEFAULT_CAPTURE_SETTINGS: () => DEFAULT_CAPTURE_SETTINGS,
60
+ DEFAULT_FEATURE_ATTRIBUTE: () => DEFAULT_FEATURE_ATTRIBUTE,
61
+ DEFAULT_LOCALE: () => DEFAULT_LOCALE,
45
62
  DEFAULT_PLATFORMS: () => DEFAULT_PLATFORMS,
46
63
  EMBED_IFRAME_ATTRS: () => EMBED_IFRAME_ATTRS,
47
64
  EVENT_NAMES: () => EVENT_NAMES,
48
65
  ErrorTrackingSettingsSchema: () => ErrorTrackingSettingsSchema,
49
66
  EventBatchSchema: () => EventBatchSchema,
67
+ FEATURE_ATTRIBUTE_PATTERN: () => FEATURE_ATTRIBUTE_PATTERN,
68
+ FEATURE_RULE_LIMITS: () => FEATURE_RULE_LIMITS,
69
+ FEEDBACK_EVENTS: () => FEEDBACK_EVENTS,
70
+ FEEDBACK_PRIORITIES: () => FEEDBACK_PRIORITIES,
71
+ FEEDBACK_PRIORITY_LABEL: () => FEEDBACK_PRIORITY_LABEL,
72
+ FEEDBACK_PRIORITY_WEIGHT: () => FEEDBACK_PRIORITY_WEIGHT,
73
+ FEEDBACK_STATUSES: () => FEEDBACK_STATUSES,
74
+ FEEDBACK_STATUS_LABEL: () => FEEDBACK_STATUS_LABEL,
50
75
  FILE_LINK_CLASS: () => FILE_LINK_CLASS,
76
+ FeedbackCommentSchema: () => FeedbackCommentSchema,
77
+ FeedbackFollowSchema: () => FeedbackFollowSchema,
78
+ FeedbackListRequestSchema: () => FeedbackListRequestSchema,
79
+ FeedbackSimilarSchema: () => FeedbackSimilarSchema,
80
+ FeedbackUpdatesReadSchema: () => FeedbackUpdatesReadSchema,
81
+ FeedbackVisitorSchema: () => FeedbackVisitorSchema,
82
+ FeedbackVoteSchema: () => FeedbackVoteSchema,
51
83
  FileComplaintSchema: () => FileComplaintSchema,
52
84
  FrequencySchema: () => FrequencySchema,
53
85
  GUIDELY_ID_ATTRIBUTE: () => GUIDELY_ID_ATTRIBUTE,
86
+ GUIDE_EXPERIMENT_GOALS: () => GUIDE_EXPERIMENT_GOALS,
87
+ GUIDE_EXPERIMENT_GOAL_LABELS: () => GUIDE_EXPERIMENT_GOAL_LABELS,
88
+ GUIDE_EXPERIMENT_STATUSES: () => GUIDE_EXPERIMENT_STATUSES,
54
89
  GUIDE_KINDS: () => GUIDE_KINDS,
55
90
  GUIDE_LIFECYCLE_EVENTS: () => GUIDE_LIFECYCLE_EVENTS,
56
91
  GUIDE_STATUSES: () => GUIDE_STATUSES,
57
92
  GUIDE_TEMPLATES: () => GUIDE_TEMPLATES,
58
93
  GUIDE_VISIBILITIES: () => GUIDE_VISIBILITIES,
59
94
  GuideConfigSchema: () => GuideConfigSchema,
95
+ GuideLocalizationSchema: () => GuideLocalizationSchema,
96
+ GuideScheduleSchema: () => GuideScheduleSchema,
60
97
  GuideStateUpdateSchema: () => GuideStateUpdateSchema,
98
+ GuideThrottlingSchema: () => GuideThrottlingSchema,
61
99
  HEATMAP_VIEWPORTS: () => HEATMAP_VIEWPORTS,
62
100
  HOWTO_ACTIONS: () => HOWTO_ACTIONS,
63
101
  HOWTO_STEP_KINDS: () => HOWTO_STEP_KINDS,
64
102
  HowToAnnotationSchema: () => HowToAnnotationSchema,
65
103
  IdentifyRequestSchema: () => IdentifyRequestSchema,
104
+ LOCALE_PATTERN: () => LOCALE_PATTERN,
66
105
  LOGGED_IN_AUDIENCE: () => LOGGED_IN_AUDIENCE,
106
+ LocaleSchema: () => LocaleSchema,
107
+ LocalizationSettingsSchema: () => LocalizationSettingsSchema,
67
108
  MAX_ANNOTATIONS: () => MAX_ANNOTATIONS,
68
109
  MAX_COLLECTION_DEPTH: () => MAX_COLLECTION_DEPTH,
69
110
  MAX_COMPLAINT_ANSWER_LENGTH: () => MAX_COMPLAINT_ANSWER_LENGTH,
@@ -71,6 +112,11 @@ __export(index_exports, {
71
112
  MAX_COMPLAINT_CHOICES: () => MAX_COMPLAINT_CHOICES,
72
113
  MAX_COMPLAINT_FIELDS: () => MAX_COMPLAINT_FIELDS,
73
114
  MAX_COMPLAINT_LENGTH: () => MAX_COMPLAINT_LENGTH,
115
+ MAX_CUSTOM_CSS: () => MAX_CUSTOM_CSS,
116
+ MAX_FEEDBACK_COMMENT: () => MAX_FEEDBACK_COMMENT,
117
+ MAX_FEEDBACK_DESCRIPTION: () => MAX_FEEDBACK_DESCRIPTION,
118
+ MAX_FEEDBACK_NOTE: () => MAX_FEEDBACK_NOTE,
119
+ MAX_FEEDBACK_TITLE: () => MAX_FEEDBACK_TITLE,
74
120
  MAX_MESSAGE_LENGTH: () => MAX_MESSAGE_LENGTH,
75
121
  MAX_PROPERTY_BYTES: () => MAX_PROPERTY_BYTES,
76
122
  MAX_STACK_FRAMES: () => MAX_STACK_FRAMES,
@@ -84,8 +130,10 @@ __export(index_exports, {
84
130
  MESSAGE_AUTHORS: () => MESSAGE_AUTHORS,
85
131
  MessengerPageRequestSchema: () => MessengerPageRequestSchema,
86
132
  NETWORK_PLUGIN: () => NETWORK_PLUGIN,
133
+ NOISY_DATA_ATTR: () => NOISY_DATA_ATTR,
87
134
  NormalizedPointSchema: () => NormalizedPointSchema,
88
135
  NormalizedRectSchema: () => NormalizedRectSchema,
136
+ PAGE_RULE_LIMITS: () => PAGE_RULE_LIMITS,
89
137
  PATH_ID_PATTERN: () => PATH_ID_PATTERN,
90
138
  PDF_BLOCK_CLASS: () => PDF_BLOCK_CLASS,
91
139
  PDF_MAX_PAGES: () => PDF_MAX_PAGES,
@@ -95,6 +143,8 @@ __export(index_exports, {
95
143
  PostMessageSchema: () => PostMessageSchema,
96
144
  ProjectThemeSchema: () => ProjectThemeSchema,
97
145
  PublishedGuideSchema: () => PublishedGuideSchema,
146
+ RC_MODULE_IDS: () => RC_MODULE_IDS,
147
+ RC_MODULE_LABELS: () => RC_MODULE_LABELS,
98
148
  REPLAY_MAX_COMPRESSED_BYTES: () => REPLAY_MAX_COMPRESSED_BYTES,
99
149
  REPLAY_MAX_RAW_BYTES: () => REPLAY_MAX_RAW_BYTES,
100
150
  REPLY_TIMES: () => REPLY_TIMES,
@@ -104,6 +154,7 @@ __export(index_exports, {
104
154
  ReplaySettingsSchema: () => ReplaySettingsSchema,
105
155
  RuleGroupSchema: () => RuleGroupSchema,
106
156
  RuleSchema: () => RuleSchema,
157
+ SCOUT_AGENT_ID: () => SCOUT_AGENT_ID,
107
158
  SCRIPT_STUB: () => SCRIPT_STUB,
108
159
  SCRIPT_STUB_METHODS: () => SCRIPT_STUB_METHODS,
109
160
  SDK_API_VERSION: () => SDK_API_VERSION,
@@ -115,30 +166,46 @@ __export(index_exports, {
115
166
  SHARED_VERSION: () => SHARED_VERSION,
116
167
  SHOW_ME_CLASS: () => SHOW_ME_CLASS,
117
168
  SHOW_ME_HREF_PREFIX: () => SHOW_ME_HREF_PREFIX,
169
+ SNAPSHOT_ATTRS: () => SNAPSHOT_ATTRS,
170
+ SNAPSHOT_LIMITS: () => SNAPSHOT_LIMITS,
118
171
  SOURCEMAP_MAX_FILES_PER_UPLOAD: () => SOURCEMAP_MAX_FILES_PER_UPLOAD,
119
172
  SOURCEMAP_MAX_FILE_BYTES: () => SOURCEMAP_MAX_FILE_BYTES,
120
173
  STATUS_LEVELS: () => STATUS_LEVELS,
121
174
  STEP_TYPES: () => STEP_TYPES,
122
175
  SURVEY_QUESTION_TYPES: () => SURVEY_QUESTION_TYPES,
176
+ SdkAgentEventsSchema: () => SdkAgentEventsSchema,
123
177
  SdkEventSchema: () => SdkEventSchema,
124
178
  SelectorStrategySchema: () => SelectorStrategySchema,
179
+ SelectorSyntaxError: () => SelectorSyntaxError,
125
180
  StartConversationSchema: () => StartConversationSchema,
126
181
  StepBranchSchema: () => StepBranchSchema,
127
182
  StepSchema: () => StepSchema,
183
+ SubmitFeedbackSchema: () => SubmitFeedbackSchema,
128
184
  SurveyConfigSchema: () => SurveyConfigSchema,
129
185
  SurveyQuestionSchema: () => SurveyQuestionSchema,
130
186
  SurveyResponseRequestSchema: () => SurveyResponseRequestSchema,
187
+ TAG_PROPERTY_LIMITS: () => TAG_PROPERTY_LIMITS,
131
188
  TRIGGER_TYPES: () => TRIGGER_TYPES,
132
189
  TargetSchema: () => TargetSchema,
133
190
  TriggerSchema: () => TriggerSchema,
134
191
  VIDEO_ATTRS: () => VIDEO_ATTRS,
192
+ WCAG_AA_LARGE: () => WCAG_AA_LARGE,
193
+ WCAG_AA_TEXT: () => WCAG_AA_TEXT,
135
194
  WS_MAX_MESSAGES_PER_SOCKET: () => WS_MAX_MESSAGES_PER_SOCKET,
136
195
  WS_MAX_MESSAGE_BYTES: () => WS_MAX_MESSAGE_BYTES,
196
+ applyGuideTranslations: () => applyGuideTranslations,
197
+ articleTextEntries: () => articleTextEntries,
198
+ assignGuideVariant: () => assignGuideVariant,
199
+ baseLanguage: () => baseLanguage,
137
200
  clamp: () => clamp,
138
201
  cleanLabel: () => cleanLabel,
139
202
  compare: () => compare,
140
203
  compareVersions: () => compareVersions,
141
204
  complaintReference: () => complaintReference,
205
+ compoundMatches: () => compoundMatches,
206
+ contrastIssues: () => contrastIssues,
207
+ contrastRatio: () => contrastRatio,
208
+ cssSelectorError: () => cssSelectorError,
142
209
  defaultGuideConfig: () => defaultGuideConfig,
143
210
  defaultStep: () => defaultStep,
144
211
  describeCaptureStep: () => describeCaptureStep,
@@ -146,12 +213,21 @@ __export(index_exports, {
146
213
  emptyRuleGroup: () => emptyRuleGroup,
147
214
  evaluateRule: () => evaluateRule,
148
215
  evaluateRules: () => evaluateRules,
216
+ evenWeights: () => evenWeights,
217
+ experimentBucketRules: () => experimentBucketRules,
218
+ experimentSalt: () => experimentSalt,
219
+ featureCssSelectors: () => featureCssSelectors,
220
+ featureRuleError: () => featureRuleError,
221
+ featureRuleMatchesClick: () => featureRuleMatchesClick,
222
+ feedbackReference: () => feedbackReference,
149
223
  fingerprintError: () => fingerprintError,
150
224
  firstNameFromTraits: () => firstNameFromTraits,
151
225
  fnv1a: () => fnv1a,
152
226
  foldPathIds: () => foldPathIds,
153
227
  getPath: () => getPath,
228
+ guideLocales: () => guideLocales,
154
229
  guidePlatforms: () => guidePlatforms,
230
+ guideTextEntries: () => guideTextEntries,
155
231
  guidelyIdFromSelector: () => guidelyIdFromSelector,
156
232
  hasVideoMedia: () => hasVideoMedia,
157
233
  isAllowedEmbedSrc: () => isAllowedEmbedSrc,
@@ -164,23 +240,51 @@ __export(index_exports, {
164
240
  isRuleGroup: () => isRuleGroup,
165
241
  isSafeMediaUrl: () => isSafeMediaUrl,
166
242
  isVideoContentType: () => isVideoContentType,
243
+ localeName: () => localeName,
244
+ localizeAnnouncement: () => localizeAnnouncement,
245
+ localizeArticle: () => localizeArticle,
246
+ localizeGuide: () => localizeGuide,
247
+ localizeResourceCenter: () => localizeResourceCenter,
248
+ matchCssSelector: () => matchCssSelector,
167
249
  matchUrlPattern: () => matchUrlPattern,
168
250
  matchesAudiences: () => matchesAudiences,
169
251
  matchesHelpQuery: () => matchesHelpQuery,
170
252
  mediaKind: () => mediaKind,
171
253
  mediaMaxBytes: () => mediaMaxBytes,
254
+ needsReview: () => needsReview,
172
255
  normalizeErrorMessage: () => normalizeErrorMessage,
173
256
  normalizeFrameFile: () => normalizeFrameFile,
257
+ normalizeLocale: () => normalizeLocale,
258
+ normalizeSnapshot: () => normalizeSnapshot,
259
+ orderedModules: () => orderedModules,
174
260
  pageLabel: () => pageLabel,
175
261
  pageName: () => pageName,
262
+ pagePattern: () => pagePattern,
263
+ pageRuleError: () => pageRuleError,
264
+ pageRuleMatches: () => pageRuleMatches,
265
+ pageRulesMatch: () => pageRulesMatch,
176
266
  pageTerms: () => pageTerms,
267
+ parseCssSelector: () => parseCssSelector,
268
+ parseCsvRows: () => parseCsvRows,
269
+ parseHexColor: () => parseHexColor,
177
270
  parseStack: () => parseStack,
271
+ parseTranslationCsv: () => parseTranslationCsv,
272
+ parseXliff: () => parseXliff,
273
+ propertyAttributeAllowed: () => propertyAttributeAllowed,
274
+ queryConditionRegex: () => queryConditionRegex,
178
275
  randomId: () => randomId,
276
+ readableTextOn: () => readableTextOn,
277
+ relativeLuminance: () => relativeLuminance,
179
278
  resolveCaptureSettings: () => resolveCaptureSettings,
279
+ resolveLocale: () => resolveLocale,
280
+ resourceCenterLocales: () => resourceCenterLocales,
180
281
  resourceCenterSections: () => resourceCenterSections,
282
+ resourceCenterTextEntries: () => resourceCenterTextEntries,
181
283
  rolloutBucket: () => rolloutBucket,
182
284
  safeRegExp: () => safeRegExp,
285
+ sanitizeCustomCss: () => sanitizeCustomCss,
183
286
  sanitizeProperties: () => sanitizeProperties,
287
+ scopeCustomCss: () => scopeCustomCss,
184
288
  screenPath: () => screenPath,
185
289
  scriptSnippet: () => scriptSnippet,
186
290
  servedArticleAudiences: () => servedArticleAudiences,
@@ -188,14 +292,25 @@ __export(index_exports, {
188
292
  showMeKeyFromHref: () => showMeKeyFromHref,
189
293
  showMeKeys: () => showMeKeys,
190
294
  slugify: () => slugify,
295
+ snapshotFromSelector: () => snapshotFromSelector,
296
+ stableStringify: () => stableStringify,
191
297
  stripOrigin: () => stripOrigin,
192
298
  supportsPlatform: () => supportsPlatform,
193
299
  templateConfig: () => templateConfig,
194
300
  toEmbedUrl: () => toEmbedUrl,
301
+ toTranslationCsv: () => toTranslationCsv,
302
+ toXliff: () => toXliff,
303
+ translationCoverage: () => translationCoverage,
304
+ unreadAnnouncements: () => unreadAnnouncements,
195
305
  validateGuideConfig: () => validateGuideConfig,
306
+ variantProblems: () => variantProblems,
307
+ variantRanges: () => variantRanges,
308
+ visibleAnnouncements: () => visibleAnnouncements,
196
309
  visibleArticleIds: () => visibleArticleIds,
197
310
  visibleButtons: () => visibleButtons,
198
311
  visitorAudiences: () => visitorAudiences,
312
+ visitorLocales: () => visitorLocales,
313
+ withExperimentBucket: () => withExperimentBucket,
199
314
  withVisibility: () => withVisibility
200
315
  });
201
316
  module.exports = __toCommonJS(index_exports);
@@ -390,17 +505,21 @@ var RULE_FIELDS = [
390
505
  "datetime.dayOfWeek",
391
506
  "datetime.hour",
392
507
  "rollout.percentage",
508
+ /** Guide A/B tests: the visitor's 0-99 bucket for the salt in `key` (see guide-experiments.ts). */
509
+ "experiment.bucket",
393
510
  "environment",
394
511
  "locale",
395
512
  "app.platform",
396
513
  "app.screen",
397
- "app.version"
514
+ "app.version",
515
+ "page.views",
516
+ "feature.clicks"
398
517
  ];
399
518
  function isRuleGroup(r) {
400
519
  return r.rules !== void 0;
401
520
  }
402
- function emptyRuleGroup(id = "root") {
403
- return { id, op: "and", rules: [] };
521
+ function emptyRuleGroup(id2 = "root") {
522
+ return { id: id2, op: "and", rules: [] };
404
523
  }
405
524
  function has(set, v) {
406
525
  if (!set) return false;
@@ -454,6 +573,8 @@ function resolveField(rule, ctx) {
454
573
  return ctx.now.getHours();
455
574
  case "rollout.percentage":
456
575
  return rolloutBucket(ctx.userId || ctx.anonymousId, ctx.rolloutSalt || "guidely");
576
+ case "experiment.bucket":
577
+ return rule.key ? rolloutBucket(ctx.userId || ctx.anonymousId, rule.key) : void 0;
457
578
  case "environment":
458
579
  return ctx.environment;
459
580
  case "locale":
@@ -464,6 +585,9 @@ function resolveField(rule, ctx) {
464
585
  return ctx.screen;
465
586
  case "app.version":
466
587
  return ctx.appVersion;
588
+ case "page.views":
589
+ case "feature.clicks":
590
+ return rule.key ? ctx.tagUsage?.[rule.key] ?? 0 : 0;
467
591
  default:
468
592
  return void 0;
469
593
  }
@@ -563,7 +687,7 @@ function evaluateRules(group, ctx) {
563
687
  const value = group.op === "and" ? results.every(Boolean) : results.some(Boolean);
564
688
  return group.negate ? !value : value;
565
689
  }
566
- var SERVER_ASSISTED_FIELDS = ["audience.member", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed"];
690
+ var SERVER_ASSISTED_FIELDS = ["audience.member", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed", "page.views", "feature.clicks"];
567
691
  var GUIDE_VISIBILITIES = ["everyone", "identified", "anonymous"];
568
692
  function withVisibility(targeting, visibility) {
569
693
  if (!visibility || visibility === "everyone") return targeting;
@@ -595,6 +719,57 @@ var RuleGroupSchema = import_zod.z.lazy(
595
719
 
596
720
  // src/guide.ts
597
721
  var import_zod2 = require("zod");
722
+
723
+ // src/contrast.ts
724
+ var WCAG_AA_TEXT = 4.5;
725
+ var WCAG_AA_LARGE = 3;
726
+ function channel(c) {
727
+ const s = c / 255;
728
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
729
+ }
730
+ function parseHexColor(hex) {
731
+ if (!hex) return null;
732
+ const m = hex.trim().match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);
733
+ if (!m) return null;
734
+ const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
735
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
736
+ }
737
+ function relativeLuminance(hex) {
738
+ const rgb = parseHexColor(hex);
739
+ if (!rgb) return null;
740
+ return 0.2126 * channel(rgb[0]) + 0.7152 * channel(rgb[1]) + 0.0722 * channel(rgb[2]);
741
+ }
742
+ function contrastRatio(a, b) {
743
+ const la = relativeLuminance(a);
744
+ const lb = relativeLuminance(b);
745
+ if (la === null || lb === null) return null;
746
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
747
+ return Math.round((hi + 0.05) / (lo + 0.05) * 100) / 100;
748
+ }
749
+ function readableTextOn(background) {
750
+ const white = contrastRatio(background, "#ffffff") ?? 0;
751
+ const dark = contrastRatio(background, "#111827") ?? 0;
752
+ return white >= dark ? "#ffffff" : "#111827";
753
+ }
754
+ function contrastIssues(colors) {
755
+ const issues = [];
756
+ const { primaryColor, backgroundColor, textColor } = colors;
757
+ if (textColor && backgroundColor) {
758
+ const r = contrastRatio(textColor, backgroundColor);
759
+ 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.` });
760
+ }
761
+ if (primaryColor) {
762
+ const label = contrastRatio(primaryColor, readableTextOn(primaryColor));
763
+ 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.` });
764
+ if (backgroundColor) {
765
+ const link = contrastRatio(primaryColor, backgroundColor);
766
+ 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.` });
767
+ }
768
+ }
769
+ return issues;
770
+ }
771
+
772
+ // src/guide.ts
598
773
  var GUIDE_KINDS = ["flow", "modal", "tooltip", "banner", "checklist", "survey", "announcement"];
599
774
  var GUIDE_STATUSES = ["draft", "published", "paused", "archived"];
600
775
  var STEP_TYPES = ["modal", "tooltip", "popover", "spotlight", "hotspot", "banner", "slideout", "checklist", "custom", "survey"];
@@ -643,6 +818,8 @@ var StepSchema = import_zod2.z.object({
643
818
  /** Sanitized HTML body (links, images, lists, formatting). */
644
819
  body: import_zod2.z.string().max(2e4).default(""),
645
820
  imageUrl: import_zod2.z.string().url().max(2e3).optional().or(import_zod2.z.literal("")),
821
+ /** Alternative text for `imageUrl` (screen readers); empty = decorative. */
822
+ imageAlt: import_zod2.z.string().max(300).optional(),
646
823
  buttons: import_zod2.z.array(ButtonSchema).max(6).default([]),
647
824
  target: TargetSchema.optional(),
648
825
  placement: import_zod2.z.enum(PLACEMENTS).default("auto"),
@@ -669,7 +846,12 @@ var StepSchema = import_zod2.z.object({
669
846
  /** Hotspot pulse dot settings. */
670
847
  hotspot: import_zod2.z.object({ size: import_zod2.z.number().int().min(8).max(40).default(14), pulse: import_zod2.z.boolean().default(true), openOn: import_zod2.z.enum(["click", "hover"]).default("click") }).optional(),
671
848
  /** Custom step: arbitrary sanitized HTML with no chrome. */
672
- customHtml: import_zod2.z.string().max(5e4).optional()
849
+ customHtml: import_zod2.z.string().max(5e4).optional(),
850
+ /**
851
+ * Code block (custom steps only): JavaScript run on the web when the step shows, only while the
852
+ * workspace allows code blocks (an admin setting, off by default). Mobile SDKs never receive it.
853
+ */
854
+ code: import_zod2.z.string().max(2e4).optional()
673
855
  });
674
856
  var TRIGGER_TYPES = ["page_load", "url_match", "event", "element_click", "element_visible", "manual", "delay", "after_guide", "segment_enter"];
675
857
  var TriggerSchema = import_zod2.z.object({
@@ -691,7 +873,9 @@ var FrequencySchema = import_zod2.z.object({
691
873
  /** Guide ids that must not be active at the same time. */
692
874
  mutuallyExclusiveWith: import_zod2.z.array(import_zod2.z.string()).max(50).default([]),
693
875
  /** Re-show if dismissed (otherwise dismissal counts as completion for frequency). */
694
- reshowAfterDismiss: import_zod2.z.boolean().default(false)
876
+ reshowAfterDismiss: import_zod2.z.boolean().default(false),
877
+ /** Bypass the project's guide throttling (always eligible as far as throttling goes). */
878
+ ignoreThrottling: import_zod2.z.boolean().optional()
695
879
  });
696
880
  var AppearanceSchema = import_zod2.z.object({
697
881
  theme: import_zod2.z.enum(["light", "dark", "auto"]).default("auto"),
@@ -703,7 +887,9 @@ var AppearanceSchema = import_zod2.z.object({
703
887
  overlayOpacity: import_zod2.z.number().min(0).max(1).optional(),
704
888
  zIndex: import_zod2.z.number().int().min(1).max(2147483647).optional(),
705
889
  preset: import_zod2.z.string().max(50).optional(),
706
- animation: import_zod2.z.enum(["fade", "slide", "none"]).default("fade")
890
+ animation: import_zod2.z.enum(["fade", "slide", "none"]).default("fade"),
891
+ /** Custom CSS scoped to this guide's container (sanitized; see custom-css.ts). Web only. */
892
+ customCss: import_zod2.z.string().max(2e4).optional()
707
893
  });
708
894
  var ChecklistTaskSchema = import_zod2.z.object({
709
895
  id: import_zod2.z.string().min(1),
@@ -750,6 +936,30 @@ var SurveyConfigSchema = import_zod2.z.object({
750
936
  startAt: import_zod2.z.string().datetime().optional(),
751
937
  endAt: import_zod2.z.string().datetime().optional()
752
938
  });
939
+ var GuideScheduleSchema = import_zod2.z.object({
940
+ startAt: import_zod2.z.string().datetime().optional(),
941
+ endAt: import_zod2.z.string().datetime().optional(),
942
+ timezone: import_zod2.z.string().max(64).optional()
943
+ });
944
+ var LOCALE_PATTERN = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8}){0,2}$/;
945
+ var LocaleSchema = import_zod2.z.string().regex(LOCALE_PATTERN, "Use a language code such as fr or pt-BR").max(20);
946
+ var GuideLocalizationSchema = import_zod2.z.object({
947
+ translations: import_zod2.z.record(LocaleSchema, import_zod2.z.record(import_zod2.z.string().max(200), import_zod2.z.string().max(5e4))).default({})
948
+ });
949
+ var LocalizationSettingsSchema = import_zod2.z.object({
950
+ defaultLocale: LocaleSchema.default("en"),
951
+ locales: import_zod2.z.array(LocaleSchema).max(50).default([]),
952
+ /** Machine-translate new and changed text into every language automatically (needs an Anthropic key). */
953
+ autoTranslate: import_zod2.z.boolean().optional(),
954
+ /** Machine translations go live only once a teammate approves them; until then visitors see the default language. */
955
+ requireReview: import_zod2.z.boolean().optional()
956
+ });
957
+ var GuideThrottlingSchema = import_zod2.z.object({
958
+ enabled: import_zod2.z.boolean().default(false),
959
+ maxGuides: import_zod2.z.number().int().min(1).max(50).default(1),
960
+ windowHours: import_zod2.z.number().int().min(1).max(720).default(24),
961
+ minGapMinutes: import_zod2.z.number().int().min(0).max(10080).default(0)
962
+ });
753
963
  var GuideConfigSchema = import_zod2.z.object({
754
964
  steps: import_zod2.z.array(StepSchema).max(50).default([]),
755
965
  /** Everyone, only identified (logged-in) users, or only anonymous visitors; applied on top of `targeting`. */
@@ -763,7 +973,11 @@ var GuideConfigSchema = import_zod2.z.object({
763
973
  /** Restrict guide to url pattern(s) (applied before trigger). On mobile these match the screen path `/<Screen>`. */
764
974
  urlPatterns: import_zod2.z.array(import_zod2.z.string().max(500)).max(20).default([]),
765
975
  /** Platforms that receive this guide. Guides created before mobile support are web-only. */
766
- platforms: import_zod2.z.array(import_zod2.z.enum(PLATFORMS)).max(PLATFORMS.length).default(["web"])
976
+ platforms: import_zod2.z.array(import_zod2.z.enum(PLATFORMS)).max(PLATFORMS.length).default(["web"]),
977
+ /** Start / end window for any guide kind (surveys also honour `survey.startAt` / `endAt`). */
978
+ schedule: GuideScheduleSchema.optional(),
979
+ /** Translations (see localization.ts). */
980
+ localization: GuideLocalizationSchema.optional()
767
981
  });
768
982
  function defaultGuideConfig(kind) {
769
983
  return GuideConfigSchema.parse({
@@ -797,7 +1011,7 @@ function defaultStep(type, overrides = {}) {
797
1011
  function visibleButtons(step, canGoBack) {
798
1012
  return canGoBack ? step.buttons : step.buttons.filter((b) => b.action !== "back");
799
1013
  }
800
- function validateGuideConfig(kind, config) {
1014
+ function validateGuideConfig(kind, config, theme) {
801
1015
  const issues = [];
802
1016
  if (kind === "checklist") {
803
1017
  if (!config.checklist || config.checklist.tasks.length === 0) issues.push({ level: "error", message: "Checklist needs at least one task." });
@@ -834,6 +1048,15 @@ function validateGuideConfig(kind, config) {
834
1048
  if (config.trigger.type === "element_click" && !config.trigger.value) issues.push({ level: "error", message: "Element click trigger needs a selector." });
835
1049
  if (config.trigger.type === "url_match" && !config.trigger.value) issues.push({ level: "error", message: "URL trigger needs a pattern." });
836
1050
  if (config.frequency.mode === "interval" && !config.frequency.intervalHours) issues.push({ level: "error", message: "Interval frequency needs an interval in hours." });
1051
+ const sched = config.schedule;
1052
+ if (sched?.startAt && sched.endAt && Date.parse(sched.endAt) <= Date.parse(sched.startAt)) issues.push({ level: "error", message: "The schedule ends before it starts." });
1053
+ if (sched?.endAt && Date.parse(sched.endAt) < Date.now()) issues.push({ level: "warning", message: "The schedule has already ended, so nobody will see this guide." });
1054
+ config.steps.forEach((step, i) => {
1055
+ if (step.code && step.type !== "custom") issues.push({ level: "error", stepId: step.id, message: `Step ${i + 1}: code blocks can only run in custom steps.` });
1056
+ if (step.code && mobile) issues.push({ level: "warning", stepId: step.id, message: `Step ${i + 1} runs a code block; mobile apps skip it.` });
1057
+ });
1058
+ const colors = { primaryColor: config.appearance.primaryColor ?? theme?.primaryColor, backgroundColor: config.appearance.backgroundColor ?? theme?.backgroundColor, textColor: config.appearance.textColor ?? theme?.textColor };
1059
+ for (const c of contrastIssues(colors)) issues.push({ level: "warning", message: `Low contrast: ${c.message}` });
837
1060
  return issues;
838
1061
  }
839
1062
  var ProjectThemeSchema = import_zod2.z.object({
@@ -843,7 +1066,9 @@ var ProjectThemeSchema = import_zod2.z.object({
843
1066
  borderRadius: import_zod2.z.number().int().min(0).max(32).default(12),
844
1067
  fontFamily: import_zod2.z.string().max(200).default("Inter, system-ui, -apple-system, sans-serif"),
845
1068
  logoUrl: import_zod2.z.string().max(2e3).optional(),
846
- brandName: import_zod2.z.string().max(100).optional()
1069
+ brandName: import_zod2.z.string().max(100).optional(),
1070
+ /** Custom CSS applied to every guide's container (sanitized and scoped like guide CSS). Web only. */
1071
+ customCss: import_zod2.z.string().max(2e4).optional()
847
1072
  });
848
1073
 
849
1074
  // src/events.ts
@@ -859,8 +1084,8 @@ function sanitizeProperties(props) {
859
1084
  for (const [k, v] of Object.entries(props)) {
860
1085
  if (SENSITIVE_PROPERTY_PATTERN.test(k)) continue;
861
1086
  if (typeof v === "function" || typeof v === "symbol") continue;
862
- const str = typeof v === "string" ? v : JSON.stringify(v ?? null);
863
- size += k.length + (str?.length ?? 0);
1087
+ const str2 = typeof v === "string" ? v : JSON.stringify(v ?? null);
1088
+ size += k.length + (str2?.length ?? 0);
864
1089
  if (size > MAX_PROPERTY_BYTES) break;
865
1090
  out[k.slice(0, 100)] = typeof v === "string" ? v.slice(0, 1e3) : v;
866
1091
  }
@@ -897,7 +1122,7 @@ function normalizeFrameFile(file) {
897
1122
  }
898
1123
  return path.replace(/[.-][0-9a-f]{6,}(?=\.\w+$)/i, "").replace(/\/\d+\//g, "/<n>/");
899
1124
  }
900
- var SOURCEMAP_MAX_FILE_BYTES = 25 * 1024 * 1024;
1125
+ var SOURCEMAP_MAX_FILE_BYTES = 100 * 1024 * 1024;
901
1126
  var SOURCEMAP_MAX_FILES_PER_UPLOAD = 200;
902
1127
  function fingerprintError(input) {
903
1128
  const top = (input.frames ?? []).find((f) => f.file);
@@ -940,9 +1165,15 @@ var EVENT_NAMES = [
940
1165
  "exception",
941
1166
  "heatmap",
942
1167
  // Feature flags: a user was bucketed into an experiment variation (properties: experimentKey, variationId, flagKey).
943
- "experiment_viewed"
1168
+ "experiment_viewed",
1169
+ // Mobile app lifecycle (mobile/SPEC.md "Product analytics"): installs, updates, opens and backgrounding.
1170
+ "app_install",
1171
+ "app_update",
1172
+ "app_open",
1173
+ "app_background"
944
1174
  ];
945
- var AUTOCAPTURE_EVENTS = ["page_view", "page_leave", "click", "rage_click", "exception", "heatmap"];
1175
+ var AUTOCAPTURE_EVENTS = ["page_view", "page_leave", "click", "rage_click", "exception", "heatmap", "app_install", "app_update", "app_open", "app_background"];
1176
+ var APP_LIFECYCLE_EVENTS = ["app_install", "app_update", "app_open", "app_background"];
946
1177
  var GUIDE_LIFECYCLE_EVENTS = ["guide_viewed", "guide_started", "step_viewed", "step_completed", "guide_completed", "guide_skipped", "guide_dismissed", "guide_abandoned"];
947
1178
  var SdkEventSchema = import_zod3.z.object({
948
1179
  eventId: import_zod3.z.string().min(8).max(64),
@@ -1010,7 +1241,9 @@ var AuthoringPickSchema = import_zod4.z.object({
1010
1241
  selectors: import_zod4.z.array(import_zod4.z.object({ kind: import_zod4.z.string(), value: import_zod4.z.string().max(1e3), label: import_zod4.z.string().max(200).optional() })).max(10),
1011
1242
  textSnapshot: import_zod4.z.string().max(200).optional(),
1012
1243
  url: import_zod4.z.string().max(2e3).optional(),
1013
- rect: import_zod4.z.object({ x: import_zod4.z.number(), y: import_zod4.z.number(), width: import_zod4.z.number(), height: import_zod4.z.number() }).optional()
1244
+ rect: import_zod4.z.object({ x: import_zod4.z.number(), y: import_zod4.z.number(), width: import_zod4.z.number(), height: import_zod4.z.number() }).optional(),
1245
+ /** Compact snapshot of the picked element (tag mode: feature rules are proposed from it). */
1246
+ elementSnapshot: import_zod4.z.record(import_zod4.z.unknown()).optional()
1014
1247
  });
1015
1248
  var PublishedGuideSchema = import_zod4.z.object({
1016
1249
  id: import_zod4.z.string(),
@@ -1088,22 +1321,153 @@ var FileComplaintSchema = import_zod6.z.object({
1088
1321
  }).optional().nullable()
1089
1322
  });
1090
1323
 
1091
- // src/capture.ts
1324
+ // src/agents.ts
1092
1325
  var import_zod7 = require("zod");
1093
- var AutocaptureSettingsSchema = import_zod7.z.object({ pageviews: import_zod7.z.boolean(), pageLeave: import_zod7.z.boolean(), clicks: import_zod7.z.boolean(), rageClicks: import_zod7.z.boolean(), heatmaps: import_zod7.z.boolean(), mouseMovement: import_zod7.z.boolean() }).partial();
1094
- var ErrorTrackingSettingsSchema = import_zod7.z.object({ enabled: import_zod7.z.boolean() }).partial();
1095
- var ReplaySettingsSchema = import_zod7.z.object({
1096
- enabled: import_zod7.z.boolean(),
1097
- sampleRate: import_zod7.z.number().int().min(0).max(100),
1098
- recordConsole: import_zod7.z.boolean(),
1099
- recordNetwork: import_zod7.z.boolean(),
1100
- recordNetworkPayloads: import_zod7.z.boolean(),
1101
- maskAllText: import_zod7.z.boolean(),
1102
- blockSelectors: import_zod7.z.array(import_zod7.z.string().min(1).max(200)).max(50),
1103
- retentionDays: import_zod7.z.number().int().min(1).max(365)
1326
+
1327
+ // src/agents-limits.ts
1328
+ var AGENT_TURN_ROLES = ["user", "assistant", "tool", "system"];
1329
+ var AGENT_OUTCOMES = ["success", "failure", "escalated", "abandoned"];
1330
+ var AGENT_TOOL_STATUSES = ["ok", "error"];
1331
+ var AGENT_TURN_MAX_TEXT = 2e4;
1332
+ var AGENT_TURNS_PER_BATCH = 100;
1333
+ var AGENT_TOOL_CALLS_PER_TURN = 50;
1334
+ var AGENT_METADATA_MAX_KEYS = 30;
1335
+ var AGENT_METADATA_MAX_BYTES = 4096;
1336
+ var SCOUT_AGENT_ID = "scout";
1337
+
1338
+ // src/agents.ts
1339
+ var ENVIRONMENTS = ["development", "staging", "production"];
1340
+ var AgentToolCallSchema = import_zod7.z.object({
1341
+ name: import_zod7.z.string().trim().min(1).max(100),
1342
+ status: import_zod7.z.enum(AGENT_TOOL_STATUSES).optional(),
1343
+ latencyMs: import_zod7.z.number().int().min(0).max(36e5).optional()
1344
+ }).strip();
1345
+ var AgentMetadataSchema = import_zod7.z.record(import_zod7.z.string().max(100), import_zod7.z.unknown()).transform((m) => {
1346
+ const out = {};
1347
+ let size = 0;
1348
+ for (const [k, v] of Object.entries(m)) {
1349
+ const key = k.trim();
1350
+ if (!key || key.startsWith("$") || SENSITIVE_PROPERTY_PATTERN.test(key)) continue;
1351
+ if (!(typeof v === "string" || typeof v === "boolean" || v === null || typeof v === "number" && Number.isFinite(v))) continue;
1352
+ const value = typeof v === "string" ? v.slice(0, 500) : v;
1353
+ size += key.length + String(value).length;
1354
+ if (size > AGENT_METADATA_MAX_BYTES || Object.keys(out).length >= AGENT_METADATA_MAX_KEYS) break;
1355
+ out[key] = value;
1356
+ }
1357
+ return out;
1358
+ });
1359
+ var id = (max) => import_zod7.z.string().trim().min(1).max(max);
1360
+ var optionalId = (max) => import_zod7.z.string().trim().max(max).optional().nullable().transform((v) => v || null);
1361
+ var AgentTurnInputSchema = import_zod7.z.object({
1362
+ type: import_zod7.z.literal("agent.conversation").optional(),
1363
+ conversationId: id(128),
1364
+ agentId: id(64).refine((v) => v.toLowerCase() !== SCOUT_AGENT_ID, { message: `"${SCOUT_AGENT_ID}" is reserved for Guidely's built-in Scout agent` }),
1365
+ agentName: import_zod7.z.string().trim().max(100).optional(),
1366
+ turnId: import_zod7.z.string().trim().min(1).max(128).optional(),
1367
+ role: import_zod7.z.enum(AGENT_TURN_ROLES),
1368
+ text: import_zod7.z.string().max(AGENT_TURN_MAX_TEXT).default(""),
1369
+ toolCalls: import_zod7.z.array(AgentToolCallSchema).max(AGENT_TOOL_CALLS_PER_TURN).default([]),
1370
+ latencyMs: import_zod7.z.number().int().min(0).max(36e5).optional(),
1371
+ outcome: import_zod7.z.enum(AGENT_OUTCOMES).optional(),
1372
+ taskSuccess: import_zod7.z.boolean().optional(),
1373
+ occurredAt: import_zod7.z.string().datetime({ offset: true }).optional(),
1374
+ userId: optionalId(256),
1375
+ anonymousId: optionalId(128),
1376
+ accountId: optionalId(256),
1377
+ sessionId: optionalId(128),
1378
+ metadata: AgentMetadataSchema.default({})
1379
+ });
1380
+ var turns = import_zod7.z.array(AgentTurnInputSchema).min(1).max(AGENT_TURNS_PER_BATCH);
1381
+ var sdkInfo = import_zod7.z.object({ name: import_zod7.z.string().max(60), version: import_zod7.z.string().max(30) }).optional();
1382
+ var SdkAgentEventsSchema = import_zod7.z.object({ turns, sdk: sdkInfo });
1383
+ var AgentEventsRequestSchema = import_zod7.z.preprocess(
1384
+ (v) => {
1385
+ if (Array.isArray(v)) return { turns: v };
1386
+ if (v && typeof v === "object" && !("turns" in v)) {
1387
+ const { environment, ...turn } = v;
1388
+ return { turns: [turn], environment };
1389
+ }
1390
+ return v;
1391
+ },
1392
+ import_zod7.z.object({ turns, environment: import_zod7.z.enum(ENVIRONMENTS).default("production"), sdk: sdkInfo })
1393
+ );
1394
+
1395
+ // src/feedback.ts
1396
+ var import_zod8 = require("zod");
1397
+
1398
+ // src/feedback-limits.ts
1399
+ var FEEDBACK_STATUSES = ["new", "under_review", "planned", "in_progress", "released", "declined"];
1400
+ var FEEDBACK_STATUS_LABEL = {
1401
+ new: "New",
1402
+ under_review: "Under review",
1403
+ planned: "Planned",
1404
+ in_progress: "In progress",
1405
+ released: "Released",
1406
+ declined: "Declined"
1407
+ };
1408
+ var FEEDBACK_PRIORITIES = ["nice_to_have", "important", "critical"];
1409
+ var FEEDBACK_PRIORITY_LABEL = { nice_to_have: "Nice to have", important: "Important", critical: "Critical" };
1410
+ var FEEDBACK_PRIORITY_WEIGHT = { nice_to_have: 1, important: 2, critical: 3 };
1411
+ var FEEDBACK_EVENTS = ["request.created", "request.status_changed", "request.voted"];
1412
+ var MAX_FEEDBACK_TITLE = 140;
1413
+ var MAX_FEEDBACK_DESCRIPTION = 4e3;
1414
+ var MAX_FEEDBACK_COMMENT = 2e3;
1415
+ var MAX_FEEDBACK_NOTE = 500;
1416
+ var feedbackReference = (number) => `#${number}`;
1417
+
1418
+ // src/feedback.ts
1419
+ var visitor = {
1420
+ anonymousId: import_zod8.z.string().min(1).max(128),
1421
+ userId: import_zod8.z.string().max(256).optional().nullable()
1422
+ };
1423
+ var FeedbackListRequestSchema = import_zod8.z.object({
1424
+ ...visitor,
1425
+ q: import_zod8.z.string().trim().max(200).optional(),
1426
+ sort: import_zod8.z.enum(["top", "new", "trending"]).default("top"),
1427
+ status: import_zod8.z.enum(FEEDBACK_STATUSES).optional(),
1428
+ /** "open" = not released or declined. */
1429
+ filter: import_zod8.z.enum(["open", "all", "mine", "following"]).default("open"),
1430
+ productArea: import_zod8.z.string().trim().max(60).optional(),
1431
+ page: import_zod8.z.number().int().min(1).max(100).default(1)
1432
+ });
1433
+ var FeedbackVisitorSchema = import_zod8.z.object(visitor);
1434
+ var SubmitFeedbackSchema = import_zod8.z.object({
1435
+ ...visitor,
1436
+ title: import_zod8.z.string().trim().min(3, "Give your idea a short title").max(MAX_FEEDBACK_TITLE),
1437
+ description: import_zod8.z.string().trim().max(MAX_FEEDBACK_DESCRIPTION).default(""),
1438
+ productArea: import_zod8.z.string().trim().max(60).optional().nullable(),
1439
+ priority: import_zod8.z.enum(FEEDBACK_PRIORITIES).default("nice_to_have"),
1440
+ /** Filed from this Scout conversation (Scout offered it). */
1441
+ conversationId: import_zod8.z.string().min(1).max(64).optional().nullable(),
1442
+ pageUrl: import_zod8.z.string().max(2e3).optional()
1443
+ });
1444
+ var FeedbackVoteSchema = import_zod8.z.object({
1445
+ ...visitor,
1446
+ priority: import_zod8.z.enum(FEEDBACK_PRIORITIES).default("nice_to_have"),
1447
+ note: import_zod8.z.string().trim().max(MAX_FEEDBACK_NOTE).optional(),
1448
+ conversationId: import_zod8.z.string().min(1).max(64).optional().nullable()
1449
+ });
1450
+ var FeedbackFollowSchema = import_zod8.z.object({ ...visitor, follow: import_zod8.z.boolean() });
1451
+ var FeedbackCommentSchema = import_zod8.z.object({ ...visitor, body: import_zod8.z.string().trim().min(1).max(MAX_FEEDBACK_COMMENT) });
1452
+ var FeedbackSimilarSchema = import_zod8.z.object({ ...visitor, title: import_zod8.z.string().trim().min(3).max(MAX_FEEDBACK_TITLE) });
1453
+ var FeedbackUpdatesReadSchema = import_zod8.z.object({ ...visitor, ids: import_zod8.z.array(import_zod8.z.string().min(1).max(64)).max(100).optional() });
1454
+
1455
+ // src/capture.ts
1456
+ var import_zod9 = require("zod");
1457
+ var AutocaptureSettingsSchema = import_zod9.z.object({ pageviews: import_zod9.z.boolean(), pageLeave: import_zod9.z.boolean(), clicks: import_zod9.z.boolean(), rageClicks: import_zod9.z.boolean(), heatmaps: import_zod9.z.boolean(), mouseMovement: import_zod9.z.boolean(), appLifecycle: import_zod9.z.boolean() }).partial();
1458
+ var ErrorTrackingSettingsSchema = import_zod9.z.object({ enabled: import_zod9.z.boolean() }).partial();
1459
+ var ReplaySettingsSchema = import_zod9.z.object({
1460
+ enabled: import_zod9.z.boolean(),
1461
+ sampleRate: import_zod9.z.number().int().min(0).max(100),
1462
+ recordConsole: import_zod9.z.boolean(),
1463
+ recordNetwork: import_zod9.z.boolean(),
1464
+ recordNetworkPayloads: import_zod9.z.boolean(),
1465
+ maskAllText: import_zod9.z.boolean(),
1466
+ blockSelectors: import_zod9.z.array(import_zod9.z.string().min(1).max(200)).max(50),
1467
+ retentionDays: import_zod9.z.number().int().min(1).max(365)
1104
1468
  }).partial();
1105
1469
  var DEFAULT_CAPTURE_SETTINGS = {
1106
- autocapture: { pageviews: true, pageLeave: true, clicks: true, rageClicks: true, heatmaps: true, mouseMovement: true },
1470
+ autocapture: { pageviews: true, pageLeave: true, clicks: true, rageClicks: true, heatmaps: true, mouseMovement: true, appLifecycle: true },
1107
1471
  errorTracking: { enabled: true },
1108
1472
  replay: { enabled: false, sampleRate: 100, recordConsole: true, recordNetwork: true, recordNetworkPayloads: false, maskAllText: false, blockSelectors: [], retentionDays: 30 }
1109
1473
  };
@@ -1121,18 +1485,18 @@ function resolveCaptureSettings(settings) {
1121
1485
  };
1122
1486
  }
1123
1487
  var HEATMAP_VIEWPORTS = { mobile: [0, 767], tablet: [768, 1279], desktop: [1280, 1e5] };
1124
- var ReplayChunkSchema = import_zod7.z.object({
1125
- sessionId: import_zod7.z.string().min(1).max(128),
1126
- windowId: import_zod7.z.string().min(1).max(64),
1127
- seq: import_zod7.z.number().int().min(0).max(1e6),
1128
- anonymousId: import_zod7.z.string().min(1).max(128),
1129
- userId: import_zod7.z.string().max(256).optional().nullable(),
1488
+ var ReplayChunkSchema = import_zod9.z.object({
1489
+ sessionId: import_zod9.z.string().min(1).max(128),
1490
+ windowId: import_zod9.z.string().min(1).max(64),
1491
+ seq: import_zod9.z.number().int().min(0).max(1e6),
1492
+ anonymousId: import_zod9.z.string().min(1).max(128),
1493
+ userId: import_zod9.z.string().max(256).optional().nullable(),
1130
1494
  /** rrweb `eventWithTime` objects, in order. */
1131
- events: import_zod7.z.array(import_zod7.z.object({ type: import_zod7.z.number().int(), timestamp: import_zod7.z.number() }).passthrough()).min(1).max(5e4),
1132
- url: import_zod7.z.string().max(2e3).optional(),
1133
- device: import_zod7.z.object({ type: import_zod7.z.string().max(20), browser: import_zod7.z.string().max(40).optional(), os: import_zod7.z.string().max(40).optional() }).optional(),
1134
- viewport: import_zod7.z.object({ width: import_zod7.z.number().int().min(0).max(1e5), height: import_zod7.z.number().int().min(0).max(1e5) }).optional(),
1135
- sdk: import_zod7.z.object({ name: import_zod7.z.string().max(60), version: import_zod7.z.string().max(30) }).optional()
1495
+ events: import_zod9.z.array(import_zod9.z.object({ type: import_zod9.z.number().int(), timestamp: import_zod9.z.number() }).passthrough()).min(1).max(5e4),
1496
+ url: import_zod9.z.string().max(2e3).optional(),
1497
+ device: import_zod9.z.object({ type: import_zod9.z.string().max(20), browser: import_zod9.z.string().max(40).optional(), os: import_zod9.z.string().max(40).optional() }).optional(),
1498
+ viewport: import_zod9.z.object({ width: import_zod9.z.number().int().min(0).max(1e5), height: import_zod9.z.number().int().min(0).max(1e5) }).optional(),
1499
+ sdk: import_zod9.z.object({ name: import_zod9.z.string().max(60), version: import_zod9.z.string().max(30) }).optional()
1136
1500
  });
1137
1501
  var REPLAY_MAX_COMPRESSED_BYTES = 2 * 1024 * 1024;
1138
1502
  var REPLAY_MAX_RAW_BYTES = 16 * 1024 * 1024;
@@ -1316,8 +1680,8 @@ var GUIDE_TEMPLATES = [
1316
1680
  }
1317
1681
  }
1318
1682
  ];
1319
- function templateConfig(id) {
1320
- const t = GUIDE_TEMPLATES.find((x) => x.id === id);
1683
+ function templateConfig(id2) {
1684
+ const t = GUIDE_TEMPLATES.find((x) => x.id === id2);
1321
1685
  if (!t) return null;
1322
1686
  return { template: t, config: GuideConfigSchema.parse(t.config) };
1323
1687
  }
@@ -1377,19 +1741,19 @@ function parseStart(v) {
1377
1741
  if (!m || !m[0]) return 0;
1378
1742
  return Math.min(Number(m[1] ?? 0) * 3600 + Number(m[2] ?? 0) * 60 + Number(m[3] ?? 0), 86400);
1379
1743
  }
1380
- function youtube(id, start) {
1381
- if (!YOUTUBE_ID.test(id)) return null;
1744
+ function youtube(id2, start) {
1745
+ if (!YOUTUBE_ID.test(id2)) return null;
1382
1746
  return {
1383
1747
  provider: "youtube",
1384
- src: `https://www.youtube-nocookie.com/embed/${id}${start ? `?start=${start}` : ""}`,
1385
- watchUrl: `https://www.youtube.com/watch?v=${id}${start ? `&t=${start}s` : ""}`,
1748
+ src: `https://www.youtube-nocookie.com/embed/${id2}${start ? `?start=${start}` : ""}`,
1749
+ watchUrl: `https://www.youtube.com/watch?v=${id2}${start ? `&t=${start}s` : ""}`,
1386
1750
  title: "YouTube video"
1387
1751
  };
1388
1752
  }
1389
- function vimeo(id, hash) {
1390
- if (!VIMEO_ID.test(id) || hash !== null && !VIMEO_HASH.test(hash)) return null;
1753
+ function vimeo(id2, hash) {
1754
+ if (!VIMEO_ID.test(id2) || hash !== null && !VIMEO_HASH.test(hash)) return null;
1391
1755
  const h = hash ? hash.toLowerCase() : null;
1392
- return { provider: "vimeo", src: `https://player.vimeo.com/video/${id}${h ? `?h=${h}` : ""}`, watchUrl: `https://vimeo.com/${id}${h ? `/${h}` : ""}`, title: "Vimeo video" };
1756
+ return { provider: "vimeo", src: `https://player.vimeo.com/video/${id2}${h ? `?h=${h}` : ""}`, watchUrl: `https://vimeo.com/${id2}${h ? `/${h}` : ""}`, title: "Vimeo video" };
1393
1757
  }
1394
1758
  function toEmbedUrl(input) {
1395
1759
  const u = parseUrl(input);
@@ -1415,16 +1779,16 @@ function toEmbedUrl(input) {
1415
1779
  return parts[0] === "video" && parts.length === 2 ? vimeo(parts[1], u.searchParams.get("h")) : null;
1416
1780
  case "loom.com":
1417
1781
  if ((parts[0] === "share" || parts[0] === "embed") && parts.length === 2 && LOOM_ID.test(parts[1])) {
1418
- const id = parts[1].toLowerCase();
1419
- return { provider: "loom", src: `https://www.loom.com/embed/${id}`, watchUrl: `https://www.loom.com/share/${id}`, title: "Loom video" };
1782
+ const id2 = parts[1].toLowerCase();
1783
+ return { provider: "loom", src: `https://www.loom.com/embed/${id2}`, watchUrl: `https://www.loom.com/share/${id2}`, title: "Loom video" };
1420
1784
  }
1421
1785
  return null;
1422
1786
  default: {
1423
- let id;
1424
- if (host === "fast.wistia.net" || host === "fast.wistia.com") id = parts[0] === "embed" && parts[1] === "iframe" && parts.length === 3 ? parts[2] : void 0;
1425
- else if (host === "wi.st" || host === "wistia.com" || /^[a-z0-9-]+\.wistia\.com$/.test(host)) id = parts[0] === "medias" && parts.length === 2 ? parts[1] : void 0;
1426
- if (!id || !WISTIA_ID.test(id)) return null;
1427
- return { provider: "wistia", src: `https://fast.wistia.net/embed/iframe/${id}`, watchUrl: `https://fast.wistia.net/embed/iframe/${id}`, title: "Wistia video" };
1787
+ let id2;
1788
+ if (host === "fast.wistia.net" || host === "fast.wistia.com") id2 = parts[0] === "embed" && parts[1] === "iframe" && parts.length === 3 ? parts[2] : void 0;
1789
+ else if (host === "wi.st" || host === "wistia.com" || /^[a-z0-9-]+\.wistia\.com$/.test(host)) id2 = parts[0] === "medias" && parts.length === 2 ? parts[1] : void 0;
1790
+ if (!id2 || !WISTIA_ID.test(id2)) return null;
1791
+ return { provider: "wistia", src: `https://fast.wistia.net/embed/iframe/${id2}`, watchUrl: `https://fast.wistia.net/embed/iframe/${id2}`, title: "Wistia video" };
1428
1792
  }
1429
1793
  }
1430
1794
  }
@@ -1455,7 +1819,7 @@ var MAX_COLLECTION_DEPTH = 3;
1455
1819
  function matchesAudiences(required, member) {
1456
1820
  if (!required || required.length === 0) return true;
1457
1821
  if (!member) return false;
1458
- const has2 = member instanceof Set ? (id) => member.has(id) : (id) => member.includes(id);
1822
+ const has2 = member instanceof Set ? (id2) => member.has(id2) : (id2) => member.includes(id2);
1459
1823
  return required.some(has2);
1460
1824
  }
1461
1825
  function resourceCenterSections(collections, articles, member) {
@@ -1509,7 +1873,7 @@ function servedArticleAudiences(audienceIds, visibility) {
1509
1873
  return visibility === "identified" && audienceIds.length === 0 ? [LOGGED_IN_AUDIENCE] : [...audienceIds];
1510
1874
  }
1511
1875
  function visitorAudiences(audienceIds, identified) {
1512
- const ids = audienceIds.filter((id) => id !== LOGGED_IN_AUDIENCE);
1876
+ const ids = audienceIds.filter((id2) => id2 !== LOGGED_IN_AUDIENCE);
1513
1877
  return identified ? [...ids, LOGGED_IN_AUDIENCE] : ids;
1514
1878
  }
1515
1879
  function visibleArticleIds(collections, articles, member) {
@@ -1545,9 +1909,35 @@ function matchesHelpQuery(text, query) {
1545
1909
  const have = words(hay);
1546
1910
  return terms.every((t) => have.some((w) => w.startsWith(t) || t.length > 3 && t.endsWith("s") && w.startsWith(t.slice(0, -1))));
1547
1911
  }
1912
+ var RC_MODULE_IDS = ["announcements", "search", "checklists", "guides", "articles", "links", "faqs"];
1913
+ var RC_MODULE_LABELS = {
1914
+ announcements: "What's new",
1915
+ search: "Search",
1916
+ checklists: "Checklists",
1917
+ guides: "Guides & tours",
1918
+ articles: "Articles",
1919
+ links: "Links",
1920
+ faqs: "FAQs"
1921
+ };
1922
+ function orderedModules(modules) {
1923
+ const known = (modules ?? []).filter((m, i, all) => RC_MODULE_IDS.includes(m.id) && all.findIndex((x) => x.id === m.id) === i);
1924
+ const missing = RC_MODULE_IDS.filter((id2) => !known.some((m) => m.id === id2)).map((id2) => ({ id: id2, enabled: true }));
1925
+ return [...known, ...missing];
1926
+ }
1927
+ function visibleAnnouncements(items, member, now = Date.now()) {
1928
+ return (items ?? []).filter((a) => {
1929
+ const t = Date.parse(a.publishedAt);
1930
+ return !Number.isNaN(t) && t <= now && matchesAudiences(a.audienceIds, member);
1931
+ }).sort((a, b) => Date.parse(b.publishedAt) - Date.parse(a.publishedAt));
1932
+ }
1933
+ function unreadAnnouncements(items, lastSeenAt) {
1934
+ const seen = lastSeenAt ? Date.parse(lastSeenAt) : NaN;
1935
+ if (Number.isNaN(seen)) return items.length;
1936
+ return items.filter((a) => Date.parse(a.publishedAt) > seen).length;
1937
+ }
1548
1938
 
1549
1939
  // src/howto.ts
1550
- var import_zod8 = require("zod");
1940
+ var import_zod10 = require("zod");
1551
1941
 
1552
1942
  // src/howto-limits.ts
1553
1943
  var CAPTURE_PARAM = "guidely_capture";
@@ -1556,36 +1946,36 @@ var CAPTURE_SCREENSHOT_MAX_BYTES = 8 * 1024 * 1024;
1556
1946
  // src/howto.ts
1557
1947
  var HOWTO_STEP_KINDS = ["action", "text", "heading", "tip", "alert"];
1558
1948
  var HOWTO_ACTIONS = ["click", "type", "select", "navigate"];
1559
- var NormalizedRectSchema = import_zod8.z.object({
1560
- x: import_zod8.z.number().min(0).max(1),
1561
- y: import_zod8.z.number().min(0).max(1),
1562
- width: import_zod8.z.number().min(0).max(1),
1563
- height: import_zod8.z.number().min(0).max(1)
1949
+ var NormalizedRectSchema = import_zod10.z.object({
1950
+ x: import_zod10.z.number().min(0).max(1),
1951
+ y: import_zod10.z.number().min(0).max(1),
1952
+ width: import_zod10.z.number().min(0).max(1),
1953
+ height: import_zod10.z.number().min(0).max(1)
1564
1954
  });
1565
- var CapturedElementSchema = import_zod8.z.object({
1955
+ var CapturedElementSchema = import_zod10.z.object({
1566
1956
  /** Visible name: aria-label, associated label, text, placeholder, alt or title. */
1567
- label: import_zod8.z.string().max(200).default(""),
1957
+ label: import_zod10.z.string().max(200).default(""),
1568
1958
  /** button, link, tab, menuitem, checkbox, radio, field, dropdown, option, element… */
1569
- role: import_zod8.z.string().max(40).default("element"),
1570
- tag: import_zod8.z.string().max(40).default("")
1959
+ role: import_zod10.z.string().max(40).default("element"),
1960
+ tag: import_zod10.z.string().max(40).default("")
1571
1961
  });
1572
- var CaptureStepSchema = import_zod8.z.object({
1962
+ var CaptureStepSchema = import_zod10.z.object({
1573
1963
  /** Random id from the SDK; a retried upload with the same id is stored once. */
1574
- clientId: import_zod8.z.string().min(1).max(64),
1575
- action: import_zod8.z.enum(HOWTO_ACTIONS),
1576
- url: import_zod8.z.string().max(2e3),
1577
- pageTitle: import_zod8.z.string().max(300).default(""),
1964
+ clientId: import_zod10.z.string().min(1).max(64),
1965
+ action: import_zod10.z.enum(HOWTO_ACTIONS),
1966
+ url: import_zod10.z.string().max(2e3),
1967
+ pageTitle: import_zod10.z.string().max(300).default(""),
1578
1968
  element: CapturedElementSchema.optional(),
1579
1969
  /** Typed text or chosen option; absent when it was sensitive (`valueRedacted`). */
1580
- value: import_zod8.z.string().max(200).optional(),
1581
- valueRedacted: import_zod8.z.boolean().default(false),
1970
+ value: import_zod10.z.string().max(200).optional(),
1971
+ valueRedacted: import_zod10.z.boolean().default(false),
1582
1972
  /** Selectors for the element, so the step can later become an interactive tour step. */
1583
- selectors: import_zod8.z.array(SelectorStrategySchema).max(10).default([]),
1973
+ selectors: import_zod10.z.array(SelectorStrategySchema).max(10).default([]),
1584
1974
  /** Where the element sits in the screenshot. */
1585
1975
  highlight: NormalizedRectSchema.optional(),
1586
1976
  /** Number of regions the SDK blurred in the screenshot before upload. */
1587
- redactions: import_zod8.z.number().int().min(0).max(1e3).default(0),
1588
- occurredAt: import_zod8.z.string().datetime().optional()
1977
+ redactions: import_zod10.z.number().int().min(0).max(1e3).default(0),
1978
+ occurredAt: import_zod10.z.string().datetime().optional()
1589
1979
  });
1590
1980
  function quoted(s) {
1591
1981
  const t = (s ?? "").replace(/\s+/g, " ").trim();
@@ -1656,12 +2046,12 @@ function hostAndPath(url) {
1656
2046
  return url.slice(0, 80);
1657
2047
  }
1658
2048
  }
1659
- var NormalizedPointSchema = import_zod8.z.object({ x: import_zod8.z.number().min(0).max(1), y: import_zod8.z.number().min(0).max(1) });
2049
+ var NormalizedPointSchema = import_zod10.z.object({ x: import_zod10.z.number().min(0).max(1), y: import_zod10.z.number().min(0).max(1) });
1660
2050
  var ANNOTATION_COLORS = ["brand", "red", "amber", "green", "black", "white"];
1661
- var HowToAnnotationSchema = import_zod8.z.discriminatedUnion("type", [
1662
- import_zod8.z.object({ id: import_zod8.z.string().min(1).max(32), type: import_zod8.z.literal("arrow"), from: NormalizedPointSchema, to: NormalizedPointSchema, color: import_zod8.z.enum(ANNOTATION_COLORS).default("brand") }),
1663
- import_zod8.z.object({ id: import_zod8.z.string().min(1).max(32), type: import_zod8.z.literal("text"), at: NormalizedPointSchema, text: import_zod8.z.string().trim().min(1).max(120), color: import_zod8.z.enum(ANNOTATION_COLORS).default("brand") }),
1664
- import_zod8.z.object({ id: import_zod8.z.string().min(1).max(32), type: import_zod8.z.literal("box"), rect: NormalizedRectSchema, color: import_zod8.z.enum(ANNOTATION_COLORS).default("brand") })
2051
+ var HowToAnnotationSchema = import_zod10.z.discriminatedUnion("type", [
2052
+ import_zod10.z.object({ id: import_zod10.z.string().min(1).max(32), type: import_zod10.z.literal("arrow"), from: NormalizedPointSchema, to: NormalizedPointSchema, color: import_zod10.z.enum(ANNOTATION_COLORS).default("brand") }),
2053
+ import_zod10.z.object({ id: import_zod10.z.string().min(1).max(32), type: import_zod10.z.literal("text"), at: NormalizedPointSchema, text: import_zod10.z.string().trim().min(1).max(120), color: import_zod10.z.enum(ANNOTATION_COLORS).default("brand") }),
2054
+ import_zod10.z.object({ id: import_zod10.z.string().min(1).max(32), type: import_zod10.z.literal("box"), rect: NormalizedRectSchema, color: import_zod10.z.enum(ANNOTATION_COLORS).default("brand") })
1665
2055
  ]);
1666
2056
  var MAX_ANNOTATIONS = 30;
1667
2057
 
@@ -1689,12 +2079,556 @@ function pageLabel(path) {
1689
2079
  }
1690
2080
  function firstNameFromTraits(traits) {
1691
2081
  if (!traits) return null;
1692
- const pick = (v) => typeof v === "string" ? v.trim() : "";
1693
- const first = pick(traits.firstName) || pick(traits.first_name) || pick(traits.firstname) || pick(traits.name).split(/\s+/)[0] || "";
2082
+ const pick2 = (v) => typeof v === "string" ? v.trim() : "";
2083
+ const first = pick2(traits.firstName) || pick2(traits.first_name) || pick2(traits.firstname) || pick2(traits.name).split(/\s+/)[0] || "";
1694
2084
  if (!first || first.length > 40 || first.includes("@") || !/\p{L}/u.test(first)) return null;
1695
2085
  return first;
1696
2086
  }
1697
2087
 
2088
+ // src/tagging.ts
2089
+ var SNAPSHOT_LIMITS = { classes: 8, className: 60, attrs: 6, attrValue: 100, ancestors: 5, hosts: 3, tag: 40, id: 80 };
2090
+ var SNAPSHOT_ATTRS = ["role", "name", "type", "aria-label", "title", "alt", "for", "href"];
2091
+ 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;
2092
+ var DEFAULT_FEATURE_ATTRIBUTE = "data-guidely-feature";
2093
+ var FEATURE_ATTRIBUTE_PATTERN = /^data-[a-z0-9][a-z0-9_.-]{0,60}$/;
2094
+ function str(v, max) {
2095
+ return typeof v === "string" && v ? v.slice(0, max) : void 0;
2096
+ }
2097
+ function cleanNode(raw) {
2098
+ if (!raw || typeof raw !== "object") return null;
2099
+ const r = raw;
2100
+ const t = str(r.t, SNAPSHOT_LIMITS.tag)?.toLowerCase();
2101
+ if (!t || !/^[a-z][a-z0-9-]*$/.test(t)) return null;
2102
+ const node = { t };
2103
+ const id2 = str(r.id, SNAPSHOT_LIMITS.id);
2104
+ if (id2) node.id = id2;
2105
+ if (Array.isArray(r.c)) {
2106
+ const c = r.c.filter((x) => typeof x === "string" && !!x && x.length <= SNAPSHOT_LIMITS.className && !/\s/.test(x)).slice(0, SNAPSHOT_LIMITS.classes);
2107
+ if (c.length) node.c = c;
2108
+ }
2109
+ if (r.a && typeof r.a === "object" && !Array.isArray(r.a)) {
2110
+ const a = {};
2111
+ for (const [k, v] of Object.entries(r.a)) {
2112
+ if (Object.keys(a).length >= SNAPSHOT_LIMITS.attrs) break;
2113
+ const key = k.toLowerCase();
2114
+ if (typeof v !== "string" || !(key.startsWith("data-") || SNAPSHOT_ATTRS.includes(key)) || key === "value" || key.length > 60) continue;
2115
+ a[key] = v.slice(0, SNAPSHOT_LIMITS.attrValue);
2116
+ }
2117
+ if (Object.keys(a).length) node.a = a;
2118
+ }
2119
+ if (typeof r.n === "number" && Number.isInteger(r.n) && r.n >= 1 && r.n <= 1e4) node.n = r.n;
2120
+ return node;
2121
+ }
2122
+ function normalizeSnapshot(raw) {
2123
+ const el = cleanNode(raw);
2124
+ if (!el) return null;
2125
+ const r = raw;
2126
+ const out = el;
2127
+ if (Array.isArray(r.p)) {
2128
+ const p = r.p.slice(0, SNAPSHOT_LIMITS.ancestors).map(cleanNode);
2129
+ const cut = p.indexOf(null);
2130
+ const list = cut === -1 ? p : p.slice(0, cut);
2131
+ if (list.length) out.p = list;
2132
+ }
2133
+ if (Array.isArray(r.h)) {
2134
+ const h = r.h.slice(0, SNAPSHOT_LIMITS.hosts).map(cleanNode).filter((x) => !!x);
2135
+ if (h.length) out.h = h;
2136
+ }
2137
+ return out;
2138
+ }
2139
+ function stableStringify(v) {
2140
+ if (Array.isArray(v)) return `[${v.map(stableStringify).join(",")}]`;
2141
+ if (v && typeof v === "object") {
2142
+ const o = v;
2143
+ return `{${Object.keys(o).filter((k) => o[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(o[k])}`).join(",")}}`;
2144
+ }
2145
+ return JSON.stringify(v ?? null);
2146
+ }
2147
+ var SelectorSyntaxError = class extends Error {
2148
+ };
2149
+ var IDENT_START = /[A-Za-z_\u00a0-\uffff-]/;
2150
+ var IDENT_CHAR = /[A-Za-z0-9_\u00a0-\uffff-]/;
2151
+ function parseCssSelector(input) {
2152
+ const s = input.trim();
2153
+ if (!s) throw new SelectorSyntaxError("Empty selector");
2154
+ if (s.length > 1e3) throw new SelectorSyntaxError("Selector is too long");
2155
+ let i = 0;
2156
+ const peek = () => s[i];
2157
+ const eof = () => i >= s.length;
2158
+ const fail = (msg) => {
2159
+ throw new SelectorSyntaxError(`${msg} at position ${i + 1}`);
2160
+ };
2161
+ const ws = () => {
2162
+ let any = false;
2163
+ while (!eof() && /\s/.test(s[i])) {
2164
+ i++;
2165
+ any = true;
2166
+ }
2167
+ return any;
2168
+ };
2169
+ const escape = () => {
2170
+ i++;
2171
+ const hex = /^[0-9a-fA-F]{1,6}/.exec(s.slice(i));
2172
+ if (hex) {
2173
+ i += hex[0].length;
2174
+ if (s[i] === " ") i++;
2175
+ return String.fromCodePoint(parseInt(hex[0], 16));
2176
+ }
2177
+ if (eof()) fail("Unfinished escape");
2178
+ return s[i++];
2179
+ };
2180
+ const ident = () => {
2181
+ let out = "";
2182
+ if (s[i] === "\\") out += escape();
2183
+ else if (!eof() && IDENT_START.test(s[i])) out += s[i++];
2184
+ else fail("Expected a name");
2185
+ while (!eof()) {
2186
+ if (s[i] === "\\") out += escape();
2187
+ else if (IDENT_CHAR.test(s[i])) out += s[i++];
2188
+ else break;
2189
+ }
2190
+ return out;
2191
+ };
2192
+ const quoted2 = () => {
2193
+ const q = s[i++];
2194
+ let out = "";
2195
+ while (!eof() && s[i] !== q) {
2196
+ if (s[i] === "\\") out += escape();
2197
+ else out += s[i++];
2198
+ }
2199
+ if (eof()) fail("Unterminated string");
2200
+ i++;
2201
+ return out;
2202
+ };
2203
+ const compound = () => {
2204
+ const c = { classes: [], attrs: [] };
2205
+ let any = false;
2206
+ if (peek() === "*") {
2207
+ i++;
2208
+ any = true;
2209
+ } else if (!eof() && (IDENT_START.test(peek()) || peek() === "\\")) {
2210
+ c.tag = ident().toLowerCase();
2211
+ any = true;
2212
+ }
2213
+ for (; ; ) {
2214
+ const ch = peek();
2215
+ if (ch === "#") {
2216
+ i++;
2217
+ c.id = ident();
2218
+ } else if (ch === ".") {
2219
+ i++;
2220
+ c.classes.push(ident());
2221
+ } else if (ch === "[") {
2222
+ i++;
2223
+ ws();
2224
+ const name = ident().toLowerCase();
2225
+ ws();
2226
+ let op = "exists";
2227
+ let value;
2228
+ let insensitive = false;
2229
+ if (peek() !== "]") {
2230
+ const m = /^(=|\^=|\$=|\*=|~=|\|=)/.exec(s.slice(i));
2231
+ if (!m) fail("Unsupported attribute operator");
2232
+ op = m[1];
2233
+ i += m[1].length;
2234
+ ws();
2235
+ value = peek() === '"' || peek() === "'" ? quoted2() : ident();
2236
+ ws();
2237
+ if (peek() === "i" || peek() === "I") {
2238
+ i++;
2239
+ insensitive = true;
2240
+ ws();
2241
+ } else if (peek() === "s" || peek() === "S") {
2242
+ i++;
2243
+ ws();
2244
+ }
2245
+ }
2246
+ if (peek() !== "]") fail("Expected ]");
2247
+ i++;
2248
+ c.attrs.push({ name, op, ...value !== void 0 ? { value } : {}, ...insensitive ? { insensitive } : {} });
2249
+ } else if (ch === ":") {
2250
+ i++;
2251
+ if (peek() === ":") fail("Pseudo-elements are not supported");
2252
+ const name = ident().toLowerCase();
2253
+ if (name === "first-of-type") c.nth = { a: 0, b: 1 };
2254
+ else if (name === "nth-of-type") {
2255
+ if (peek() !== "(") fail("Expected (");
2256
+ i++;
2257
+ ws();
2258
+ const m = /^(odd|even|\d+)/i.exec(s.slice(i));
2259
+ if (!m) fail("Only :nth-of-type(n), odd or even are supported");
2260
+ i += m[0].length;
2261
+ ws();
2262
+ if (peek() !== ")") fail("Expected )");
2263
+ i++;
2264
+ const v = m[0].toLowerCase();
2265
+ c.nth = v === "odd" ? { a: 2, b: 1 } : v === "even" ? { a: 2, b: 0 } : { a: 0, b: Number(v) };
2266
+ } else fail(`Unsupported pseudo-class :${name}`);
2267
+ } else break;
2268
+ any = true;
2269
+ }
2270
+ return any ? c : null;
2271
+ };
2272
+ const list = [];
2273
+ for (; ; ) {
2274
+ ws();
2275
+ const sel = { compounds: [], combinators: [] };
2276
+ const first = compound();
2277
+ if (!first) fail("Expected a selector");
2278
+ sel.compounds.push(first);
2279
+ for (; ; ) {
2280
+ const hadWs = ws();
2281
+ if (eof() || peek() === ",") break;
2282
+ let comb = " ";
2283
+ if (s.startsWith(">>>", i)) {
2284
+ comb = ">>>";
2285
+ i += 3;
2286
+ ws();
2287
+ } else if (peek() === ">") {
2288
+ comb = ">";
2289
+ i++;
2290
+ ws();
2291
+ } else if (peek() === "+" || peek() === "~") fail("Sibling combinators are not supported");
2292
+ else if (!hadWs) fail("Unexpected character");
2293
+ const next = compound();
2294
+ if (!next) fail("Expected a selector after the combinator");
2295
+ sel.compounds.push(next);
2296
+ sel.combinators.push(comb);
2297
+ }
2298
+ list.push(sel);
2299
+ if (eof()) break;
2300
+ i++;
2301
+ }
2302
+ return list;
2303
+ }
2304
+ function cssSelectorError(selector) {
2305
+ try {
2306
+ parseCssSelector(selector);
2307
+ return null;
2308
+ } catch (e) {
2309
+ return e instanceof Error ? e.message : "Invalid selector";
2310
+ }
2311
+ }
2312
+ function attrMatches(test, node) {
2313
+ let actual;
2314
+ if (test.name === "id") actual = node.id;
2315
+ else if (test.name === "class") actual = node.c?.join(" ");
2316
+ else actual = node.a?.[test.name];
2317
+ if (actual === void 0) return false;
2318
+ if (test.op === "exists") return true;
2319
+ let v = test.value ?? "";
2320
+ if (test.insensitive) {
2321
+ actual = actual.toLowerCase();
2322
+ v = v.toLowerCase();
2323
+ }
2324
+ switch (test.op) {
2325
+ case "=":
2326
+ return actual === v;
2327
+ case "^=":
2328
+ return !!v && actual.startsWith(v);
2329
+ case "$=":
2330
+ return !!v && actual.endsWith(v);
2331
+ case "*=":
2332
+ return !!v && actual.includes(v);
2333
+ case "~=":
2334
+ return !!v && actual.split(/\s+/).includes(v);
2335
+ case "|=":
2336
+ return actual === v || actual.startsWith(`${v}-`);
2337
+ default:
2338
+ return false;
2339
+ }
2340
+ }
2341
+ function compoundMatches(c, node) {
2342
+ if (c.tag && c.tag !== node.t) return false;
2343
+ if (c.id !== void 0 && node.id !== c.id) return false;
2344
+ for (const cls of c.classes) if (!node.c?.includes(cls)) return false;
2345
+ for (const a of c.attrs) if (!attrMatches(a, node)) return false;
2346
+ if (c.nth) {
2347
+ if (!node.n) return false;
2348
+ const { a, b } = c.nth;
2349
+ if (a === 0 ? node.n !== b : (node.n - b) % a !== 0 || (node.n - b) / a < 0) return false;
2350
+ }
2351
+ return true;
2352
+ }
2353
+ function chainMatches(compounds, combinators, nodes, ci = compounds.length - 1, ni = 0) {
2354
+ if (!compoundMatches(compounds[ci], nodes[ni])) return false;
2355
+ if (ci === 0) return true;
2356
+ const comb = combinators[ci - 1];
2357
+ if (comb === ">") return ni + 1 < nodes.length && chainMatches(compounds, combinators, nodes, ci - 1, ni + 1);
2358
+ for (let k = ni + 1; k < nodes.length; k++) if (chainMatches(compounds, combinators, nodes, ci - 1, k)) return true;
2359
+ return false;
2360
+ }
2361
+ function complexMatches(sel, snap) {
2362
+ const segments = [{ compounds: [sel.compounds[0]], combinators: [] }];
2363
+ sel.combinators.forEach((comb, k) => {
2364
+ const next = sel.compounds[k + 1];
2365
+ if (comb === ">>>") segments.push({ compounds: [next], combinators: [] });
2366
+ else {
2367
+ const seg = segments[segments.length - 1];
2368
+ seg.compounds.push(next);
2369
+ seg.combinators.push(comb);
2370
+ }
2371
+ });
2372
+ const last = segments.pop();
2373
+ const nodes = [snap, ...snap.p ?? []];
2374
+ if (!chainMatches(last.compounds, last.combinators, nodes)) return false;
2375
+ const hosts = snap.h ?? [];
2376
+ let from = 0;
2377
+ for (let k = segments.length - 1; k >= 0; k--) {
2378
+ const target = segments[k].compounds[segments[k].compounds.length - 1];
2379
+ let found = -1;
2380
+ for (let j = from; j < hosts.length; j++) {
2381
+ if (compoundMatches(target, hosts[j])) {
2382
+ found = j;
2383
+ break;
2384
+ }
2385
+ }
2386
+ if (found === -1) return false;
2387
+ from = found + 1;
2388
+ }
2389
+ return true;
2390
+ }
2391
+ var parsedCache = /* @__PURE__ */ new Map();
2392
+ function matchCssSelector(selector, snap) {
2393
+ let list;
2394
+ if (typeof selector === "string") {
2395
+ if (!parsedCache.has(selector)) {
2396
+ if (parsedCache.size > 500) parsedCache.clear();
2397
+ try {
2398
+ parsedCache.set(selector, parseCssSelector(selector));
2399
+ } catch {
2400
+ parsedCache.set(selector, null);
2401
+ }
2402
+ }
2403
+ list = parsedCache.get(selector);
2404
+ } else list = selector;
2405
+ return !!list && list.some((sel) => complexMatches(sel, snap));
2406
+ }
2407
+ function nodeOfCompound(c) {
2408
+ const node = { t: c.tag ?? "*" };
2409
+ if (c.id) node.id = c.id;
2410
+ if (c.classes.length) node.c = c.classes.slice(0, SNAPSHOT_LIMITS.classes);
2411
+ const a = {};
2412
+ for (const t of c.attrs) if (t.op === "=" && t.value !== void 0) a[t.name] = t.value;
2413
+ if (Object.keys(a).length) node.a = a;
2414
+ if (c.nth && c.nth.a === 0) node.n = c.nth.b;
2415
+ return node;
2416
+ }
2417
+ function snapshotFromSelector(selector, tag) {
2418
+ let list;
2419
+ try {
2420
+ list = parseCssSelector(selector);
2421
+ } catch {
2422
+ return null;
2423
+ }
2424
+ if (list.length !== 1) return null;
2425
+ const sel = list[0];
2426
+ const segments = [[sel.compounds[0]]];
2427
+ sel.combinators.forEach((comb, k) => {
2428
+ if (comb === ">>>") segments.push([sel.compounds[k + 1]]);
2429
+ else segments[segments.length - 1].push(sel.compounds[k + 1]);
2430
+ });
2431
+ const own = segments.pop();
2432
+ const el = nodeOfCompound(own[own.length - 1]);
2433
+ if (el.t === "*" && tag && /^[a-z][a-z0-9-]*$/i.test(tag)) el.t = tag.toLowerCase();
2434
+ const snap = el;
2435
+ const p = own.slice(0, -1).reverse().map(nodeOfCompound);
2436
+ if (p.length) snap.p = p.slice(0, SNAPSHOT_LIMITS.ancestors);
2437
+ const h = segments.reverse().map((seg) => nodeOfCompound(seg[seg.length - 1]));
2438
+ if (h.length) snap.h = h.slice(0, SNAPSHOT_LIMITS.hosts);
2439
+ return snap;
2440
+ }
2441
+ var PAGE_RULE_LIMITS = { rules: 20, value: 500, query: 5 };
2442
+ var escapeRe = (s) => s.replace(/[.+?^${}()|[\]\\*]/g, "\\$&");
2443
+ function globToRegex(pattern) {
2444
+ let out = "";
2445
+ for (let k = 0; k < pattern.length; k++) {
2446
+ const ch = pattern[k];
2447
+ if (ch === "*") {
2448
+ if (pattern[k + 1] === "*") {
2449
+ out += ".*";
2450
+ k++;
2451
+ } else out += "[^/]*";
2452
+ } else if (ch === ":" && (k === 0 || pattern[k - 1] === "/") && /[A-Za-z_]/.test(pattern[k + 1] ?? "")) {
2453
+ let j = k + 1;
2454
+ while (j < pattern.length && /[\w]/.test(pattern[j])) j++;
2455
+ out += "[^/]+";
2456
+ k = j - 1;
2457
+ } else out += escapeRe(ch);
2458
+ }
2459
+ return out;
2460
+ }
2461
+ function pagePattern(raw) {
2462
+ let p = raw.trim();
2463
+ const query = [];
2464
+ const hash = p.indexOf("#");
2465
+ if (hash !== -1) p = p.slice(0, hash);
2466
+ const q = p.indexOf("?");
2467
+ if (q !== -1) {
2468
+ for (const part of p.slice(q + 1).split("&")) {
2469
+ if (!part) continue;
2470
+ const eq = part.indexOf("=");
2471
+ const name = decodeSafe(eq === -1 ? part : part.slice(0, eq));
2472
+ const value = eq === -1 ? void 0 : decodeSafe(part.slice(eq + 1));
2473
+ if (!name) continue;
2474
+ query.push(value === void 0 || value === "*" ? { name, op: "exists" } : { name, op: "equals", value });
2475
+ }
2476
+ p = p.slice(0, q);
2477
+ }
2478
+ let target = "path";
2479
+ if (p.startsWith("//*")) p = p.slice(3);
2480
+ let prefix = "";
2481
+ const abs = /^(https?:)?\/\/([^/]+)(.*)$/i.exec(p);
2482
+ if (abs) {
2483
+ target = "url";
2484
+ prefix = `https?://${globToRegex(abs[2].toLowerCase())}`;
2485
+ p = abs[3] || "/";
2486
+ }
2487
+ if (!p.startsWith("/")) p = `/${p}`;
2488
+ const body = p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
2489
+ const src = body === "/" ? "/?" : `${globToRegex(body)}/?`;
2490
+ return { source: `^${prefix}${src}$`, target, query: query.slice(0, PAGE_RULE_LIMITS.query) };
2491
+ }
2492
+ function decodeSafe(s) {
2493
+ try {
2494
+ return decodeURIComponent(s.replace(/\+/g, " "));
2495
+ } catch {
2496
+ return s;
2497
+ }
2498
+ }
2499
+ function queryConditionRegex(c) {
2500
+ const name = escapeRe(c.name);
2501
+ switch (c.op) {
2502
+ case "equals":
2503
+ return `[?&]${name}=${escapeRe(encodeLoose(c.value ?? ""))}(&|#|$)`;
2504
+ case "contains":
2505
+ return `[?&]${name}=[^&#]*${escapeRe(encodeLoose(c.value ?? ""))}`;
2506
+ default:
2507
+ return `[?&]${name}(=|&|#|$)`;
2508
+ }
2509
+ }
2510
+ function encodeLoose(v) {
2511
+ return encodeURIComponent(v).replace(/%2F/gi, "/").replace(/%3A/gi, ":").replace(/%2C/gi, ",").replace(/%40/gi, "@");
2512
+ }
2513
+ function pathOnly(ctx) {
2514
+ if (ctx.path) return ctx.path.split("?")[0] || "/";
2515
+ if (!ctx.url) return null;
2516
+ try {
2517
+ return new URL(ctx.url, "http://x.invalid").pathname;
2518
+ } catch {
2519
+ return null;
2520
+ }
2521
+ }
2522
+ function regexOrNull(source) {
2523
+ try {
2524
+ return new RegExp(source, "i");
2525
+ } catch {
2526
+ return null;
2527
+ }
2528
+ }
2529
+ function pageRuleMatches(rule, ctx) {
2530
+ const path = pathOnly(ctx);
2531
+ if (rule.type === "title") {
2532
+ const t = (ctx.title ?? "").toLowerCase();
2533
+ const v = rule.value.toLowerCase();
2534
+ return !!t && (rule.op === "contains" ? t.includes(v) : t === v);
2535
+ }
2536
+ if (rule.type === "regex") {
2537
+ const re2 = regexOrNull(rule.value);
2538
+ return !!re2 && path !== null && re2.test(path);
2539
+ }
2540
+ const pat = pagePattern(rule.value);
2541
+ const re = regexOrNull(pat.source);
2542
+ if (!re) return false;
2543
+ let subject = path;
2544
+ if (pat.target === "url") {
2545
+ if (!ctx.url) return false;
2546
+ subject = ctx.url.split(/[?#]/)[0];
2547
+ }
2548
+ if (subject === null || !re.test(subject)) return false;
2549
+ const conds = [...pat.query, ...rule.query ?? []];
2550
+ for (const c of conds) {
2551
+ const hit = !!ctx.url && new RegExp(queryConditionRegex(c), "i").test(ctx.url);
2552
+ if (c.op === "absent" ? hit : !hit) return false;
2553
+ }
2554
+ return true;
2555
+ }
2556
+ function pageRulesMatch(rules, ctx) {
2557
+ const include = rules.filter((r) => !r.exclude);
2558
+ if (!include.length || !include.some((r) => pageRuleMatches(r, ctx))) return false;
2559
+ return !rules.some((r) => r.exclude && pageRuleMatches(r, ctx));
2560
+ }
2561
+ function pageRuleError(rule) {
2562
+ const v = rule.value?.trim();
2563
+ if (!v) return "A rule needs a value";
2564
+ if (v.length > PAGE_RULE_LIMITS.value) return "The rule is too long";
2565
+ if (rule.type === "regex") {
2566
+ if (!regexOrNull(v)) return `"${v}" is not a valid regular expression`;
2567
+ if (/\(\?[<=!]/.test(v) || /\\[1-9]/.test(v)) return "Look-arounds and back-references are not supported";
2568
+ }
2569
+ if (rule.type === "url" && !regexOrNull(pagePattern(v).source)) return `"${v}" is not a valid URL rule`;
2570
+ 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`;
2571
+ return null;
2572
+ }
2573
+ var FEATURE_RULE_LIMITS = { rules: 20, value: 1e3 };
2574
+ function globMatch(pattern, value) {
2575
+ const re = new RegExp(`^${pattern.split("*").map(escapeRe).join(".*")}$`, "s");
2576
+ return re.test(value);
2577
+ }
2578
+ function featureRuleMatchesClick(rule, click, css) {
2579
+ if (!rule.selector && !rule.text && !rule.tag && !rule.href) return false;
2580
+ if (rule.selector) {
2581
+ const sel = click.selector ?? "";
2582
+ const v = rule.selector.value;
2583
+ 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);
2584
+ if (!ok) return false;
2585
+ }
2586
+ if (rule.text) {
2587
+ const t = (click.text ?? "").toLowerCase();
2588
+ const v = rule.text.value.toLowerCase();
2589
+ if (rule.text.op === "contains" ? !t.includes(v) : t !== v) return false;
2590
+ }
2591
+ if (rule.tag && (click.tag ?? "").toLowerCase() !== rule.tag.toLowerCase()) return false;
2592
+ if (rule.href) {
2593
+ const h = click.href ?? "";
2594
+ const v = rule.href.value;
2595
+ if (rule.href.op === "equals" ? h !== v : rule.href.op === "prefix" ? !h.startsWith(v) : !h.includes(v)) return false;
2596
+ }
2597
+ if (rule.platform && (click.platform ?? "web") !== rule.platform) return false;
2598
+ return true;
2599
+ }
2600
+ function featureRuleError(rule) {
2601
+ if (!rule.selector && !rule.text && !rule.tag && !rule.href) return "A feature rule needs a selector, text, tag or link condition";
2602
+ if (rule.selector) {
2603
+ const v = rule.selector.value?.trim();
2604
+ if (!v) return "The selector is empty";
2605
+ if (v.length > FEATURE_RULE_LIMITS.value) return "The selector is too long";
2606
+ if (rule.selector.op === "css") {
2607
+ const err = cssSelectorError(v);
2608
+ if (err) return `Unsupported CSS selector: ${err}`;
2609
+ }
2610
+ }
2611
+ if (rule.text && !rule.text.value.trim()) return "The text condition is empty";
2612
+ if (rule.href && !rule.href.value.trim()) return "The link condition is empty";
2613
+ if (rule.tag && !/^[a-z][a-z0-9-]{0,40}$/i.test(rule.tag)) return "The tag is not an element name";
2614
+ if (rule.page?.pattern) return pageRuleError({ type: "url", value: rule.page.pattern });
2615
+ return null;
2616
+ }
2617
+ function featureCssSelectors(rules) {
2618
+ const out = [];
2619
+ for (const r of rules) {
2620
+ if (r.exclude || !r.selector) continue;
2621
+ if ((r.selector.op === "css" || r.selector.op === "exact") && !cssSelectorError(r.selector.value)) out.push(r.selector.value);
2622
+ }
2623
+ return out;
2624
+ }
2625
+ var TAG_PROPERTY_LIMITS = { perTag: 10, total: 50, value: 100 };
2626
+ function propertyAttributeAllowed(name) {
2627
+ const n = name.toLowerCase();
2628
+ if (n === "value" || n.startsWith("on") || n === "style" || n === "srcdoc") return false;
2629
+ return /^[a-z][a-z0-9_:.-]{0,60}$/.test(n);
2630
+ }
2631
+
1698
2632
  // src/snippet.ts
1699
2633
  var SCRIPT_STUB_METHODS = [
1700
2634
  "identify",
@@ -1704,6 +2638,7 @@ var SCRIPT_STUB_METHODS = [
1704
2638
  "setAccount",
1705
2639
  "updateTraits",
1706
2640
  "setConsent",
2641
+ "setLocale",
1707
2642
  "startGuide",
1708
2643
  "stopGuide",
1709
2644
  "dismissGuide",
@@ -1716,7 +2651,10 @@ var SCRIPT_STUB_METHODS = [
1716
2651
  "closeChecklist",
1717
2652
  "completeChecklistTask",
1718
2653
  "openComplaint",
2654
+ "openIdeas",
1719
2655
  "captureException",
2656
+ "agentConversation",
2657
+ "trackAgentTurn",
1720
2658
  "on"
1721
2659
  ];
1722
2660
  var SCRIPT_STUB = `!function(w){if(w.Guidely)return;var g=w.Guidely={_q:[]},c=g._c={};function q(o,k){o[k]=function(){g._q.push([o===c?1:0,k,[].slice.call(arguments)])}}q(g,"init");"${SCRIPT_STUB_METHODS.join(" ")}".split(" ").forEach(function(k){q(c,k)});c.isFeatureEnabled=function(k,f){return!!f};c.getFeatureValue=function(k,f){return f};g.get=function(){return c}}(window);`;
@@ -1728,15 +2666,544 @@ function scriptSnippet(scriptUrl, initOptions) {
1728
2666
  <script src="${scriptUrl}" async></script>`;
1729
2667
  }
1730
2668
 
2669
+ // src/localization.ts
2670
+ function needsReview(state) {
2671
+ return !!state && (state.origin === "machine" && !state.approved || state.outdated);
2672
+ }
2673
+ var DEFAULT_LOCALE = "en";
2674
+ var COMMON_LOCALES = [
2675
+ { code: "en", name: "English" },
2676
+ { code: "en-GB", name: "English (UK)" },
2677
+ { code: "fr", name: "French" },
2678
+ { code: "fr-CA", name: "French (Canada)" },
2679
+ { code: "de", name: "German" },
2680
+ { code: "es", name: "Spanish" },
2681
+ { code: "es-MX", name: "Spanish (Mexico)" },
2682
+ { code: "it", name: "Italian" },
2683
+ { code: "pt", name: "Portuguese" },
2684
+ { code: "pt-BR", name: "Portuguese (Brazil)" },
2685
+ { code: "nl", name: "Dutch" },
2686
+ { code: "sv", name: "Swedish" },
2687
+ { code: "da", name: "Danish" },
2688
+ { code: "nb", name: "Norwegian" },
2689
+ { code: "fi", name: "Finnish" },
2690
+ { code: "pl", name: "Polish" },
2691
+ { code: "cs", name: "Czech" },
2692
+ { code: "tr", name: "Turkish" },
2693
+ { code: "ru", name: "Russian" },
2694
+ { code: "uk", name: "Ukrainian" },
2695
+ { code: "ar", name: "Arabic" },
2696
+ { code: "he", name: "Hebrew" },
2697
+ { code: "hi", name: "Hindi" },
2698
+ { code: "ja", name: "Japanese" },
2699
+ { code: "ko", name: "Korean" },
2700
+ { code: "zh-Hans", name: "Chinese (Simplified)" },
2701
+ { code: "zh-Hant", name: "Chinese (Traditional)" },
2702
+ { code: "id", name: "Indonesian" },
2703
+ { code: "th", name: "Thai" },
2704
+ { code: "vi", name: "Vietnamese" }
2705
+ ];
2706
+ function localeName(code) {
2707
+ const exact = COMMON_LOCALES.find((l) => l.code.toLowerCase() === code.toLowerCase());
2708
+ if (exact) return exact.name;
2709
+ const base = COMMON_LOCALES.find((l) => l.code.toLowerCase() === baseLanguage(code));
2710
+ return base ? `${base.name} (${code})` : code;
2711
+ }
2712
+ function normalizeLocale(input) {
2713
+ if (typeof input !== "string") return "";
2714
+ const parts = input.trim().replace(/_/g, "-").split("-").filter(Boolean);
2715
+ if (!parts.length || !/^[a-zA-Z]{2,3}$/.test(parts[0])) return "";
2716
+ 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("-");
2717
+ }
2718
+ function baseLanguage(locale) {
2719
+ return normalizeLocale(locale).split("-")[0] ?? "";
2720
+ }
2721
+ function resolveLocale(requested, available, defaultLocale = DEFAULT_LOCALE) {
2722
+ const def = normalizeLocale(defaultLocale) || DEFAULT_LOCALE;
2723
+ const avail = available.map(normalizeLocale).filter(Boolean);
2724
+ const all = [def, ...avail.filter((a) => a.toLowerCase() !== def.toLowerCase())];
2725
+ for (const raw of requested) {
2726
+ const want = normalizeLocale(raw);
2727
+ if (!want) continue;
2728
+ const exact = all.find((a) => a.toLowerCase() === want.toLowerCase());
2729
+ if (exact) return exact;
2730
+ const base = baseLanguage(want);
2731
+ const sameBase = all.find((a) => a.toLowerCase() === base) ?? all.find((a) => baseLanguage(a) === base);
2732
+ if (sameBase) return sameBase;
2733
+ }
2734
+ return def;
2735
+ }
2736
+ function visitorLocales(explicit, traits, platform = []) {
2737
+ const out = [];
2738
+ const push = (v) => {
2739
+ const n = normalizeLocale(v);
2740
+ if (n && !out.includes(n)) out.push(n);
2741
+ };
2742
+ push(explicit);
2743
+ push(traits?.language);
2744
+ push(traits?.locale);
2745
+ for (const p of platform) push(p);
2746
+ return out;
2747
+ }
2748
+ function guideTextEntries(config) {
2749
+ const out = [];
2750
+ const add = (key, source, kind, label) => {
2751
+ if (source && source.trim()) out.push({ key, source, kind, label });
2752
+ };
2753
+ config.steps.forEach((s, i) => {
2754
+ const at = `Step ${i + 1}`;
2755
+ add(`steps.${s.id}.title`, s.title, "text", `${at} \xB7 Title`);
2756
+ add(`steps.${s.id}.body`, s.body, "html", `${at} \xB7 Body`);
2757
+ add(`steps.${s.id}.customHtml`, s.customHtml, "html", `${at} \xB7 Custom HTML`);
2758
+ add(`steps.${s.id}.imageAlt`, s.imageAlt, "text", `${at} \xB7 Image description`);
2759
+ s.buttons.forEach((b) => add(`steps.${s.id}.buttons.${b.id}.label`, b.label, "text", `${at} \xB7 Button \u201C${b.label}\u201D`));
2760
+ });
2761
+ const c = config.checklist;
2762
+ if (c) {
2763
+ add("checklist.launcherLabel", c.launcherLabel, "text", "Checklist \xB7 Launcher label");
2764
+ add("checklist.completionTitle", c.completionTitle, "text", "Checklist \xB7 Completion title");
2765
+ add("checklist.completionBody", c.completionBody, "html", "Checklist \xB7 Completion message");
2766
+ c.tasks.forEach((t, i) => {
2767
+ add(`checklist.tasks.${t.id}.title`, t.title, "text", `Task ${i + 1} \xB7 Title`);
2768
+ add(`checklist.tasks.${t.id}.description`, t.description, "html", `Task ${i + 1} \xB7 Description`);
2769
+ });
2770
+ }
2771
+ const sv = config.survey;
2772
+ if (sv) {
2773
+ sv.questions.forEach((q, i) => {
2774
+ const at = `Question ${i + 1}`;
2775
+ add(`survey.questions.${q.id}.title`, q.title, "text", `${at} \xB7 Question`);
2776
+ add(`survey.questions.${q.id}.description`, q.description, "text", `${at} \xB7 Description`);
2777
+ add(`survey.questions.${q.id}.placeholder`, q.placeholder, "text", `${at} \xB7 Placeholder`);
2778
+ add(`survey.questions.${q.id}.lowLabel`, q.lowLabel, "text", `${at} \xB7 Low label`);
2779
+ add(`survey.questions.${q.id}.highLabel`, q.highLabel, "text", `${at} \xB7 High label`);
2780
+ q.options.forEach((o) => add(`survey.questions.${q.id}.options.${o.id}.label`, o.label, "text", `${at} \xB7 Option \u201C${o.label}\u201D`));
2781
+ });
2782
+ add("survey.thankYouTitle", sv.thankYouTitle, "text", "Survey \xB7 Thank-you title");
2783
+ add("survey.thankYouBody", sv.thankYouBody, "html", "Survey \xB7 Thank-you message");
2784
+ }
2785
+ return out;
2786
+ }
2787
+ function guideLocales(config) {
2788
+ const t = config.localization?.translations ?? {};
2789
+ return Object.keys(t).filter((l) => Object.values(t[l] ?? {}).some((v) => typeof v === "string" && v.trim() !== ""));
2790
+ }
2791
+ function pick(map, key, fallback) {
2792
+ const v = map?.[key];
2793
+ return typeof v === "string" && v.trim() !== "" ? v : fallback;
2794
+ }
2795
+ function applyGuideTranslations(config, map) {
2796
+ if (!map || !Object.keys(map).length) return config;
2797
+ return {
2798
+ ...config,
2799
+ steps: config.steps.map((s) => ({
2800
+ ...s,
2801
+ title: pick(map, `steps.${s.id}.title`, s.title),
2802
+ body: pick(map, `steps.${s.id}.body`, s.body),
2803
+ customHtml: pick(map, `steps.${s.id}.customHtml`, s.customHtml),
2804
+ imageAlt: pick(map, `steps.${s.id}.imageAlt`, s.imageAlt),
2805
+ buttons: s.buttons.map((b) => ({ ...b, label: pick(map, `steps.${s.id}.buttons.${b.id}.label`, b.label) }))
2806
+ })),
2807
+ checklist: config.checklist ? {
2808
+ ...config.checklist,
2809
+ launcherLabel: pick(map, "checklist.launcherLabel", config.checklist.launcherLabel),
2810
+ completionTitle: pick(map, "checklist.completionTitle", config.checklist.completionTitle),
2811
+ completionBody: pick(map, "checklist.completionBody", config.checklist.completionBody),
2812
+ 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) }))
2813
+ } : config.checklist,
2814
+ survey: config.survey ? {
2815
+ ...config.survey,
2816
+ thankYouTitle: pick(map, "survey.thankYouTitle", config.survey.thankYouTitle),
2817
+ thankYouBody: pick(map, "survey.thankYouBody", config.survey.thankYouBody),
2818
+ questions: config.survey.questions.map((q) => ({
2819
+ ...q,
2820
+ title: pick(map, `survey.questions.${q.id}.title`, q.title),
2821
+ description: pick(map, `survey.questions.${q.id}.description`, q.description),
2822
+ placeholder: pick(map, `survey.questions.${q.id}.placeholder`, q.placeholder),
2823
+ lowLabel: pick(map, `survey.questions.${q.id}.lowLabel`, q.lowLabel),
2824
+ highLabel: pick(map, `survey.questions.${q.id}.highLabel`, q.highLabel),
2825
+ options: q.options.map((o) => ({ ...o, label: pick(map, `survey.questions.${q.id}.options.${o.id}.label`, o.label) }))
2826
+ }))
2827
+ } : config.survey
2828
+ };
2829
+ }
2830
+ function localizeGuide(guide, requested, defaultLocale = DEFAULT_LOCALE) {
2831
+ const translations = guide.config.localization?.translations ?? {};
2832
+ const locale = resolveLocale(requested, guideLocales(guide.config), defaultLocale);
2833
+ const key = Object.keys(translations).find((l) => normalizeLocale(l).toLowerCase() === locale.toLowerCase());
2834
+ if (!key) return { ...guide, locale };
2835
+ return { ...guide, locale, config: applyGuideTranslations(guide.config, translations[key]) };
2836
+ }
2837
+ function translationCoverage(entries, map, locale) {
2838
+ const keys = new Set(entries.map((e) => e.key));
2839
+ const missing = entries.filter((e) => !pick(map, e.key, void 0)).map((e) => e.key);
2840
+ const stale = Object.keys(map ?? {}).filter((k) => !keys.has(k) && (map?.[k] ?? "").trim() !== "");
2841
+ return { locale, total: entries.length, translated: entries.length - missing.length, missing, stale };
2842
+ }
2843
+ function resourceCenterTextEntries(rc) {
2844
+ const out = [];
2845
+ const add = (key, source, kind, label) => {
2846
+ if (source && source.trim()) out.push({ key, source, kind, label });
2847
+ };
2848
+ add("title", rc.title, "text", "Title");
2849
+ add("launcher.label", rc.launcher?.label, "text", "Launcher label");
2850
+ rc.collections.forEach((c) => {
2851
+ add(`collections.${c.id}.name`, c.name, "text", `Collection \u201C${c.name}\u201D`);
2852
+ add(`collections.${c.id}.description`, c.description, "text", `Collection \u201C${c.name}\u201D \xB7 Description`);
2853
+ });
2854
+ rc.links.forEach((l) => add(`links.${l.id}.label`, l.label, "text", `Link \u201C${l.label}\u201D`));
2855
+ rc.faqs.forEach((f, i) => {
2856
+ add(`faqs.${f.id}.question`, f.question, "text", `FAQ ${i + 1} \xB7 Question`);
2857
+ add(`faqs.${f.id}.answer`, f.answer, "html", `FAQ ${i + 1} \xB7 Answer`);
2858
+ });
2859
+ return out;
2860
+ }
2861
+ function articleTextEntries(a) {
2862
+ const out = [];
2863
+ if (a.title.trim()) out.push({ key: "title", source: a.title, kind: "text", label: "Title" });
2864
+ if (a.summary?.trim()) out.push({ key: "summary", source: a.summary, kind: "text", label: "Summary" });
2865
+ if (a.body?.trim()) out.push({ key: "body", source: a.body, kind: "html", label: "Body" });
2866
+ return out;
2867
+ }
2868
+ function resourceCenterLocales(rc) {
2869
+ const set = new Set(Object.keys(rc.translations ?? {}));
2870
+ for (const a of rc.articles) for (const l of Object.keys(a.translations ?? {})) set.add(l);
2871
+ for (const a of rc.announcements ?? []) for (const l of Object.keys(a.translations ?? {})) set.add(l);
2872
+ return [...set];
2873
+ }
2874
+ function translationFor(map, locale) {
2875
+ if (!map) return void 0;
2876
+ const key = Object.keys(map).find((l) => normalizeLocale(l).toLowerCase() === locale.toLowerCase());
2877
+ return key ? map[key] : void 0;
2878
+ }
2879
+ function localizeArticle(a, locale) {
2880
+ const t = translationFor(a.translations, locale);
2881
+ if (!t) return a;
2882
+ const body = t.body?.trim() ? t.body : a.body;
2883
+ return { ...a, title: t.title?.trim() ? t.title : a.title, summary: t.summary?.trim() ? t.summary : a.summary, body, ...t.bodyOmitted ? { bodyOmitted: true } : {} };
2884
+ }
2885
+ function localizeAnnouncement(a, locale) {
2886
+ const t = translationFor(a.translations, locale);
2887
+ if (!t) return a;
2888
+ return { ...a, title: t.title?.trim() ? t.title : a.title, body: t.body?.trim() ? t.body : a.body };
2889
+ }
2890
+ function localizeResourceCenter(rc, requested, defaultLocale = DEFAULT_LOCALE) {
2891
+ const locale = resolveLocale(requested, resourceCenterLocales(rc), defaultLocale);
2892
+ if (locale.toLowerCase() === normalizeLocale(defaultLocale).toLowerCase()) return { ...rc, locale };
2893
+ const map = translationFor(rc.translations, locale);
2894
+ return {
2895
+ ...rc,
2896
+ locale,
2897
+ title: pick(map, "title", rc.title),
2898
+ launcher: { ...rc.launcher, label: pick(map, "launcher.label", rc.launcher.label) },
2899
+ collections: rc.collections.map((c) => ({ ...c, name: pick(map, `collections.${c.id}.name`, c.name), description: pick(map, `collections.${c.id}.description`, c.description) })),
2900
+ links: rc.links.map((l) => ({ ...l, label: pick(map, `links.${l.id}.label`, l.label) })),
2901
+ faqs: rc.faqs.map((f) => ({ ...f, question: pick(map, `faqs.${f.id}.question`, f.question), answer: pick(map, `faqs.${f.id}.answer`, f.answer) })),
2902
+ articles: rc.articles.map((a) => localizeArticle(a, locale)),
2903
+ announcements: rc.announcements?.map((a) => localizeAnnouncement(a, locale))
2904
+ };
2905
+ }
2906
+
2907
+ // src/guide-experiments.ts
2908
+ var CONTROL_VARIANT_ID = "control";
2909
+ var GUIDE_EXPERIMENT_STATUSES = ["draft", "running", "completed"];
2910
+ var GUIDE_EXPERIMENT_GOALS = ["guide_completed", "event", "page_visit", "click_text"];
2911
+ var GUIDE_EXPERIMENT_GOAL_LABELS = {
2912
+ guide_completed: "Completes the guide",
2913
+ event: "Tracks an event",
2914
+ page_visit: "Visits a page",
2915
+ click_text: "Clicks an element with text"
2916
+ };
2917
+ function experimentSalt(experimentId) {
2918
+ return `gx:${experimentId}`;
2919
+ }
2920
+ function variantRanges(variants) {
2921
+ let at = 0;
2922
+ return variants.map((v) => {
2923
+ const from = at;
2924
+ at = Math.min(100, at + Math.max(0, Math.round(v.weight)));
2925
+ return { id: v.id, from, to: at };
2926
+ });
2927
+ }
2928
+ function assignGuideVariant(variants, experimentId, subject) {
2929
+ const bucket = rolloutBucket(subject, experimentSalt(experimentId));
2930
+ return variantRanges(variants).find((r) => bucket >= r.from && bucket < r.to)?.id ?? null;
2931
+ }
2932
+ function experimentBucketRules(salt, from, to) {
2933
+ return [
2934
+ { id: "experiment-from", field: "experiment.bucket", key: salt, op: "gte", value: from },
2935
+ { id: "experiment-to", field: "experiment.bucket", key: salt, op: "lt", value: to }
2936
+ ];
2937
+ }
2938
+ function withExperimentBucket(targeting, salt, from, to) {
2939
+ return { id: "experiment", op: "and", rules: [...experimentBucketRules(salt, from, to), targeting] };
2940
+ }
2941
+ function variantProblems(variants) {
2942
+ const problems = [];
2943
+ if (variants.length < 2) problems.push("An A/B test needs at least two variants.");
2944
+ if (variants.length > 5) problems.push("An A/B test can have at most five variants.");
2945
+ const guides = variants.filter((v) => v.guideId);
2946
+ if (guides.length === 0) problems.push("At least one variant must show a guide.");
2947
+ if (variants.filter((v) => !v.guideId).length > 1) problems.push("Only one variant can be the control group (no guide).");
2948
+ if (new Set(guides.map((v) => v.guideId)).size !== guides.length) problems.push("Each variant needs its own guide.");
2949
+ if (new Set(variants.map((v) => v.id)).size !== variants.length) problems.push("Variant ids must be unique.");
2950
+ if (variants.some((v) => !Number.isInteger(v.weight) || v.weight < 1)) problems.push("Every variant needs a whole-number share of at least 1%.");
2951
+ const total = variants.reduce((s, v) => s + v.weight, 0);
2952
+ if (total !== 100) problems.push(`Traffic shares must add up to 100% (now ${total}%).`);
2953
+ return problems;
2954
+ }
2955
+ function evenWeights(n) {
2956
+ if (n <= 0) return [];
2957
+ const base = Math.floor(100 / n);
2958
+ return Array.from({ length: n }, (_, i) => base + (i < 100 - base * n ? 1 : 0));
2959
+ }
2960
+
2961
+ // src/custom-css.ts
2962
+ var MAX_CUSTOM_CSS = 2e4;
2963
+ var BLOCKED_AT_RULES = /^@(import|charset|namespace|document|-moz-document)\b/i;
2964
+ var ALLOWED_AT_RULES = /^@(media|supports|container|layer|keyframes|-webkit-keyframes|font-face)\b/i;
2965
+ function splitBlocks(css) {
2966
+ const out = [];
2967
+ let i = 0;
2968
+ const n = css.length;
2969
+ while (i < n) {
2970
+ let prelude = "";
2971
+ let quote = null;
2972
+ while (i < n) {
2973
+ const ch = css[i];
2974
+ if (quote) {
2975
+ prelude += ch;
2976
+ if (ch === "\\") prelude += css[++i] ?? "";
2977
+ else if (ch === quote) quote = null;
2978
+ } else if (ch === '"' || ch === "'") {
2979
+ quote = ch;
2980
+ prelude += ch;
2981
+ } else if (ch === "{") break;
2982
+ else if (ch === ";") {
2983
+ prelude = "";
2984
+ } else if (ch === "}") {
2985
+ prelude = "";
2986
+ } else prelude += ch;
2987
+ i++;
2988
+ }
2989
+ if (i >= n) break;
2990
+ i++;
2991
+ let depth = 1;
2992
+ let body = "";
2993
+ quote = null;
2994
+ while (i < n && depth > 0) {
2995
+ const ch = css[i];
2996
+ if (quote) {
2997
+ body += ch;
2998
+ if (ch === "\\") body += css[++i] ?? "";
2999
+ else if (ch === quote) quote = null;
3000
+ } else if (ch === '"' || ch === "'") {
3001
+ quote = ch;
3002
+ body += ch;
3003
+ } else if (ch === "{") {
3004
+ depth++;
3005
+ body += ch;
3006
+ } else if (ch === "}") {
3007
+ depth--;
3008
+ if (depth > 0) body += ch;
3009
+ } else body += ch;
3010
+ i++;
3011
+ }
3012
+ out.push({ prelude: prelude.trim(), body });
3013
+ }
3014
+ return out;
3015
+ }
3016
+ function splitSelectors(list) {
3017
+ const out = [];
3018
+ let depth = 0;
3019
+ let cur = "";
3020
+ for (const ch of list) {
3021
+ if (ch === "(" || ch === "[") depth++;
3022
+ else if (ch === ")" || ch === "]") depth = Math.max(0, depth - 1);
3023
+ if (ch === "," && depth === 0) {
3024
+ out.push(cur.trim());
3025
+ cur = "";
3026
+ } else cur += ch;
3027
+ }
3028
+ if (cur.trim()) out.push(cur.trim());
3029
+ return out;
3030
+ }
3031
+ function safeUrl(raw) {
3032
+ const u = raw.trim().replace(/^['"]|['"]$/g, "").trim();
3033
+ return /^https:\/\//i.test(u) || /^data:image\/(png|jpe?g|gif|webp|svg\+xml)[;,]/i.test(u);
3034
+ }
3035
+ function cleanDeclarations(body) {
3036
+ 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();
3037
+ }
3038
+ function sanitizeCustomCss(input) {
3039
+ if (!input) return "";
3040
+ let css = String(input).slice(0, MAX_CUSTOM_CSS);
3041
+ css = css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, "").replace(/<\/?[a-z!][^>]*>/gi, "").replace(/</g, "");
3042
+ return render(splitBlocks(css), 0);
3043
+ }
3044
+ function render(blocks, depth) {
3045
+ const parts = [];
3046
+ for (const b of blocks) {
3047
+ if (!b.prelude) continue;
3048
+ if (b.prelude.startsWith("@")) {
3049
+ if (BLOCKED_AT_RULES.test(b.prelude) || !ALLOWED_AT_RULES.test(b.prelude)) continue;
3050
+ if (/^@(-webkit-)?keyframes|^@font-face/i.test(b.prelude)) {
3051
+ const inner = /^@font-face/i.test(b.prelude) ? cleanDeclarations(b.body) : splitBlocks(b.body).map((k) => `${k.prelude}{${cleanDeclarations(k.body)}}`).join("");
3052
+ parts.push(`${b.prelude}{${inner}}`);
3053
+ } else if (depth < 3) parts.push(`${b.prelude}{${render(splitBlocks(b.body), depth + 1)}}`);
3054
+ continue;
3055
+ }
3056
+ const selectors = splitSelectors(b.prelude).filter((s) => !/:host|::slotted|::part/i.test(s));
3057
+ if (!selectors.length) continue;
3058
+ parts.push(`${selectors.join(",")}{${cleanDeclarations(b.body)}}`);
3059
+ }
3060
+ return parts.join("\n");
3061
+ }
3062
+ function scopeCustomCss(css, scope) {
3063
+ return scopeBlocks(splitBlocks(sanitizeCustomCss(css)), scope, 0);
3064
+ }
3065
+ function scopeBlocks(blocks, scope, depth) {
3066
+ const parts = [];
3067
+ for (const b of blocks) {
3068
+ if (b.prelude.startsWith("@")) {
3069
+ if (/^@(-webkit-)?keyframes|^@font-face/i.test(b.prelude)) parts.push(`${b.prelude}{${b.body}}`);
3070
+ else if (depth < 3) parts.push(`${b.prelude}{${scopeBlocks(splitBlocks(b.body), scope, depth + 1)}}`);
3071
+ continue;
3072
+ }
3073
+ const sels = splitSelectors(b.prelude).map((s) => {
3074
+ const self = s.match(/^(:root|html|body|:scope|&)(?![\w-])(.*)$/i);
3075
+ if (self) return `${scope}${self[2] ?? ""}`;
3076
+ return `${scope} ${s}`;
3077
+ });
3078
+ parts.push(`${sels.join(",")}{${b.body}}`);
3079
+ }
3080
+ return parts.join("\n");
3081
+ }
3082
+
3083
+ // src/translation-files.ts
3084
+ function xmlEscape(s) {
3085
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3086
+ }
3087
+ function xmlUnescape(s) {
3088
+ return s.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, (_, c) => c.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")).replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d))).replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16))).replace(/&amp;/g, "&");
3089
+ }
3090
+ function toXliff(units, opts) {
3091
+ const body = units.map(
3092
+ (u) => ` <trans-unit id="${xmlEscape(u.key)}">
3093
+ <source>${xmlEscape(u.source)}</source>
3094
+ <target${u.target ? "" : ' state="needs-translation"'}>${xmlEscape(u.target)}</target>${u.note ? `
3095
+ <note>${xmlEscape(u.note)}</note>` : ""}
3096
+ </trans-unit>`
3097
+ ).join("\n");
3098
+ return `<?xml version="1.0" encoding="UTF-8"?>
3099
+ <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3100
+ <file original="${xmlEscape(opts.original)}" source-language="${xmlEscape(opts.sourceLocale)}" target-language="${xmlEscape(opts.targetLocale)}" datatype="html">
3101
+ <body>
3102
+ ${body}
3103
+ </body>
3104
+ </file>
3105
+ </xliff>
3106
+ `;
3107
+ }
3108
+ function parseXliff(xml) {
3109
+ const target = xml.match(/target-language="([^"]+)"/)?.[1] ?? xml.match(/\btrgLang="([^"]+)"/)?.[1];
3110
+ const entries = {};
3111
+ for (const m of xml.matchAll(/<(trans-unit|unit)\b[^>]*\bid="([^"]*)"[^>]*>([\s\S]*?)<\/\1>/g)) {
3112
+ const key = xmlUnescape(m[2]);
3113
+ const t = m[3].match(/<target\b[^>]*>([\s\S]*?)<\/target>/);
3114
+ const text = t ? xmlUnescape(t[1]) : "";
3115
+ if (key && text.trim()) entries[key] = text;
3116
+ }
3117
+ return { targetLocale: target ? xmlUnescape(target) : void 0, entries };
3118
+ }
3119
+ function csvCell(s) {
3120
+ return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
3121
+ }
3122
+ function toTranslationCsv(units, targetLocale) {
3123
+ const rows = [["key", "context", "source", targetLocale], ...units.map((u) => [u.key, u.note ?? "", u.source, u.target])];
3124
+ return rows.map((r) => r.map(csvCell).join(",")).join("\r\n") + "\r\n";
3125
+ }
3126
+ function parseCsvRows(text) {
3127
+ const rows = [];
3128
+ let row = [];
3129
+ let cell = "";
3130
+ let quoted2 = false;
3131
+ const src = text.replace(/^\uFEFF/, "");
3132
+ for (let i = 0; i < src.length; i++) {
3133
+ const ch = src[i];
3134
+ if (quoted2) {
3135
+ if (ch === '"') {
3136
+ if (src[i + 1] === '"') {
3137
+ cell += '"';
3138
+ i++;
3139
+ } else quoted2 = false;
3140
+ } else cell += ch;
3141
+ } else if (ch === '"') quoted2 = true;
3142
+ else if (ch === ",") {
3143
+ row.push(cell);
3144
+ cell = "";
3145
+ } else if (ch === "\n" || ch === "\r") {
3146
+ if (ch === "\r" && src[i + 1] === "\n") i++;
3147
+ row.push(cell);
3148
+ rows.push(row);
3149
+ row = [];
3150
+ cell = "";
3151
+ } else cell += ch;
3152
+ }
3153
+ if (cell !== "" || row.length) {
3154
+ row.push(cell);
3155
+ rows.push(row);
3156
+ }
3157
+ return rows.filter((r) => r.some((c) => c.trim() !== ""));
3158
+ }
3159
+ function parseTranslationCsv(text) {
3160
+ const [header, ...rows] = parseCsvRows(text);
3161
+ if (!header) return { entries: {} };
3162
+ const names = header.map((h) => h.trim());
3163
+ const lower = names.map((h) => h.toLowerCase());
3164
+ const keyCol = lower.indexOf("key");
3165
+ if (keyCol < 0) return { entries: {} };
3166
+ let targetCol = lower.indexOf("target");
3167
+ if (targetCol < 0) {
3168
+ for (let i = names.length - 1; i >= 0; i--) {
3169
+ if (!["key", "context", "source", "label", "note"].includes(lower[i])) {
3170
+ targetCol = i;
3171
+ break;
3172
+ }
3173
+ }
3174
+ }
3175
+ if (targetCol < 0) return { entries: {} };
3176
+ const entries = {};
3177
+ for (const r of rows) {
3178
+ const key = (r[keyCol] ?? "").trim();
3179
+ const value = r[targetCol] ?? "";
3180
+ if (key && value.trim()) entries[key] = value;
3181
+ }
3182
+ return { targetLocale: lower[targetCol] === "target" ? void 0 : names[targetCol], entries };
3183
+ }
3184
+
1731
3185
  // src/index.ts
1732
3186
  var SDK_API_VERSION = "v1";
1733
- var SHARED_VERSION = "0.10.0";
3187
+ var SHARED_VERSION = "0.12.0";
1734
3188
  // Annotate the CommonJS export names for ESM import in node:
1735
3189
  0 && (module.exports = {
1736
3190
  ADVANCE_ON,
3191
+ AGENT_METADATA_MAX_BYTES,
3192
+ AGENT_METADATA_MAX_KEYS,
3193
+ AGENT_OUTCOMES,
3194
+ AGENT_TOOL_CALLS_PER_TURN,
3195
+ AGENT_TOOL_STATUSES,
3196
+ AGENT_TURNS_PER_BATCH,
3197
+ AGENT_TURN_MAX_TEXT,
3198
+ AGENT_TURN_ROLES,
1737
3199
  ANNOTATION_COLORS,
3200
+ APP_LIFECYCLE_EVENTS,
1738
3201
  ARTICLE_VISIBILITIES,
1739
3202
  AUTOCAPTURE_EVENTS,
3203
+ AgentEventsRequestSchema,
3204
+ AgentMetadataSchema,
3205
+ AgentToolCallSchema,
3206
+ AgentTurnInputSchema,
1740
3207
  AppearanceSchema,
1741
3208
  AuthoringPickSchema,
1742
3209
  AutocaptureSettingsSchema,
@@ -1744,9 +3211,11 @@ var SHARED_VERSION = "0.10.0";
1744
3211
  ButtonSchema,
1745
3212
  CAPTURE_PARAM,
1746
3213
  CAPTURE_SCREENSHOT_MAX_BYTES,
3214
+ COMMON_LOCALES,
1747
3215
  COMPLAINT_EVENTS,
1748
3216
  COMPLAINT_FIELD_TYPES,
1749
3217
  COMPLAINT_STATUSES,
3218
+ CONTROL_VARIANT_ID,
1750
3219
  CaptureStepSchema,
1751
3220
  CapturedElementSchema,
1752
3221
  ChecklistConfigSchema,
@@ -1755,28 +3224,54 @@ var SHARED_VERSION = "0.10.0";
1755
3224
  ConversationLookupSchema,
1756
3225
  ConversationRatingSchema,
1757
3226
  DEFAULT_CAPTURE_SETTINGS,
3227
+ DEFAULT_FEATURE_ATTRIBUTE,
3228
+ DEFAULT_LOCALE,
1758
3229
  DEFAULT_PLATFORMS,
1759
3230
  EMBED_IFRAME_ATTRS,
1760
3231
  EVENT_NAMES,
1761
3232
  ErrorTrackingSettingsSchema,
1762
3233
  EventBatchSchema,
3234
+ FEATURE_ATTRIBUTE_PATTERN,
3235
+ FEATURE_RULE_LIMITS,
3236
+ FEEDBACK_EVENTS,
3237
+ FEEDBACK_PRIORITIES,
3238
+ FEEDBACK_PRIORITY_LABEL,
3239
+ FEEDBACK_PRIORITY_WEIGHT,
3240
+ FEEDBACK_STATUSES,
3241
+ FEEDBACK_STATUS_LABEL,
1763
3242
  FILE_LINK_CLASS,
3243
+ FeedbackCommentSchema,
3244
+ FeedbackFollowSchema,
3245
+ FeedbackListRequestSchema,
3246
+ FeedbackSimilarSchema,
3247
+ FeedbackUpdatesReadSchema,
3248
+ FeedbackVisitorSchema,
3249
+ FeedbackVoteSchema,
1764
3250
  FileComplaintSchema,
1765
3251
  FrequencySchema,
1766
3252
  GUIDELY_ID_ATTRIBUTE,
3253
+ GUIDE_EXPERIMENT_GOALS,
3254
+ GUIDE_EXPERIMENT_GOAL_LABELS,
3255
+ GUIDE_EXPERIMENT_STATUSES,
1767
3256
  GUIDE_KINDS,
1768
3257
  GUIDE_LIFECYCLE_EVENTS,
1769
3258
  GUIDE_STATUSES,
1770
3259
  GUIDE_TEMPLATES,
1771
3260
  GUIDE_VISIBILITIES,
1772
3261
  GuideConfigSchema,
3262
+ GuideLocalizationSchema,
3263
+ GuideScheduleSchema,
1773
3264
  GuideStateUpdateSchema,
3265
+ GuideThrottlingSchema,
1774
3266
  HEATMAP_VIEWPORTS,
1775
3267
  HOWTO_ACTIONS,
1776
3268
  HOWTO_STEP_KINDS,
1777
3269
  HowToAnnotationSchema,
1778
3270
  IdentifyRequestSchema,
3271
+ LOCALE_PATTERN,
1779
3272
  LOGGED_IN_AUDIENCE,
3273
+ LocaleSchema,
3274
+ LocalizationSettingsSchema,
1780
3275
  MAX_ANNOTATIONS,
1781
3276
  MAX_COLLECTION_DEPTH,
1782
3277
  MAX_COMPLAINT_ANSWER_LENGTH,
@@ -1784,6 +3279,11 @@ var SHARED_VERSION = "0.10.0";
1784
3279
  MAX_COMPLAINT_CHOICES,
1785
3280
  MAX_COMPLAINT_FIELDS,
1786
3281
  MAX_COMPLAINT_LENGTH,
3282
+ MAX_CUSTOM_CSS,
3283
+ MAX_FEEDBACK_COMMENT,
3284
+ MAX_FEEDBACK_DESCRIPTION,
3285
+ MAX_FEEDBACK_NOTE,
3286
+ MAX_FEEDBACK_TITLE,
1787
3287
  MAX_MESSAGE_LENGTH,
1788
3288
  MAX_PROPERTY_BYTES,
1789
3289
  MAX_STACK_FRAMES,
@@ -1797,8 +3297,10 @@ var SHARED_VERSION = "0.10.0";
1797
3297
  MESSAGE_AUTHORS,
1798
3298
  MessengerPageRequestSchema,
1799
3299
  NETWORK_PLUGIN,
3300
+ NOISY_DATA_ATTR,
1800
3301
  NormalizedPointSchema,
1801
3302
  NormalizedRectSchema,
3303
+ PAGE_RULE_LIMITS,
1802
3304
  PATH_ID_PATTERN,
1803
3305
  PDF_BLOCK_CLASS,
1804
3306
  PDF_MAX_PAGES,
@@ -1808,6 +3310,8 @@ var SHARED_VERSION = "0.10.0";
1808
3310
  PostMessageSchema,
1809
3311
  ProjectThemeSchema,
1810
3312
  PublishedGuideSchema,
3313
+ RC_MODULE_IDS,
3314
+ RC_MODULE_LABELS,
1811
3315
  REPLAY_MAX_COMPRESSED_BYTES,
1812
3316
  REPLAY_MAX_RAW_BYTES,
1813
3317
  REPLY_TIMES,
@@ -1817,6 +3321,7 @@ var SHARED_VERSION = "0.10.0";
1817
3321
  ReplaySettingsSchema,
1818
3322
  RuleGroupSchema,
1819
3323
  RuleSchema,
3324
+ SCOUT_AGENT_ID,
1820
3325
  SCRIPT_STUB,
1821
3326
  SCRIPT_STUB_METHODS,
1822
3327
  SDK_API_VERSION,
@@ -1828,30 +3333,46 @@ var SHARED_VERSION = "0.10.0";
1828
3333
  SHARED_VERSION,
1829
3334
  SHOW_ME_CLASS,
1830
3335
  SHOW_ME_HREF_PREFIX,
3336
+ SNAPSHOT_ATTRS,
3337
+ SNAPSHOT_LIMITS,
1831
3338
  SOURCEMAP_MAX_FILES_PER_UPLOAD,
1832
3339
  SOURCEMAP_MAX_FILE_BYTES,
1833
3340
  STATUS_LEVELS,
1834
3341
  STEP_TYPES,
1835
3342
  SURVEY_QUESTION_TYPES,
3343
+ SdkAgentEventsSchema,
1836
3344
  SdkEventSchema,
1837
3345
  SelectorStrategySchema,
3346
+ SelectorSyntaxError,
1838
3347
  StartConversationSchema,
1839
3348
  StepBranchSchema,
1840
3349
  StepSchema,
3350
+ SubmitFeedbackSchema,
1841
3351
  SurveyConfigSchema,
1842
3352
  SurveyQuestionSchema,
1843
3353
  SurveyResponseRequestSchema,
3354
+ TAG_PROPERTY_LIMITS,
1844
3355
  TRIGGER_TYPES,
1845
3356
  TargetSchema,
1846
3357
  TriggerSchema,
1847
3358
  VIDEO_ATTRS,
3359
+ WCAG_AA_LARGE,
3360
+ WCAG_AA_TEXT,
1848
3361
  WS_MAX_MESSAGES_PER_SOCKET,
1849
3362
  WS_MAX_MESSAGE_BYTES,
3363
+ applyGuideTranslations,
3364
+ articleTextEntries,
3365
+ assignGuideVariant,
3366
+ baseLanguage,
1850
3367
  clamp,
1851
3368
  cleanLabel,
1852
3369
  compare,
1853
3370
  compareVersions,
1854
3371
  complaintReference,
3372
+ compoundMatches,
3373
+ contrastIssues,
3374
+ contrastRatio,
3375
+ cssSelectorError,
1855
3376
  defaultGuideConfig,
1856
3377
  defaultStep,
1857
3378
  describeCaptureStep,
@@ -1859,12 +3380,21 @@ var SHARED_VERSION = "0.10.0";
1859
3380
  emptyRuleGroup,
1860
3381
  evaluateRule,
1861
3382
  evaluateRules,
3383
+ evenWeights,
3384
+ experimentBucketRules,
3385
+ experimentSalt,
3386
+ featureCssSelectors,
3387
+ featureRuleError,
3388
+ featureRuleMatchesClick,
3389
+ feedbackReference,
1862
3390
  fingerprintError,
1863
3391
  firstNameFromTraits,
1864
3392
  fnv1a,
1865
3393
  foldPathIds,
1866
3394
  getPath,
3395
+ guideLocales,
1867
3396
  guidePlatforms,
3397
+ guideTextEntries,
1868
3398
  guidelyIdFromSelector,
1869
3399
  hasVideoMedia,
1870
3400
  isAllowedEmbedSrc,
@@ -1877,23 +3407,51 @@ var SHARED_VERSION = "0.10.0";
1877
3407
  isRuleGroup,
1878
3408
  isSafeMediaUrl,
1879
3409
  isVideoContentType,
3410
+ localeName,
3411
+ localizeAnnouncement,
3412
+ localizeArticle,
3413
+ localizeGuide,
3414
+ localizeResourceCenter,
3415
+ matchCssSelector,
1880
3416
  matchUrlPattern,
1881
3417
  matchesAudiences,
1882
3418
  matchesHelpQuery,
1883
3419
  mediaKind,
1884
3420
  mediaMaxBytes,
3421
+ needsReview,
1885
3422
  normalizeErrorMessage,
1886
3423
  normalizeFrameFile,
3424
+ normalizeLocale,
3425
+ normalizeSnapshot,
3426
+ orderedModules,
1887
3427
  pageLabel,
1888
3428
  pageName,
3429
+ pagePattern,
3430
+ pageRuleError,
3431
+ pageRuleMatches,
3432
+ pageRulesMatch,
1889
3433
  pageTerms,
3434
+ parseCssSelector,
3435
+ parseCsvRows,
3436
+ parseHexColor,
1890
3437
  parseStack,
3438
+ parseTranslationCsv,
3439
+ parseXliff,
3440
+ propertyAttributeAllowed,
3441
+ queryConditionRegex,
1891
3442
  randomId,
3443
+ readableTextOn,
3444
+ relativeLuminance,
1892
3445
  resolveCaptureSettings,
3446
+ resolveLocale,
3447
+ resourceCenterLocales,
1893
3448
  resourceCenterSections,
3449
+ resourceCenterTextEntries,
1894
3450
  rolloutBucket,
1895
3451
  safeRegExp,
3452
+ sanitizeCustomCss,
1896
3453
  sanitizeProperties,
3454
+ scopeCustomCss,
1897
3455
  screenPath,
1898
3456
  scriptSnippet,
1899
3457
  servedArticleAudiences,
@@ -1901,14 +3459,25 @@ var SHARED_VERSION = "0.10.0";
1901
3459
  showMeKeyFromHref,
1902
3460
  showMeKeys,
1903
3461
  slugify,
3462
+ snapshotFromSelector,
3463
+ stableStringify,
1904
3464
  stripOrigin,
1905
3465
  supportsPlatform,
1906
3466
  templateConfig,
1907
3467
  toEmbedUrl,
3468
+ toTranslationCsv,
3469
+ toXliff,
3470
+ translationCoverage,
3471
+ unreadAnnouncements,
1908
3472
  validateGuideConfig,
3473
+ variantProblems,
3474
+ variantRanges,
3475
+ visibleAnnouncements,
1909
3476
  visibleArticleIds,
1910
3477
  visibleButtons,
1911
3478
  visitorAudiences,
3479
+ visitorLocales,
3480
+ withExperimentBucket,
1912
3481
  withVisibility
1913
3482
  });
1914
3483
  //# sourceMappingURL=index.cjs.map