@guidelytech/shared 0.10.0 → 0.11.0

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