saasco-sdk 0.1.45 → 0.2.4

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.
@@ -0,0 +1,535 @@
1
+ import { z } from 'zod';
2
+
3
+ declare enum LogLevel {
4
+ ERROR = 0,
5
+ WARN = 1,
6
+ INFO = 2,
7
+ DEBUG = 3
8
+ }
9
+
10
+ type EventType = "identify" | "track";
11
+ type AnalyticsContext = {
12
+ distinctId?: string | null;
13
+ anonymousId?: string | null;
14
+ sessionId?: string | null;
15
+ [key: string]: unknown;
16
+ };
17
+ type EventEnvelope = {
18
+ id: string;
19
+ type: EventType;
20
+ timestamp: number;
21
+ name?: string;
22
+ properties?: Record<string, unknown>;
23
+ context: AnalyticsContext;
24
+ };
25
+ type IntegrationEnvironment = "client" | "server";
26
+ type Integration = {
27
+ /**
28
+ * The name of the integration
29
+ */
30
+ name: string;
31
+ /**
32
+ * The environments where this integration can run
33
+ */
34
+ environments: IntegrationEnvironment[];
35
+ /**
36
+ * The function to initialize the integration
37
+ */
38
+ init?: (context?: AnalyticsContext) => Promise<void> | void;
39
+ /**
40
+ * The function to track an event
41
+ */
42
+ track?: (name: string, properties?: Record<string, unknown>, context?: AnalyticsContext) => void;
43
+ /**
44
+ * The function to identify a user
45
+ */
46
+ identify?: (userId?: string | null, properties?: Record<string, unknown>, context?: AnalyticsContext) => void | Promise<void>;
47
+ };
48
+ type IntegrationStatus = "idle" | "loading" | "ready" | "error";
49
+ type IntegrationState = {
50
+ integration: Integration;
51
+ status: IntegrationStatus;
52
+ };
53
+ type ManagerConfig = {
54
+ /**
55
+ * Enable logger level
56
+ */
57
+ loggerLevel?: LogLevel;
58
+ /**
59
+ * Max queue size, once it exceeds this number, the oldest event will be dropped
60
+ */
61
+ maxQueueSize?: number;
62
+ /**
63
+ * Max integration wait time, this is how long we will wait for an integration to be ready before flushing the queue. If an integration is not ready after this time it will miss any previous events.
64
+ */
65
+ maxIntegrationWaitTime?: number;
66
+ /**
67
+ * Periodic flush interval in milliseconds. Set to 0 to disable periodic flushing.
68
+ */
69
+ flushInterval?: number;
70
+ };
71
+ declare class IntegrationManager {
72
+ private context;
73
+ private integrations;
74
+ private globalQueue;
75
+ private config;
76
+ private logger;
77
+ private initTime;
78
+ private currentEnvironment;
79
+ private flushTimer?;
80
+ private unloadHandler?;
81
+ constructor(config?: ManagerConfig);
82
+ /**
83
+ * Shallow-merge context to keep it simple + predictable in v0
84
+ */
85
+ setContext(next: Partial<AnalyticsContext>): void;
86
+ /**
87
+ * Register and init an integration. When init resolves, we mark it ready and
88
+ * immediately flush any queued events in FIFO order to *all* ready integrations.
89
+ */
90
+ registerIntegration(integration: Integration): Promise<void>;
91
+ identify(userId?: string | null, traits?: Record<string, unknown>): void;
92
+ track(name: string, properties?: Record<string, unknown>): void;
93
+ /**
94
+ * Core send path: if at least one integration is ready -> deliver immediately
95
+ * Else enqueue (bounded FIFO)
96
+ */
97
+ private send;
98
+ private deliver;
99
+ /**
100
+ * Flush queued events FIFO once at least one integration is ready.
101
+ */
102
+ private flush;
103
+ private readyCount;
104
+ private isReady;
105
+ /**
106
+ * Setup periodic flushing if enabled
107
+ */
108
+ private setupPeriodicFlushing;
109
+ /**
110
+ * Setup page unload handler for client environment
111
+ */
112
+ private setupUnloadHandler;
113
+ /** Debug helpers */
114
+ getStats(): {
115
+ context: AnalyticsContext;
116
+ currentEnvironment: IntegrationEnvironment;
117
+ flushInterval: number;
118
+ integrations: {
119
+ environments: IntegrationEnvironment[];
120
+ name: string;
121
+ status: IntegrationStatus;
122
+ }[];
123
+ periodicFlushEnabled: boolean;
124
+ queueLength: number;
125
+ readyCount: number;
126
+ };
127
+ }
128
+
129
+ type IntegrationConfigBase = {
130
+ type: string;
131
+ config: Record<string, any>;
132
+ debug?: boolean;
133
+ };
134
+
135
+ declare global {
136
+ interface Window {
137
+ fbq?: Fbq;
138
+ _fbq?: Fbq;
139
+ }
140
+ interface Fbq {
141
+ (...args: unknown[]): void;
142
+ queue?: unknown[];
143
+ loaded?: boolean;
144
+ version?: string;
145
+ disablePushState?: boolean;
146
+ allowDuplicatePageViews?: boolean;
147
+ }
148
+ }
149
+ type FacebookEventMapping = Record<string, StandardFacebookEvent>;
150
+ type FacebookPixelIntegrationConfig = IntegrationConfigBase & {
151
+ type: "facebook-pixel";
152
+ config: FacebookPixelConfig;
153
+ };
154
+ type FacebookPixelConfig = {
155
+ pixelId: string;
156
+ eventMapping?: FacebookEventMapping;
157
+ automaticConfiguration?: boolean;
158
+ };
159
+ declare const standardFacebookEvents: readonly ["AddPaymentInfo", "AddToCart", "AddToWishlist", "CompleteRegistration", "Contact", "CustomizeProduct", "Donate", "FindLocation", "InitiateCheckout", "Lead", "Purchase", "Schedule", "Search", "StartTrial", "SubmitApplication", "Subscribe", "ViewContent", "PageView"];
160
+ type StandardFacebookEvent = (typeof standardFacebookEvents)[number];
161
+ /**
162
+ * Create a Facebook Pixel integration instance
163
+ */
164
+ declare function createFacebookPixelIntegration(config: FacebookPixelConfig, debug?: boolean): Integration;
165
+
166
+ declare global {
167
+ interface Window {
168
+ pintrk?: Pintrk;
169
+ _pintrk?: Pintrk;
170
+ }
171
+ interface Pintrk {
172
+ (...args: unknown[]): void;
173
+ queue?: unknown[];
174
+ loaded?: boolean;
175
+ version?: string;
176
+ }
177
+ }
178
+ type PinterestEventMapping = Record<string, StandardPinterestEvent>;
179
+ type PinterestTagIntegrationConfig = IntegrationConfigBase & {
180
+ type: "pinterest-tag";
181
+ config: PinterestTagConfig;
182
+ };
183
+ type PinterestTagConfig = {
184
+ tagId: string;
185
+ eventMapping?: PinterestEventMapping;
186
+ automaticConfiguration?: boolean;
187
+ };
188
+ /**
189
+ * Standard Pinterest events
190
+ * Reference: https://www.pinterest.com/_/_/help/business/article/event-code
191
+ */
192
+ declare const standardPinterestEvents: readonly ["checkout", "addtocart", "pagevisit", "signup", "watchvideo", "lead", "search", "viewcategory", "custom", "addpaymentinfo", "addtowishlist", "initiatecheckout", "subscribe", "viewcontent"];
193
+ type StandardPinterestEvent = (typeof standardPinterestEvents)[number];
194
+ /**
195
+ * Create a Pinterest Tag integration instance
196
+ * Documentation: https://help.pinterest.com/en/business/article/install-the-pinterest-tag
197
+ */
198
+ declare function createPinterestTagIntegration(config: PinterestTagConfig, debug?: boolean): Integration;
199
+
200
+ /**
201
+ * TikTok Pixel Integration
202
+ *
203
+ * This integration provides TikTok Pixel tracking capabilities including:
204
+ * - Event tracking for standard and custom events
205
+ * - Advanced matching with hashed user identification data
206
+ * - Automatic script loading and initialization
207
+ *
208
+ * Key Resources:
209
+ * - Advanced Matching: https://business-api.tiktok.com/portal/docs?rid=5ipocbxyw8v&id=1739585700402178
210
+ * - Standard Events: https://business-api.tiktok.com/portal/docs?id=1771101186666498
211
+ */
212
+
213
+ declare global {
214
+ interface Window {
215
+ ttq?: Ttq;
216
+ TiktokAnalyticsObject?: string;
217
+ }
218
+ interface Ttq {
219
+ (...args: unknown[]): void;
220
+ methods?: string[];
221
+ _i?: Record<string, unknown>;
222
+ _t?: Record<string, number>;
223
+ _o?: Record<string, unknown>;
224
+ load?: (pixelId: string, options?: Record<string, unknown>) => void;
225
+ page?: () => void;
226
+ track?: (eventName: string, properties?: Record<string, unknown>) => void;
227
+ identify?: (properties?: Record<string, unknown>) => void;
228
+ setAndDefer?: (obj: Record<string, unknown>, method: string) => void;
229
+ instance?: (pixelId: string) => Ttq;
230
+ }
231
+ }
232
+ type TikTokEventMapping = Record<string, StandardTikTokEvent>;
233
+ type TikTokPixelIntegrationConfig = IntegrationConfigBase & {
234
+ type: "tiktok-pixel";
235
+ config: TikTokPixelConfig;
236
+ };
237
+ type TikTokPixelConfig = {
238
+ pixelId: string;
239
+ eventMapping?: TikTokEventMapping;
240
+ testMode?: boolean;
241
+ };
242
+ /**
243
+ * Standard TikTok events supported by the pixel
244
+ *
245
+ * Note: This list reflects TikTok's official standard events. Events like 'CompletePayment'
246
+ * are not standard events and should be tracked as custom events if needed.
247
+ *
248
+ * Documentation: https://business-api.tiktok.com/portal/docs?id=1771101186666498
249
+ */
250
+ declare const standardTikTokEvents: readonly ["AddPaymentInfo", "AddToCart", "AddToWishlist", "ApplicationApproval", "CompleteRegistration", "Contact", "CustomizeProduct", "Download", "FindLocation", "InitiateCheckout", "Lead", "Purchase", "Schedule", "Search", "StartTrial", "SubmitApplication", "Subscribe", "ViewContent", "PageView"];
251
+ type StandardTikTokEvent = (typeof standardTikTokEvents)[number];
252
+ /**
253
+ * Create a TikTok Pixel integration instance
254
+ */
255
+ declare function createTikTokPixelIntegration(config: TikTokPixelConfig, debug?: boolean): Integration;
256
+
257
+ declare global {
258
+ interface Window {
259
+ saascoAutoPageTrackingActive?: boolean;
260
+ saasco: Saasco;
261
+ saascoLastIdentifyKey?: string;
262
+ /** Set once the lazy-loaded support script has been injected. */
263
+ __saascoSupportInjected?: boolean;
264
+ /** Set once the lazy-loaded social-proof loader script has been injected. */
265
+ __saascoSocialProofInjected?: boolean;
266
+ }
267
+ }
268
+ type Identity = {
269
+ userId: string | number;
270
+ anonymousId?: string | number;
271
+ } | {
272
+ anonymousId: string | number;
273
+ userId?: string | number;
274
+ };
275
+ type Context = {
276
+ active?: boolean;
277
+ };
278
+ type TrackPayload = Identity & {
279
+ event: string;
280
+ sessionId?: string;
281
+ properties?: Record<string, any>;
282
+ context?: Context;
283
+ };
284
+ type DoRequestResponse = {
285
+ success: boolean;
286
+ message: string;
287
+ };
288
+ type IntegrationsConfig = (FacebookPixelIntegrationConfig | PinterestTagIntegrationConfig | TikTokPixelIntegrationConfig)[];
289
+ /**
290
+ * Opt-in config for the support widget, set on the `Saasco` constructor.
291
+ * The widget is a cross-origin iframe loaded by a lean host-page loader
292
+ * (`saasco-support-loader.js`); no React ships in this analytics entry,
293
+ * which stays React-free by lazily injecting the loader rather than importing
294
+ * it. Providing this object opts in; pass `enabled: false` to keep it off (e.g.
295
+ * behind your own runtime flag). The projectId is shared from the analytics
296
+ * config — you never declare it twice.
297
+ */
298
+ type SupportInit = {
299
+ /** Defaults to `true` when the `support` object is provided. */
300
+ enabled?: boolean;
301
+ /** Origin of the saasco app hosting the support API. Defaults server-side to where the widget bundle is served from. */
302
+ baseUrl?: string;
303
+ /** Input placeholder for the chat composer. */
304
+ placeholder?: string;
305
+ /**
306
+ * URL the loader is loaded from. Accepts either the analytics
307
+ * `saasco-sdk.js` URL (the loader URL is derived from it) or the
308
+ * `saasco-support-loader.js` URL directly. Defaults to deriving from the
309
+ * loaded analytics `<script>` tag, so CDN installs can omit it.
310
+ */
311
+ scriptUrl?: string;
312
+ };
313
+ /**
314
+ * Optional config for the Social Proof widget. Social proof is **always
315
+ * available wherever the analytics SDK runs** — you don't need to pass this
316
+ * object at all. Whether the widget actually renders is decided
317
+ * **server-side**: on init the SDK runs a cheap widget-payload check and lazily
318
+ * injects the dependency-free loader (`saasco-social-proof-loader.js`, ~71 KB
319
+ * gzipped) only when the project has the app enabled in the dashboard, so
320
+ * pages where it's off never download it — and the dashboard toggle controls
321
+ * every install (CDN and npm) uniformly.
322
+ *
323
+ * The loader + widget-payload origin is resolved automatically: the CDN
324
+ * `<script>` origin for CDN installs, else the public Saasco CDN for
325
+ * npm/bundled installs (which carry no script tag on the page). Pass this object
326
+ * only to override those defaults or to opt out: `enabled: false` (or
327
+ * `data-social-proof-enabled="false"` on the CDN tag) is a client kill-switch
328
+ * that skips the check entirely; `baseUrl`/`scriptUrl` point a same-origin,
329
+ * proxied, or self-hosted install at the right origin. The projectId is shared
330
+ * from the analytics config — you never declare it twice.
331
+ */
332
+ type SocialProofInit = {
333
+ /**
334
+ * Client kill-switch. Defaults to `true`. When `false`, the SDK skips the
335
+ * server check and never injects the loader, regardless of the dashboard
336
+ * setting.
337
+ */
338
+ enabled?: boolean;
339
+ /**
340
+ * Origin of the saasco app hosting the social-proof widget-payload API.
341
+ * Defaults to the loader bundle's origin — the CDN `<script>` origin for CDN
342
+ * installs, else the public Saasco CDN for npm/bundled installs.
343
+ */
344
+ baseUrl?: string;
345
+ /**
346
+ * URL the loader is loaded from. Accepts either the analytics
347
+ * `saasco-sdk.js` URL (the loader URL is derived from it) or the
348
+ * `saasco-social-proof-loader.js` URL directly. Defaults to deriving from
349
+ * the loaded analytics `<script>` tag, so CDN installs can omit it.
350
+ */
351
+ scriptUrl?: string;
352
+ };
353
+ declare class Saasco {
354
+ private config;
355
+ private lastPageViewPath;
356
+ private isInitialized;
357
+ private integrationManager;
358
+ private logger;
359
+ private lastSupportIdentity;
360
+ /**
361
+ * Creates an instance of the Saasco SDK.
362
+ * @param config Configuration options.
363
+ * @param config.projectId The unique identifier for the project.
364
+ * @param config.proxy The URL of the proxy server to use, if any.
365
+ * @param config.autoPageTracking Whether to automatically track page views. Default is false.
366
+ * @param config.enabled Whether analytics is enabled. Default is true. Set to false for development and staging envioronments. Will still allow debug mode to be true, just no events will be sent
367
+ * @param config.debug Whether to log debug information. Default is false.
368
+ * @param config.trackUrlParams Whether to track URL parameters. Default is true.
369
+ * @param config.trackHashChanges Whether to track hash changes. Default is true.
370
+ * @param config.integrations Configuration for third-party integrations like Facebook Pixel.
371
+ */
372
+ constructor(config: {
373
+ projectId: string;
374
+ proxy?: string;
375
+ autoPageTracking?: {
376
+ enabled: boolean;
377
+ trackQueryParams?: boolean;
378
+ trackHash?: boolean;
379
+ };
380
+ enabled?: boolean;
381
+ debug?: boolean;
382
+ debugVerbose?: boolean;
383
+ integrations?: IntegrationsConfig;
384
+ support?: SupportInit;
385
+ socialProof?: SocialProofInit;
386
+ });
387
+ init(): void;
388
+ disableDebug(): void;
389
+ enableDebug(): void;
390
+ /**
391
+ * Enables and injects the support widget when it was constructed with
392
+ * `support: { enabled: false }`. Safe to call multiple times.
393
+ */
394
+ enableSupport(): void;
395
+ /**
396
+ * Enables and injects the social-proof widget (e.g. after constructing with
397
+ * `socialProof: { enabled: false }`, or when no `socialProof` block was
398
+ * passed). Injection still runs the server check, so the loader only
399
+ * downloads when the project has the app enabled in the dashboard.
400
+ * Safe to call multiple times — the loader injection is guarded against
401
+ * double-injection.
402
+ */
403
+ enableSocialProof(): void;
404
+ /**
405
+ * Initialize third-party integrations
406
+ */
407
+ private initIntegrations;
408
+ /**
409
+ * Track events with support for both client (Segment-style) and server (object-style) usage
410
+ * Client: track('User Signed Up', { plan: 'Pro' }, { source: 'client' })
411
+ * Server: track({ event: 'User Signed Up', userId: 'user_123', properties: { plan: 'Pro' } })
412
+ */
413
+ track(action: string, properties?: Record<string, any>, context?: Context): Promise<DoRequestResponse>;
414
+ track(payload: TrackPayload): Promise<DoRequestResponse>;
415
+ /**
416
+ * The page method lets you record page views on your website
417
+ * This records the page title and path and names the event useing the reserved property "Page Viewed"
418
+ *
419
+ * Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
420
+ */
421
+ page(): Promise<DoRequestResponse> | undefined;
422
+ /**
423
+ * The identify method lets you tie a user to their actions and record traits about them.
424
+ * We recommend you call this when the user logs in and when any traits get updated.
425
+ * You can also identify a user as null when they logout to clear the user
426
+ *
427
+ * @param distinctId The user's id. This should be the user id from your database. This is optional and can be skipped, but you must provide an email address on the user properties.
428
+ * @param properties A dictionary of traits you know about the user like their email, name, plan etc.
429
+ * @param context Context for the identify call such as whether the user is active.
430
+ */
431
+ identify(properties: Record<string, any>, context?: Context): Promise<DoRequestResponse>;
432
+ identify(distinctId: string | number | null, properties?: Record<string, any>, context?: Context): Promise<DoRequestResponse>;
433
+ /**
434
+ * This should only be called when the user logs out
435
+ * It will reset the session, anonymous id, and user id
436
+ *
437
+ * All events after calling reset will be tracked as a new user
438
+ *
439
+ */
440
+ logout(): void;
441
+ /**
442
+ * Handles sending data to the Analytics API
443
+ * If you have a proxy set up, it will send the data to the proxy and you can handle forwarding the data to the Analytics events API
444
+ * @param path - API path relative to the analytics base URL
445
+ * @param data - Request payload to send
446
+ */
447
+ private doRequest;
448
+ /**
449
+ * If autoPageTracking is enabled, this will automatically track page views
450
+ * It listens to url changes to track new pages every time the url changes
451
+ * @returns void
452
+ */
453
+ private initAutoPageTracking;
454
+ getIntegrationsStats(): {
455
+ context: AnalyticsContext;
456
+ currentEnvironment: IntegrationEnvironment;
457
+ flushInterval: number;
458
+ integrations: {
459
+ environments: IntegrationEnvironment[];
460
+ name: string;
461
+ status: IntegrationStatus;
462
+ }[];
463
+ periodicFlushEnabled: boolean;
464
+ queueLength: number;
465
+ readyCount: number;
466
+ };
467
+ /**
468
+ * Lazily injects the support **loader** from the same `/sdk/` origin as
469
+ * the analytics bundle, forwarding the shared `projectId` and the widget
470
+ * config as `data-*` attributes. The loader (no React) injects the
471
+ * cross-origin embed iframe. Deferred (`async`) and guarded against
472
+ * double-injection so re-running `init()` is a no-op.
473
+ */
474
+ private injectSupport;
475
+ /**
476
+ * Lazily injects the social-proof loader (server-gated). See
477
+ * {@link injectSocialProofLoader}.
478
+ */
479
+ private injectSocialProof;
480
+ /**
481
+ * Records the latest CRM identity and forwards it to the support widget.
482
+ * No-op when support isn't enabled.
483
+ */
484
+ private updateSupportIdentity;
485
+ /**
486
+ * Pushes the current identity onto `window.SaascoSupport.identify`. The
487
+ * widget bundle publishes that global asynchronously, so this short-polls for
488
+ * it (same approach as tool registration); the load handler also calls this,
489
+ * so a fresh page load with a stored distinctId still identifies the chat.
490
+ */
491
+ private pushSupportIdentity;
492
+ }
493
+
494
+ /**
495
+ * Browser-collected context attached to track payloads by `getBrowserContext()`.
496
+ *
497
+ * Defined here rather than in `libs/analytics/sdk` because server and worker
498
+ * code validates it too. The SDK re-exports it, so `saasco-sdk`'s public API is
499
+ * unchanged — but a shared module importing the SDK barrel would drag the whole
500
+ * DOM-dependent bundle into every consumer's program, including the Cloudflare
501
+ * Worker, which has no DOM lib.
502
+ */
503
+ declare const BrowserContextSchema: z.ZodObject<{
504
+ $href: z.ZodString;
505
+ $locale: z.ZodString;
506
+ $location: z.ZodString;
507
+ $pathname: z.ZodString;
508
+ $referrer: z.ZodString;
509
+ $referringDomain: z.ZodString;
510
+ $screenDPI: z.ZodNumber;
511
+ $screenHeight: z.ZodNumber;
512
+ $screenWidth: z.ZodNumber;
513
+ $title: z.ZodString;
514
+ $userAgent: z.ZodString;
515
+ $utmAdId: z.ZodNullable<z.ZodString>;
516
+ $utmAdSource: z.ZodNullable<z.ZodString>;
517
+ $utmCampaign: z.ZodNullable<z.ZodString>;
518
+ $utmCampaignId: z.ZodNullable<z.ZodString>;
519
+ $utmContent: z.ZodNullable<z.ZodString>;
520
+ $utmCreativeFormat: z.ZodNullable<z.ZodString>;
521
+ $utmId: z.ZodNullable<z.ZodString>;
522
+ $utmMarketingTactic: z.ZodNullable<z.ZodString>;
523
+ $utmMedium: z.ZodNullable<z.ZodString>;
524
+ $utmSource: z.ZodNullable<z.ZodString>;
525
+ $utmSourcePlatform: z.ZodNullable<z.ZodString>;
526
+ $utmTerm: z.ZodNullable<z.ZodString>;
527
+ }, z.core.$strip>;
528
+ type BrowserContext = z.infer<typeof BrowserContextSchema>;
529
+ type SuperContext = Record<string, unknown>;
530
+
531
+ declare function getBrowserContext(): BrowserContext;
532
+
533
+ declare const timezones: Record<string, string>;
534
+
535
+ export { type AnalyticsContext, type BrowserContext, BrowserContextSchema, type EventEnvelope, type EventType, type FacebookEventMapping, type FacebookPixelConfig, type FacebookPixelIntegrationConfig, type Integration, type IntegrationConfigBase, type IntegrationEnvironment, IntegrationManager, type IntegrationState, type IntegrationStatus, type IntegrationsConfig, type ManagerConfig, type PinterestEventMapping, type PinterestTagConfig, type PinterestTagIntegrationConfig, Saasco, type SocialProofInit, type StandardFacebookEvent, type StandardPinterestEvent, type StandardTikTokEvent, type SuperContext, type SupportInit, type TikTokEventMapping, type TikTokPixelConfig, type TikTokPixelIntegrationConfig, createFacebookPixelIntegration, createPinterestTagIntegration, createTikTokPixelIntegration, getBrowserContext, standardFacebookEvents, standardPinterestEvents, standardTikTokEvents, timezones };