@guidelytech/shared 0.0.0-stage → 0.2.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.js ADDED
@@ -0,0 +1,669 @@
1
+ import {
2
+ MAX_PROPERTY_BYTES,
3
+ RULE_FIELDS,
4
+ RULE_OPERATORS,
5
+ SENSITIVE_PROPERTY_PATTERN,
6
+ SERVER_ASSISTED_FIELDS,
7
+ clamp,
8
+ compare,
9
+ describeRule,
10
+ emptyRuleGroup,
11
+ evaluateRule,
12
+ evaluateRules,
13
+ fnv1a,
14
+ getPath,
15
+ isPlainObject,
16
+ isRuleGroup,
17
+ matchUrlPattern,
18
+ randomId,
19
+ rolloutBucket,
20
+ safeRegExp,
21
+ sanitizeProperties,
22
+ slugify,
23
+ stripOrigin
24
+ } from "./chunk-OFBIZEM5.js";
25
+
26
+ // src/targeting.ts
27
+ import { z } from "zod";
28
+ var RuleSchema = z.object({
29
+ id: z.string().min(1),
30
+ field: z.enum(RULE_FIELDS),
31
+ key: z.string().max(200).optional(),
32
+ op: z.enum(RULE_OPERATORS),
33
+ value: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]).optional(),
34
+ negate: z.boolean().optional()
35
+ });
36
+ var RuleGroupSchema = z.lazy(
37
+ () => z.object({
38
+ id: z.string().min(1),
39
+ op: z.enum(["and", "or"]),
40
+ rules: z.array(z.union([RuleSchema, RuleGroupSchema])).max(100),
41
+ negate: z.boolean().optional()
42
+ })
43
+ );
44
+
45
+ // src/guide.ts
46
+ import { z as z2 } from "zod";
47
+ var GUIDE_KINDS = ["flow", "modal", "tooltip", "banner", "checklist", "survey", "announcement"];
48
+ var GUIDE_STATUSES = ["draft", "published", "paused", "archived"];
49
+ var STEP_TYPES = ["modal", "tooltip", "popover", "spotlight", "hotspot", "banner", "slideout", "checklist", "custom", "survey"];
50
+ var PLACEMENTS = ["top", "top-start", "top-end", "right", "right-start", "right-end", "bottom", "bottom-start", "bottom-end", "left", "left-start", "left-end", "auto"];
51
+ var SELECTOR_KINDS = ["css", "id", "data-attr", "aria", "text", "xpath"];
52
+ var SelectorStrategySchema = z2.object({
53
+ kind: z2.enum(SELECTOR_KINDS),
54
+ value: z2.string().min(1).max(1e3),
55
+ /** Optional human-readable label captured at pick time. */
56
+ label: z2.string().max(200).optional()
57
+ });
58
+ var TargetSchema = z2.object({
59
+ /** Ordered strategies; the first one resolving to exactly one element wins. */
60
+ selectors: z2.array(SelectorStrategySchema).max(10),
61
+ /** How long to wait for the element before applying fallback. */
62
+ waitMs: z2.number().int().min(0).max(6e4).default(5e3),
63
+ /** What to do when the element never shows up. */
64
+ fallback: z2.enum(["skip", "show_as_modal", "end_guide", "wait"]).default("skip"),
65
+ /** Scroll the element into view before positioning. */
66
+ scrollIntoView: z2.boolean().default(true),
67
+ /** Text snapshot captured at pick time; used for authoring warnings. */
68
+ textSnapshot: z2.string().max(200).optional()
69
+ });
70
+ var BUTTON_ACTIONS = ["next", "back", "dismiss", "complete", "skip", "url", "start_guide", "event", "open_resource_center", "none"];
71
+ var ButtonSchema = z2.object({
72
+ id: z2.string().min(1),
73
+ label: z2.string().min(1).max(80),
74
+ action: z2.enum(BUTTON_ACTIONS),
75
+ variant: z2.enum(["primary", "secondary", "ghost", "link"]).default("primary"),
76
+ /** url for `url`, guide id for `start_guide`, event name for `event`, step id for `next` branch override */
77
+ value: z2.string().max(2e3).optional(),
78
+ newTab: z2.boolean().optional()
79
+ });
80
+ var StepBranchSchema = z2.object({
81
+ id: z2.string(),
82
+ /** Rule group evaluated against targeting context when leaving the step. */
83
+ when: RuleGroupSchema,
84
+ /** Step id to jump to. */
85
+ goTo: z2.string()
86
+ });
87
+ var ADVANCE_ON = ["button", "element_click", "element_visible", "event", "delay", "any"];
88
+ var StepSchema = z2.object({
89
+ id: z2.string().min(1).max(64),
90
+ type: z2.enum(STEP_TYPES),
91
+ title: z2.string().max(200).default(""),
92
+ /** Sanitized HTML body (links, images, lists, formatting). */
93
+ body: z2.string().max(2e4).default(""),
94
+ imageUrl: z2.string().url().max(2e3).optional().or(z2.literal("")),
95
+ buttons: z2.array(ButtonSchema).max(6).default([]),
96
+ target: TargetSchema.optional(),
97
+ placement: z2.enum(PLACEMENTS).default("auto"),
98
+ /** Pixel offset between anchor and card. */
99
+ offset: z2.number().int().min(0).max(64).default(10),
100
+ showOverlay: z2.boolean().default(false),
101
+ showProgress: z2.boolean().default(true),
102
+ showClose: z2.boolean().default(true),
103
+ dismissOnOutsideClick: z2.boolean().default(false),
104
+ /** Highlight padding for spotlight. */
105
+ spotlightPadding: z2.number().int().min(0).max(64).default(6),
106
+ /** Banner/slideout position. */
107
+ position: z2.enum(["top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right", "center"]).default("bottom-right"),
108
+ /** URL pattern this step belongs to (for multi-page flows). */
109
+ url: z2.string().max(500).optional(),
110
+ /** Automatic advancement. */
111
+ advanceOn: z2.enum(ADVANCE_ON).default("button"),
112
+ advanceValue: z2.string().max(500).optional(),
113
+ advanceDelayMs: z2.number().int().min(0).max(6e5).optional(),
114
+ branches: z2.array(StepBranchSchema).max(10).default([]),
115
+ width: z2.number().int().min(200).max(900).optional(),
116
+ /** Step-level targeting: skip step when rules do not match. */
117
+ targeting: RuleGroupSchema.optional(),
118
+ /** Hotspot pulse dot settings. */
119
+ hotspot: z2.object({ size: z2.number().int().min(8).max(40).default(14), pulse: z2.boolean().default(true), openOn: z2.enum(["click", "hover"]).default("click") }).optional(),
120
+ /** Custom step: arbitrary sanitized HTML with no chrome. */
121
+ customHtml: z2.string().max(5e4).optional()
122
+ });
123
+ var TRIGGER_TYPES = ["page_load", "url_match", "event", "element_click", "element_visible", "manual", "delay", "after_guide", "segment_enter"];
124
+ var TriggerSchema = z2.object({
125
+ type: z2.enum(TRIGGER_TYPES).default("page_load"),
126
+ /** url pattern, event name, selector, guide id, audience id depending on type */
127
+ value: z2.string().max(1e3).optional(),
128
+ delayMs: z2.number().int().min(0).max(6e5).default(0),
129
+ /** Also require URL to match this pattern (any trigger). */
130
+ urlPattern: z2.string().max(500).optional()
131
+ });
132
+ var FrequencySchema = z2.object({
133
+ mode: z2.enum(["once", "once_per_session", "every_time", "interval"]).default("once"),
134
+ intervalHours: z2.number().int().min(1).max(8760).optional(),
135
+ maxImpressions: z2.number().int().min(1).max(1e3).optional(),
136
+ /** Hours to wait after dismissal before eligible again (when not `once`). */
137
+ cooldownHours: z2.number().int().min(0).max(8760).default(0),
138
+ /** Lower number wins when multiple guides qualify. */
139
+ priority: z2.number().int().min(0).max(1e3).default(100),
140
+ /** Guide ids that must not be active at the same time. */
141
+ mutuallyExclusiveWith: z2.array(z2.string()).max(50).default([]),
142
+ /** Re-show if dismissed (otherwise dismissal counts as completion for frequency). */
143
+ reshowAfterDismiss: z2.boolean().default(false)
144
+ });
145
+ var AppearanceSchema = z2.object({
146
+ theme: z2.enum(["light", "dark", "auto"]).default("auto"),
147
+ primaryColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
148
+ backgroundColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
149
+ textColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
150
+ borderRadius: z2.number().int().min(0).max(32).optional(),
151
+ fontFamily: z2.string().max(200).optional(),
152
+ overlayOpacity: z2.number().min(0).max(1).optional(),
153
+ zIndex: z2.number().int().min(1).max(2147483647).optional(),
154
+ preset: z2.string().max(50).optional(),
155
+ animation: z2.enum(["fade", "slide", "none"]).default("fade")
156
+ });
157
+ var ChecklistTaskSchema = z2.object({
158
+ id: z2.string().min(1),
159
+ title: z2.string().min(1).max(200),
160
+ description: z2.string().max(2e3).default(""),
161
+ /** How the task completes. */
162
+ completion: z2.enum(["manual", "event", "guide_completed", "url_visited", "click"]).default("manual"),
163
+ completionValue: z2.string().max(500).optional(),
164
+ /** Optional action when clicking the task. */
165
+ action: z2.enum(["none", "start_guide", "url", "event"]).default("none"),
166
+ actionValue: z2.string().max(2e3).optional(),
167
+ required: z2.boolean().default(true)
168
+ });
169
+ var ChecklistConfigSchema = z2.object({
170
+ tasks: z2.array(ChecklistTaskSchema).min(1).max(30),
171
+ ordered: z2.boolean().default(false),
172
+ launcherLabel: z2.string().max(60).default("Getting started"),
173
+ position: z2.enum(["bottom-right", "bottom-left"]).default("bottom-right"),
174
+ completionTitle: z2.string().max(200).default("You're all set!"),
175
+ completionBody: z2.string().max(2e3).default(""),
176
+ autoOpen: z2.boolean().default(true),
177
+ dismissible: z2.boolean().default(true)
178
+ });
179
+ var SURVEY_QUESTION_TYPES = ["nps", "csat", "thumbs", "single_choice", "multiple_choice", "text", "rating"];
180
+ var SurveyQuestionSchema = z2.object({
181
+ id: z2.string().min(1),
182
+ type: z2.enum(SURVEY_QUESTION_TYPES),
183
+ title: z2.string().min(1).max(500),
184
+ description: z2.string().max(1e3).default(""),
185
+ required: z2.boolean().default(true),
186
+ options: z2.array(z2.object({ id: z2.string(), label: z2.string().max(200) })).max(20).default([]),
187
+ scaleMax: z2.number().int().min(2).max(10).optional(),
188
+ lowLabel: z2.string().max(60).optional(),
189
+ highLabel: z2.string().max(60).optional(),
190
+ placeholder: z2.string().max(200).optional(),
191
+ /** Conditional follow-up: show only when a previous answer matches. */
192
+ showWhen: z2.object({ questionId: z2.string(), op: z2.enum(["equals", "lte", "gte", "in"]), value: z2.union([z2.string(), z2.number(), z2.array(z2.string())]) }).optional()
193
+ });
194
+ var SurveyConfigSchema = z2.object({
195
+ questions: z2.array(SurveyQuestionSchema).min(1).max(20),
196
+ thankYouTitle: z2.string().max(200).default("Thanks for your feedback!"),
197
+ thankYouBody: z2.string().max(2e3).default(""),
198
+ position: z2.enum(["bottom-right", "bottom-left", "center"]).default("bottom-right"),
199
+ startAt: z2.string().datetime().optional(),
200
+ endAt: z2.string().datetime().optional()
201
+ });
202
+ var GuideConfigSchema = z2.object({
203
+ steps: z2.array(StepSchema).max(50).default([]),
204
+ targeting: RuleGroupSchema.default(() => emptyRuleGroup()),
205
+ trigger: TriggerSchema.default({}),
206
+ frequency: FrequencySchema.default({}),
207
+ appearance: AppearanceSchema.default({}),
208
+ checklist: ChecklistConfigSchema.optional(),
209
+ survey: SurveyConfigSchema.optional(),
210
+ /** Restrict guide to url pattern(s) (applied before trigger). */
211
+ urlPatterns: z2.array(z2.string().max(500)).max(20).default([])
212
+ });
213
+ function defaultGuideConfig(kind) {
214
+ return GuideConfigSchema.parse({
215
+ steps: kind === "checklist" || kind === "survey" ? [] : [defaultStep(kind === "flow" ? "tooltip" : kind === "banner" ? "banner" : kind === "tooltip" ? "tooltip" : "modal")],
216
+ checklist: kind === "checklist" ? { tasks: [{ id: "task-1", title: "Complete your profile" }] } : void 0,
217
+ survey: kind === "survey" ? { questions: [{ id: "q1", type: "nps", title: "How likely are you to recommend us to a friend?" }] } : void 0,
218
+ trigger: kind === "checklist" ? { type: "page_load" } : {}
219
+ });
220
+ }
221
+ var stepCounter = 0;
222
+ function defaultStep(type, overrides = {}) {
223
+ stepCounter += 1;
224
+ const base = {
225
+ id: `step-${Date.now().toString(36)}-${stepCounter}`,
226
+ type,
227
+ title: type === "modal" ? "Welcome!" : "Step title",
228
+ body: "<p>Describe what the user should do here.</p>",
229
+ buttons: [
230
+ { id: "btn-back", label: "Back", action: "back", variant: "ghost" },
231
+ { id: "btn-next", label: "Next", action: "next", variant: "primary" }
232
+ ],
233
+ placement: type === "banner" ? "top" : "auto",
234
+ showOverlay: type === "modal" || type === "spotlight",
235
+ ...overrides
236
+ };
237
+ if (["tooltip", "popover", "spotlight", "hotspot"].includes(type) && !base.target) {
238
+ base.target = { selectors: [], waitMs: 5e3, fallback: "skip", scrollIntoView: true };
239
+ }
240
+ return StepSchema.parse(base);
241
+ }
242
+ function visibleButtons(step, canGoBack) {
243
+ return canGoBack ? step.buttons : step.buttons.filter((b) => b.action !== "back");
244
+ }
245
+ function validateGuideConfig(kind, config) {
246
+ const issues = [];
247
+ if (kind === "checklist") {
248
+ if (!config.checklist || config.checklist.tasks.length === 0) issues.push({ level: "error", message: "Checklist needs at least one task." });
249
+ } else if (kind === "survey") {
250
+ if (!config.survey || config.survey.questions.length === 0) issues.push({ level: "error", message: "Survey needs at least one question." });
251
+ config.survey?.questions.forEach((q) => {
252
+ if ((q.type === "single_choice" || q.type === "multiple_choice") && q.options.length < 2) issues.push({ level: "error", message: `Question "${q.title}" needs at least two options.` });
253
+ });
254
+ } else {
255
+ if (config.steps.length === 0) issues.push({ level: "error", message: "Add at least one step." });
256
+ }
257
+ const ids = /* @__PURE__ */ new Set();
258
+ config.steps.forEach((step, i) => {
259
+ if (ids.has(step.id)) issues.push({ level: "error", stepId: step.id, message: `Duplicate step id "${step.id}".` });
260
+ ids.add(step.id);
261
+ const anchored = ["tooltip", "popover", "spotlight", "hotspot"].includes(step.type);
262
+ if (anchored && (!step.target || step.target.selectors.length === 0)) issues.push({ level: "error", stepId: step.id, message: `Step ${i + 1} (${step.type}) needs a target element.` });
263
+ if (!step.title && !step.body && step.type !== "custom") issues.push({ level: "warning", stepId: step.id, message: `Step ${i + 1} has no title or body.` });
264
+ if (step.buttons.length === 0 && step.advanceOn === "button" && step.type !== "hotspot" && step.type !== "custom") issues.push({ level: "warning", stepId: step.id, message: `Step ${i + 1} has no buttons and advances on button; users can only close it.` });
265
+ step.buttons.forEach((b) => {
266
+ if (b.action === "url" && !/^https?:\/\//i.test(b.value || "") && !(b.value || "").startsWith("/")) issues.push({ level: "error", stepId: step.id, message: `Button "${b.label}" needs an http(s) or relative URL.` });
267
+ if (b.action === "start_guide" && !b.value) issues.push({ level: "error", stepId: step.id, message: `Button "${b.label}" needs a guide to start.` });
268
+ });
269
+ step.branches.forEach((br) => {
270
+ if (!ids.has(br.goTo) && !config.steps.some((s) => s.id === br.goTo)) issues.push({ level: "error", stepId: step.id, message: `Branch points to unknown step "${br.goTo}".` });
271
+ });
272
+ });
273
+ if (config.trigger.type === "event" && !config.trigger.value) issues.push({ level: "error", message: "Event trigger needs an event name." });
274
+ if (config.trigger.type === "element_click" && !config.trigger.value) issues.push({ level: "error", message: "Element click trigger needs a selector." });
275
+ if (config.trigger.type === "url_match" && !config.trigger.value) issues.push({ level: "error", message: "URL trigger needs a pattern." });
276
+ if (config.frequency.mode === "interval" && !config.frequency.intervalHours) issues.push({ level: "error", message: "Interval frequency needs an interval in hours." });
277
+ return issues;
278
+ }
279
+ var ProjectThemeSchema = z2.object({
280
+ primaryColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).default("#4f46e5"),
281
+ backgroundColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).default("#ffffff"),
282
+ textColor: z2.string().regex(/^#[0-9a-fA-F]{6}$/).default("#111827"),
283
+ borderRadius: z2.number().int().min(0).max(32).default(12),
284
+ fontFamily: z2.string().max(200).default("Inter, system-ui, -apple-system, sans-serif"),
285
+ logoUrl: z2.string().max(2e3).optional(),
286
+ brandName: z2.string().max(100).optional()
287
+ });
288
+
289
+ // src/events.ts
290
+ import { z as z3 } from "zod";
291
+ var EVENT_NAMES = [
292
+ "guide_viewed",
293
+ "guide_started",
294
+ "step_viewed",
295
+ "step_completed",
296
+ "guide_completed",
297
+ "guide_skipped",
298
+ "guide_dismissed",
299
+ "guide_abandoned",
300
+ "checklist_task_completed",
301
+ "checklist_completed",
302
+ "checklist_dismissed",
303
+ "survey_displayed",
304
+ "survey_submitted",
305
+ "survey_dismissed",
306
+ "resource_center_opened",
307
+ "article_viewed",
308
+ "messenger_opened",
309
+ "conversation_started",
310
+ "conversation_handed_off",
311
+ "scout_answered",
312
+ "custom",
313
+ "page_view",
314
+ "identify"
315
+ ];
316
+ var GUIDE_LIFECYCLE_EVENTS = ["guide_viewed", "guide_started", "step_viewed", "step_completed", "guide_completed", "guide_skipped", "guide_dismissed", "guide_abandoned"];
317
+ var SdkEventSchema = z3.object({
318
+ eventId: z3.string().min(8).max(64),
319
+ name: z3.enum(EVENT_NAMES),
320
+ /** For `custom` events: the application-defined name. */
321
+ customName: z3.string().min(1).max(120).optional(),
322
+ occurredAt: z3.string().datetime({ offset: true }),
323
+ anonymousId: z3.string().min(1).max(128),
324
+ userId: z3.string().max(256).optional().nullable(),
325
+ accountId: z3.string().max(256).optional().nullable(),
326
+ sessionId: z3.string().max(128).optional(),
327
+ guideId: z3.string().max(64).optional(),
328
+ guideVersion: z3.number().int().optional(),
329
+ stepId: z3.string().max(64).optional(),
330
+ stepIndex: z3.number().int().min(0).optional(),
331
+ url: z3.string().max(2e3).optional(),
332
+ properties: z3.record(z3.unknown()).optional()
333
+ });
334
+ var EventBatchSchema = z3.object({
335
+ events: z3.array(SdkEventSchema).min(1).max(50),
336
+ sentAt: z3.string().datetime({ offset: true }).optional(),
337
+ sdk: z3.object({ name: z3.string().max(60), version: z3.string().max(30) }).optional()
338
+ });
339
+
340
+ // src/sdk-api.ts
341
+ import { z as z4 } from "zod";
342
+ var IdentifyRequestSchema = z4.object({
343
+ anonymousId: z4.string().min(1).max(128),
344
+ userId: z4.string().min(1).max(256).optional().nullable(),
345
+ traits: z4.record(z4.unknown()).optional(),
346
+ account: z4.object({ id: z4.string().min(1).max(256), traits: z4.record(z4.unknown()).optional() }).optional().nullable(),
347
+ sessionId: z4.string().max(128).optional(),
348
+ url: z4.string().max(2e3).optional()
349
+ });
350
+ var ChecklistProgressRequestSchema = z4.object({
351
+ anonymousId: z4.string().min(1).max(128),
352
+ userId: z4.string().max(256).optional().nullable(),
353
+ guideVersion: z4.number().int().optional(),
354
+ completedTaskIds: z4.array(z4.string().max(64)).max(100),
355
+ dismissed: z4.boolean().optional(),
356
+ completed: z4.boolean().optional()
357
+ });
358
+ var SurveyResponseRequestSchema = z4.object({
359
+ anonymousId: z4.string().min(1).max(128),
360
+ userId: z4.string().max(256).optional().nullable(),
361
+ accountId: z4.string().max(256).optional().nullable(),
362
+ guideVersion: z4.number().int(),
363
+ answers: z4.record(z4.union([z4.string().max(5e3), z4.number(), z4.boolean(), z4.array(z4.string().max(500)).max(50)])),
364
+ responseId: z4.string().min(8).max(64)
365
+ });
366
+ var GuideStateUpdateSchema = z4.object({
367
+ anonymousId: z4.string().min(1).max(128),
368
+ userId: z4.string().max(256).optional().nullable(),
369
+ updates: z4.array(
370
+ z4.object({
371
+ guideId: z4.string(),
372
+ impression: z4.boolean().optional(),
373
+ completed: z4.boolean().optional(),
374
+ dismissed: z4.boolean().optional()
375
+ })
376
+ ).max(50)
377
+ });
378
+ var AuthoringPickSchema = z4.object({
379
+ stepId: z4.string().max(64).optional(),
380
+ selectors: z4.array(z4.object({ kind: z4.string(), value: z4.string().max(1e3), label: z4.string().max(200).optional() })).max(10),
381
+ textSnapshot: z4.string().max(200).optional(),
382
+ url: z4.string().max(2e3).optional(),
383
+ rect: z4.object({ x: z4.number(), y: z4.number(), width: z4.number(), height: z4.number() }).optional()
384
+ });
385
+ var PublishedGuideSchema = z4.object({
386
+ id: z4.string(),
387
+ key: z4.string(),
388
+ name: z4.string(),
389
+ kind: z4.string(),
390
+ version: z4.number(),
391
+ config: GuideConfigSchema,
392
+ publishedAt: z4.string()
393
+ });
394
+
395
+ // src/messenger.ts
396
+ import { z as z5 } from "zod";
397
+ var MESSAGE_AUTHORS = ["user", "scout", "agent", "system"];
398
+ var MAX_MESSAGE_LENGTH = 4e3;
399
+ var messageText = z5.string().trim().min(1).max(MAX_MESSAGE_LENGTH);
400
+ var StartConversationSchema = z5.object({
401
+ anonymousId: z5.string().min(1).max(128),
402
+ userId: z5.string().max(256).optional().nullable(),
403
+ message: messageText,
404
+ pageUrl: z5.string().max(2e3).optional()
405
+ });
406
+ var ConversationLookupSchema = z5.object({
407
+ tokens: z5.array(z5.string().min(16).max(128)).max(50)
408
+ });
409
+ var PostMessageSchema = z5.object({ message: messageText });
410
+ var ConversationRatingSchema = z5.object({
411
+ rating: z5.number().int().min(1).max(5),
412
+ comment: z5.string().max(1e3).optional()
413
+ });
414
+
415
+ // src/templates.ts
416
+ var nav = (opts = {}) => [
417
+ ...opts.first ? [] : [{ id: "back", label: "Back", action: "back", variant: "ghost" }],
418
+ opts.last ? { id: "done", label: "Finish", action: "complete", variant: "primary" } : { id: "next", label: "Next", action: "next", variant: "primary" }
419
+ ];
420
+ var GUIDE_TEMPLATES = [
421
+ {
422
+ id: "new-user-onboarding",
423
+ name: "New-user onboarding tour",
424
+ description: "A welcome modal followed by three anchored steps that introduce the main navigation.",
425
+ kind: "flow",
426
+ category: "onboarding",
427
+ config: {
428
+ steps: [
429
+ { id: "welcome", type: "modal", title: "Welcome aboard \u{1F44B}", body: "<p>We'll show you around in under a minute. You can skip at any time.</p>", showOverlay: true, buttons: [{ id: "skip", label: "Skip tour", action: "dismiss", variant: "ghost" }, { id: "start", label: "Show me around", action: "next" }] },
430
+ { id: "nav", type: "tooltip", title: "Your navigation", body: "<p>Everything lives in the sidebar. Switch between dashboards, contacts and settings here.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='sidebar']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "right", buttons: nav() },
431
+ { id: "create", type: "spotlight", title: "Create your first record", body: "<p>Use the primary button to add something new. We'll highlight it for you.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='primary-action']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "bottom", showOverlay: true, buttons: nav() },
432
+ { id: "help", type: "tooltip", title: "Need help later?", body: "<p>Open the help menu any time to replay this tour or browse the resource center.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='help']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "bottom", buttons: nav({ last: true }) }
433
+ ],
434
+ trigger: { type: "page_load" },
435
+ frequency: { mode: "once", priority: 10 },
436
+ targeting: { id: "root", op: "and", rules: [{ id: "r1", field: "visitor.firstVisit", op: "is_true" }] }
437
+ }
438
+ },
439
+ {
440
+ id: "feature-discovery",
441
+ name: "First-time feature discovery",
442
+ description: "A hotspot that draws attention to a new capability and expands into a tooltip.",
443
+ kind: "tooltip",
444
+ category: "feature",
445
+ config: {
446
+ steps: [{ id: "hotspot", type: "hotspot", title: "New: smart filters", body: "<p>Filters now understand natural language. Try <em>\u201Cdeals closing this month\u201D</em>.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='filters']" }], waitMs: 8e3, fallback: "skip", scrollIntoView: true }, placement: "bottom", buttons: [{ id: "got-it", label: "Got it", action: "complete" }], hotspot: { size: 14, pulse: true, openOn: "click" }, showProgress: false }],
447
+ trigger: { type: "element_visible", value: "[data-tour='filters']" },
448
+ frequency: { mode: "once", maxImpressions: 3, priority: 50 }
449
+ }
450
+ },
451
+ {
452
+ id: "setup-wizard",
453
+ name: "Setup wizard",
454
+ description: "Multi-step modal wizard that walks a new admin through initial configuration with branching.",
455
+ kind: "flow",
456
+ category: "setup",
457
+ config: {
458
+ steps: [
459
+ { id: "intro", type: "modal", title: "Let's set up your workspace", body: "<p>Three quick steps: invite your team, connect a data source, and choose a plan.</p>", showOverlay: true, buttons: [{ id: "later", label: "Later", action: "dismiss", variant: "ghost" }, { id: "go", label: "Start setup", action: "next" }] },
460
+ { id: "team", type: "popover", title: "Invite teammates", body: "<p>Guidely works best with your whole team. Add a few emails here.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='invite']" }], waitMs: 5e3, fallback: "show_as_modal", scrollIntoView: true }, buttons: nav() },
461
+ { id: "data", type: "popover", title: "Connect a data source", body: "<p>Import contacts from a CSV or connect your CRM.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='import']" }], waitMs: 5e3, fallback: "show_as_modal", scrollIntoView: true }, buttons: nav() },
462
+ { id: "done", type: "modal", title: "You're ready \u{1F389}", body: "<p>That's it. Explore the dashboard, and open the help menu if you get stuck.</p>", showOverlay: true, buttons: nav({ last: true }) }
463
+ ],
464
+ trigger: { type: "page_load", urlPattern: "/dashboard" },
465
+ frequency: { mode: "once", priority: 20 },
466
+ targeting: { id: "root", op: "and", rules: [{ id: "r1", field: "user.role", op: "equals", value: "admin" }] }
467
+ }
468
+ },
469
+ {
470
+ id: "form-completion",
471
+ name: "Form completion helper",
472
+ description: "Tooltips that advance as the user fills out each field of a form.",
473
+ kind: "flow",
474
+ category: "forms",
475
+ config: {
476
+ steps: [
477
+ { id: "name", type: "tooltip", title: "Name the contact", body: "<p>Use their full name so search works well.</p>", target: { selectors: [{ kind: "css", value: "input[name='name']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "right", advanceOn: "element_click", advanceValue: "input[name='email']", buttons: [] },
478
+ { id: "email", type: "tooltip", title: "Add an email", body: "<p>We'll use it for sequences and reminders.</p>", target: { selectors: [{ kind: "css", value: "input[name='email']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "right", buttons: nav() },
479
+ { id: "save", type: "spotlight", title: "Save", body: "<p>Hit save, and your contact appears in the list.</p>", target: { selectors: [{ kind: "css", value: "button[type='submit']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "top", showOverlay: true, buttons: nav({ last: true }) }
480
+ ],
481
+ trigger: { type: "url_match", value: "/contacts/new" },
482
+ frequency: { mode: "once", priority: 40 }
483
+ }
484
+ },
485
+ {
486
+ id: "workflow-walkthrough",
487
+ name: "Complex workflow walkthrough",
488
+ description: "A multi-page flow that follows the user across routes with URL-aware steps.",
489
+ kind: "flow",
490
+ category: "onboarding",
491
+ config: {
492
+ steps: [
493
+ { id: "start", type: "modal", title: "Close your first deal", body: "<p>We'll go from pipeline to closed-won in four steps.</p>", showOverlay: true, buttons: [{ id: "skip", label: "Not now", action: "dismiss", variant: "ghost" }, { id: "next", label: "Let's go", action: "next" }] },
494
+ { id: "pipeline", type: "tooltip", title: "Open the pipeline", body: "<p>Click here to see your deals by stage.</p>", url: "/dashboard", target: { selectors: [{ kind: "data-attr", value: "[data-tour='nav-deals']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "right", advanceOn: "element_click", advanceValue: "[data-tour='nav-deals']", buttons: [] },
495
+ { id: "drag", type: "spotlight", title: "Move a deal", body: "<p>Drag a card to the next stage, or use the stage menu.</p>", url: "/deals", target: { selectors: [{ kind: "data-attr", value: "[data-tour='deal-card']" }], waitMs: 8e3, fallback: "skip", scrollIntoView: true }, placement: "bottom", showOverlay: true, buttons: nav() },
496
+ { id: "won", type: "tooltip", title: "Mark as won", body: "<p>When it closes, mark it won to update your forecast.</p>", url: "/deals", target: { selectors: [{ kind: "data-attr", value: "[data-tour='mark-won']" }], waitMs: 8e3, fallback: "skip", scrollIntoView: true }, placement: "left", buttons: nav({ last: true }) }
497
+ ],
498
+ trigger: { type: "manual" },
499
+ frequency: { mode: "every_time", priority: 30 }
500
+ }
501
+ },
502
+ {
503
+ id: "feature-announcement",
504
+ name: "New feature announcement",
505
+ description: "A centered modal with an image announcing a new capability.",
506
+ kind: "announcement",
507
+ category: "announcement",
508
+ config: {
509
+ steps: [{ id: "announce", type: "modal", title: "Introducing Reports 2.0", body: "<p>Build custom reports with drag-and-drop metrics, scheduled emails and shareable links.</p><ul><li>12 new chart types</li><li>Export to CSV and PDF</li></ul>", imageUrl: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=60", showOverlay: true, buttons: [{ id: "later", label: "Maybe later", action: "dismiss", variant: "ghost" }, { id: "try", label: "Try it now", action: "url", value: "/reports" }], showProgress: false }],
510
+ trigger: { type: "page_load", delayMs: 1500 },
511
+ frequency: { mode: "once", priority: 60 }
512
+ }
513
+ },
514
+ {
515
+ id: "contextual-tooltip",
516
+ name: "Contextual tooltip",
517
+ description: "A single tooltip that appears when a specific element becomes visible.",
518
+ kind: "tooltip",
519
+ category: "help",
520
+ config: {
521
+ steps: [{ id: "tip", type: "tooltip", title: "Pro tip", body: "<p>Press <strong>\u2318K</strong> to jump anywhere.</p>", target: { selectors: [{ kind: "data-attr", value: "[data-tour='search']" }], waitMs: 5e3, fallback: "skip", scrollIntoView: true }, placement: "bottom", buttons: [{ id: "ok", label: "Got it", action: "complete" }], showProgress: false }],
522
+ trigger: { type: "element_visible", value: "[data-tour='search']", delayMs: 500 },
523
+ frequency: { mode: "once", priority: 80 }
524
+ }
525
+ },
526
+ {
527
+ id: "product-update-banner",
528
+ name: "Product update notification",
529
+ description: "A dismissible top banner linking to release notes.",
530
+ kind: "banner",
531
+ category: "announcement",
532
+ config: {
533
+ steps: [{ id: "banner", type: "banner", title: "", body: "<p><strong>Scheduled maintenance</strong> on Saturday 02:00\u201303:00 UTC. <a href='/status'>Read more</a>.</p>", position: "top", placement: "top", buttons: [{ id: "dismiss", label: "Dismiss", action: "dismiss", variant: "ghost" }], showProgress: false }],
534
+ trigger: { type: "page_load" },
535
+ frequency: { mode: "once_per_session", priority: 90 }
536
+ }
537
+ },
538
+ {
539
+ id: "onboarding-checklist",
540
+ name: "User onboarding checklist",
541
+ description: "A persistent checklist with four tasks that complete automatically from events.",
542
+ kind: "checklist",
543
+ category: "onboarding",
544
+ config: {
545
+ steps: [],
546
+ checklist: {
547
+ tasks: [
548
+ { id: "profile", title: "Complete your profile", description: "Add a photo and your role.", completion: "event", completionValue: "profile_completed", action: "url", actionValue: "/settings/profile" },
549
+ { id: "contact", title: "Add your first contact", description: "Import or create a contact.", completion: "event", completionValue: "contact_created", action: "url", actionValue: "/contacts/new" },
550
+ { id: "deal", title: "Create a deal", description: "Track your first opportunity.", completion: "event", completionValue: "deal_created", action: "url", actionValue: "/deals" },
551
+ { id: "tour", title: "Take the product tour", description: "A 60-second walkthrough.", completion: "guide_completed", completionValue: "new-user-onboarding", action: "start_guide", actionValue: "new-user-onboarding", required: false }
552
+ ],
553
+ ordered: false,
554
+ launcherLabel: "Getting started",
555
+ position: "bottom-right",
556
+ completionTitle: "You're all set! \u{1F389}",
557
+ completionBody: "You've completed onboarding. Explore the rest of the app at your own pace.",
558
+ autoOpen: true,
559
+ dismissible: true
560
+ },
561
+ trigger: { type: "page_load" },
562
+ frequency: { mode: "every_time", priority: 200 }
563
+ }
564
+ },
565
+ {
566
+ id: "nps-survey",
567
+ name: "NPS survey",
568
+ description: "Net Promoter Score with a conditional follow-up question.",
569
+ kind: "survey",
570
+ category: "feedback",
571
+ config: {
572
+ steps: [],
573
+ survey: {
574
+ questions: [
575
+ { id: "nps", type: "nps", title: "How likely are you to recommend us to a colleague?", lowLabel: "Not likely", highLabel: "Very likely" },
576
+ { id: "why-low", type: "text", title: "What could we do better?", required: false, placeholder: "Tell us more\u2026", showWhen: { questionId: "nps", op: "lte", value: 6 } },
577
+ { id: "why-high", type: "text", title: "What do you like most?", required: false, placeholder: "Tell us more\u2026", showWhen: { questionId: "nps", op: "gte", value: 9 } }
578
+ ],
579
+ position: "bottom-right"
580
+ },
581
+ trigger: { type: "page_load", delayMs: 5e3 },
582
+ frequency: { mode: "interval", intervalHours: 2160, priority: 150 },
583
+ targeting: { id: "root", op: "and", rules: [{ id: "r1", field: "visitor.returning", op: "is_true" }] }
584
+ }
585
+ }
586
+ ];
587
+ function templateConfig(id) {
588
+ const t = GUIDE_TEMPLATES.find((x) => x.id === id);
589
+ if (!t) return null;
590
+ return { template: t, config: GuideConfigSchema.parse(t.config) };
591
+ }
592
+
593
+ // src/index.ts
594
+ var SDK_API_VERSION = "v1";
595
+ var SHARED_VERSION = "0.2.0";
596
+ export {
597
+ ADVANCE_ON,
598
+ AppearanceSchema,
599
+ AuthoringPickSchema,
600
+ BUTTON_ACTIONS,
601
+ ButtonSchema,
602
+ ChecklistConfigSchema,
603
+ ChecklistProgressRequestSchema,
604
+ ChecklistTaskSchema,
605
+ ConversationLookupSchema,
606
+ ConversationRatingSchema,
607
+ EVENT_NAMES,
608
+ EventBatchSchema,
609
+ FrequencySchema,
610
+ GUIDE_KINDS,
611
+ GUIDE_LIFECYCLE_EVENTS,
612
+ GUIDE_STATUSES,
613
+ GUIDE_TEMPLATES,
614
+ GuideConfigSchema,
615
+ GuideStateUpdateSchema,
616
+ IdentifyRequestSchema,
617
+ MAX_MESSAGE_LENGTH,
618
+ MAX_PROPERTY_BYTES,
619
+ MESSAGE_AUTHORS,
620
+ PLACEMENTS,
621
+ PostMessageSchema,
622
+ ProjectThemeSchema,
623
+ PublishedGuideSchema,
624
+ RULE_FIELDS,
625
+ RULE_OPERATORS,
626
+ RuleGroupSchema,
627
+ RuleSchema,
628
+ SDK_API_VERSION,
629
+ SELECTOR_KINDS,
630
+ SENSITIVE_PROPERTY_PATTERN,
631
+ SERVER_ASSISTED_FIELDS,
632
+ SHARED_VERSION,
633
+ STEP_TYPES,
634
+ SURVEY_QUESTION_TYPES,
635
+ SdkEventSchema,
636
+ SelectorStrategySchema,
637
+ StartConversationSchema,
638
+ StepBranchSchema,
639
+ StepSchema,
640
+ SurveyConfigSchema,
641
+ SurveyQuestionSchema,
642
+ SurveyResponseRequestSchema,
643
+ TRIGGER_TYPES,
644
+ TargetSchema,
645
+ TriggerSchema,
646
+ clamp,
647
+ compare,
648
+ defaultGuideConfig,
649
+ defaultStep,
650
+ describeRule,
651
+ emptyRuleGroup,
652
+ evaluateRule,
653
+ evaluateRules,
654
+ fnv1a,
655
+ getPath,
656
+ isPlainObject,
657
+ isRuleGroup,
658
+ matchUrlPattern,
659
+ randomId,
660
+ rolloutBucket,
661
+ safeRegExp,
662
+ sanitizeProperties,
663
+ slugify,
664
+ stripOrigin,
665
+ templateConfig,
666
+ validateGuideConfig,
667
+ visibleButtons
668
+ };
669
+ //# sourceMappingURL=index.js.map