saasco-sdk 0.1.13 → 0.1.15
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/README.md +19 -7
- package/index.cjs.js +146 -50
- package/index.esm.js +141 -51
- package/package.json +1 -1
- package/src/index.d.ts +2 -0
- package/src/lib/analytics.d.ts +6 -1
- package/src/lib/getBrowserContext.d.ts +2 -0
- package/src/lib/tracking/index.d.ts +1 -0
- package/src/lib/tracking/types.d.ts +2798 -0
- package/src/lib/types.d.ts +207 -47
package/index.esm.js
CHANGED
|
@@ -2,6 +2,8 @@ import { __awaiter } from 'tslib';
|
|
|
2
2
|
import { v4 } from '@lukeed/uuid';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
|
+
var version = "0.1.15";
|
|
6
|
+
|
|
5
7
|
const timezones = {
|
|
6
8
|
'Asia/Barnaul': 'RU',
|
|
7
9
|
'Africa/Nouakchott': 'MR',
|
|
@@ -430,10 +432,39 @@ const timezones = {
|
|
|
430
432
|
'Asia/Calcutta': 'IN'
|
|
431
433
|
};
|
|
432
434
|
|
|
433
|
-
|
|
435
|
+
function getBrowserContext() {
|
|
436
|
+
var _a;
|
|
437
|
+
const isBrowser = typeof window !== 'undefined';
|
|
438
|
+
if (!isBrowser) return;
|
|
439
|
+
const customNavigator = navigator;
|
|
440
|
+
const $locale = (customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.languages) && (customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.languages.length) ? customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.languages[0] : (customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.userLanguage) || (customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.language) || (customNavigator === null || customNavigator === void 0 ? void 0 : customNavigator.browserLanguage) || 'en';
|
|
441
|
+
// https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
442
|
+
// Only has 96.63% global support, so we need to check for undefined
|
|
443
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
444
|
+
const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
|
|
445
|
+
const $href = window.location.href;
|
|
446
|
+
const $pathname = window.location.pathname;
|
|
447
|
+
const $referrer = document.referrer;
|
|
448
|
+
const $screenDPI = window.devicePixelRatio;
|
|
449
|
+
const $screenHeight = screen.height;
|
|
450
|
+
const $screenWidth = screen.width;
|
|
451
|
+
const $title = document.title;
|
|
452
|
+
const $userAgent = window.navigator.userAgent;
|
|
453
|
+
return {
|
|
454
|
+
$locale,
|
|
455
|
+
$location,
|
|
456
|
+
$href,
|
|
457
|
+
$pathname,
|
|
458
|
+
$referrer,
|
|
459
|
+
$screenDPI,
|
|
460
|
+
$screenHeight,
|
|
461
|
+
$screenWidth,
|
|
462
|
+
$title,
|
|
463
|
+
$userAgent
|
|
464
|
+
};
|
|
465
|
+
}
|
|
434
466
|
|
|
435
467
|
const isBrowser = typeof window !== 'undefined';
|
|
436
|
-
let userId = null;
|
|
437
468
|
const PREF = 'saasco-sdk';
|
|
438
469
|
const data = {};
|
|
439
470
|
function storeData(key, value, ttl) {
|
|
@@ -499,35 +530,11 @@ function setAnonmousId({
|
|
|
499
530
|
storeData(`anonymous-id`, anonymousId, 1000 * 60 * 60 * 24 * 365);
|
|
500
531
|
return anonymousId;
|
|
501
532
|
}
|
|
502
|
-
function
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
508
|
-
// Only has 96.63% global support, so we need to check for undefined
|
|
509
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
510
|
-
const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
|
|
511
|
-
const $href = window.location.href;
|
|
512
|
-
const $pathname = window.location.pathname;
|
|
513
|
-
const $referrer = document.referrer;
|
|
514
|
-
const $screenDPI = window.devicePixelRatio;
|
|
515
|
-
const $screenHeight = screen.height;
|
|
516
|
-
const $screenWidth = screen.width;
|
|
517
|
-
const $title = document.title;
|
|
518
|
-
const $userAgent = window.navigator.userAgent;
|
|
519
|
-
return {
|
|
520
|
-
$locale,
|
|
521
|
-
$location,
|
|
522
|
-
$href,
|
|
523
|
-
$pathname,
|
|
524
|
-
$referrer,
|
|
525
|
-
$screenDPI,
|
|
526
|
-
$screenHeight,
|
|
527
|
-
$screenWidth,
|
|
528
|
-
$title,
|
|
529
|
-
$userAgent
|
|
530
|
-
};
|
|
533
|
+
function getUserId() {
|
|
534
|
+
return retrieveData(`user-id`);
|
|
535
|
+
}
|
|
536
|
+
function setUserId(userId) {
|
|
537
|
+
storeData(`user-id`, userId, 1000 * 60 * 60 * 24 * 365);
|
|
531
538
|
}
|
|
532
539
|
class Saasco {
|
|
533
540
|
/**
|
|
@@ -538,10 +545,12 @@ class Saasco {
|
|
|
538
545
|
* @param config.autoPageTracking Whether to automatically track page views. Default is false.
|
|
539
546
|
* @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
|
|
540
547
|
* @param config.debug Whether to log debug information. Default is false.
|
|
548
|
+
* @param config.trackUrlParams Whether to track URL parameters. Default is true.
|
|
549
|
+
* @param config.trackHashChanges Whether to track hash changes. Default is true.
|
|
541
550
|
*/
|
|
542
551
|
constructor(config) {
|
|
543
552
|
this.config = config;
|
|
544
|
-
this.
|
|
553
|
+
this.lastPageViewPath = '';
|
|
545
554
|
this.isInitialized = false;
|
|
546
555
|
if (!config.projectId) {
|
|
547
556
|
this.error("Project ID is required but has not been provided. If you are using an env variable make sure it's set correctly.");
|
|
@@ -549,6 +558,9 @@ class Saasco {
|
|
|
549
558
|
}
|
|
550
559
|
// default enabled to true
|
|
551
560
|
this.config.enabled = this.config.enabled === undefined ? true : this.config.enabled;
|
|
561
|
+
// default URL tracking options
|
|
562
|
+
this.config.trackUrlParams = this.config.trackUrlParams === undefined ? true : this.config.trackUrlParams;
|
|
563
|
+
this.config.trackHashChanges = this.config.trackHashChanges === undefined ? true : this.config.trackHashChanges;
|
|
552
564
|
}
|
|
553
565
|
init() {
|
|
554
566
|
if (this.isInitialized) {
|
|
@@ -586,16 +598,6 @@ class Saasco {
|
|
|
586
598
|
if (!this.config.projectId) {
|
|
587
599
|
return this.error("Unable to track event. Project ID is required but has not been provided. If you are using an env variable make sure it's set correctly.");
|
|
588
600
|
}
|
|
589
|
-
// Prevent duplicate Page View tracking
|
|
590
|
-
if (name === 'Page View') {
|
|
591
|
-
if (!isBrowser) {
|
|
592
|
-
console.warn('Saasco page tracking is only available in the browser');
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
const pageViewHref = window.location.href;
|
|
596
|
-
if (pageViewHref === this.lastPageViewHref) return;
|
|
597
|
-
this.lastPageViewHref = pageViewHref;
|
|
598
|
-
}
|
|
599
601
|
setSessionId();
|
|
600
602
|
setAnonmousId();
|
|
601
603
|
const browserContext = getBrowserContext();
|
|
@@ -606,9 +608,9 @@ class Saasco {
|
|
|
606
608
|
version,
|
|
607
609
|
sessionId: getSessionId(),
|
|
608
610
|
anonymousId: getAnonymousId(),
|
|
609
|
-
distinctId:
|
|
611
|
+
distinctId: getUserId(),
|
|
610
612
|
projectId: this.config.projectId,
|
|
611
|
-
payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
|
|
613
|
+
payload: JSON.stringify(Object.assign(Object.assign({}, browserContext || {}), {
|
|
612
614
|
properties: properties || {}
|
|
613
615
|
})),
|
|
614
616
|
context: JSON.stringify(context || {})
|
|
@@ -622,6 +624,23 @@ class Saasco {
|
|
|
622
624
|
* Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
|
|
623
625
|
*/
|
|
624
626
|
page() {
|
|
627
|
+
if (!isBrowser) {
|
|
628
|
+
console.warn('Saasco page tracking is only available in the browser');
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const url = new URL(window.location.href);
|
|
632
|
+
let pathToCompare = url.pathname;
|
|
633
|
+
// Include search params if configured
|
|
634
|
+
if (this.config.trackUrlParams) {
|
|
635
|
+
pathToCompare += url.search;
|
|
636
|
+
}
|
|
637
|
+
// Include hash if configured
|
|
638
|
+
if (this.config.trackHashChanges) {
|
|
639
|
+
pathToCompare += url.hash;
|
|
640
|
+
}
|
|
641
|
+
// Only track if the path has changed
|
|
642
|
+
if (pathToCompare === this.lastPageViewPath) return;
|
|
643
|
+
this.lastPageViewPath = pathToCompare;
|
|
625
644
|
return this.track('Page View');
|
|
626
645
|
}
|
|
627
646
|
identify(distinctIdOrProperties, propertiesOrContext, contextOrNothing) {
|
|
@@ -635,7 +654,7 @@ class Saasco {
|
|
|
635
654
|
// When the user gets identified as null this will reset the users session and anonymous id
|
|
636
655
|
// This should only be called when distinctId is null and there is an existing userId.
|
|
637
656
|
// This means the user has logged out and we should reset the session and anonymous IDs
|
|
638
|
-
const userIdChangedToNull = distinctId === null && !!
|
|
657
|
+
const userIdChangedToNull = distinctId === null && !!getUserId();
|
|
639
658
|
if (userIdChangedToNull) this.log('User ID change to null. Session reset');
|
|
640
659
|
const reset = userIdChangedToNull;
|
|
641
660
|
setSessionId({
|
|
@@ -645,7 +664,7 @@ class Saasco {
|
|
|
645
664
|
reset
|
|
646
665
|
});
|
|
647
666
|
// set the distinct Id to the userId
|
|
648
|
-
|
|
667
|
+
setUserId(distinctId);
|
|
649
668
|
// No distinctId provided so we don't track the user
|
|
650
669
|
if (!distinctId) return;
|
|
651
670
|
const data = {
|
|
@@ -805,6 +824,9 @@ function coerceReservedProperties(properties) {
|
|
|
805
824
|
}, {
|
|
806
825
|
key: 'displayName',
|
|
807
826
|
coerceFrom: ['display_name', 'displayName', 'user_display_name', 'userDisplayName', 'full_name', 'fullName', 'user_full_name', 'userFullName', 'complete_name', 'completeName', 'user_complete_name', 'userCompleteName', 'name', 'username']
|
|
827
|
+
}, {
|
|
828
|
+
key: '$stripeCustomerId',
|
|
829
|
+
coerceFrom: ['stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId']
|
|
808
830
|
}];
|
|
809
831
|
return coerce.reduce((acc, {
|
|
810
832
|
key,
|
|
@@ -852,6 +874,61 @@ function coerceValue(properties, keys, schema) {
|
|
|
852
874
|
return coercedValue;
|
|
853
875
|
}
|
|
854
876
|
|
|
877
|
+
const browserContextSchema = z.object({
|
|
878
|
+
$locale: z.string(),
|
|
879
|
+
$location: z.string(),
|
|
880
|
+
$href: z.string(),
|
|
881
|
+
$pathname: z.string(),
|
|
882
|
+
$referrer: z.string(),
|
|
883
|
+
$screenDPI: z.number(),
|
|
884
|
+
$screenHeight: z.number(),
|
|
885
|
+
$screenWidth: z.number(),
|
|
886
|
+
$title: z.string(),
|
|
887
|
+
$userAgent: z.string()
|
|
888
|
+
});
|
|
889
|
+
const serverContextSchema = z.object({
|
|
890
|
+
$city: z.string().optional(),
|
|
891
|
+
$country: z.string().optional(),
|
|
892
|
+
$continent: z.string().optional(),
|
|
893
|
+
$latitude: z.number().optional(),
|
|
894
|
+
$longitude: z.number().optional(),
|
|
895
|
+
$timezone: z.string().optional(),
|
|
896
|
+
$userAgent: z.string().optional(),
|
|
897
|
+
$referrer: z.string().optional(),
|
|
898
|
+
$ip: z.string().optional(),
|
|
899
|
+
$processedAt: z.string().datetime().optional(),
|
|
900
|
+
$identityHash: z.string().optional()
|
|
901
|
+
});
|
|
902
|
+
const trackedEventTypesSchema = z.enum(['SHORTLINK_REDIRECT']);
|
|
903
|
+
const trackedEventSchema = z.object({
|
|
904
|
+
id: z.string().uuid(),
|
|
905
|
+
timestamp: z.string().datetime(),
|
|
906
|
+
projectId: z.string(),
|
|
907
|
+
version: z.string(),
|
|
908
|
+
type: trackedEventTypesSchema,
|
|
909
|
+
payload: z.object({
|
|
910
|
+
browserContext: browserContextSchema.optional(),
|
|
911
|
+
serverContext: serverContextSchema.optional(),
|
|
912
|
+
properties: z.record(z.string(), z.any()).optional()
|
|
913
|
+
})
|
|
914
|
+
});
|
|
915
|
+
/**
|
|
916
|
+
* Creates a zod for tracking any type of event.
|
|
917
|
+
* Includes the base tracking schema and extends with any new schema
|
|
918
|
+
* @param type
|
|
919
|
+
* @param payloadSchema
|
|
920
|
+
* @returns
|
|
921
|
+
*/
|
|
922
|
+
function createTrackedEventTypeSchema(type, payloadSchema) {
|
|
923
|
+
const typeSchema = z.literal(type);
|
|
924
|
+
return trackedEventSchema.extend({
|
|
925
|
+
type: typeSchema,
|
|
926
|
+
payload: z.object(Object.assign(Object.assign({}, trackedEventSchema.shape.payload.shape), {
|
|
927
|
+
properties: payloadSchema
|
|
928
|
+
}))
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
|
|
855
932
|
const tbAny = z.union([z.string(), z.number(), z.array(z.union([z.string(), z.number()]))]);
|
|
856
933
|
const tinyBirdBaseSchema = z.object({
|
|
857
934
|
meta: z.array(z.object({
|
|
@@ -891,7 +968,9 @@ const TinybirdJobResponseSchema = z.object({
|
|
|
891
968
|
const latestEventsRequestSchema = z.object({
|
|
892
969
|
projectId: z.string(),
|
|
893
970
|
limit: z.number().optional(),
|
|
894
|
-
payload: z.boolean().optional()
|
|
971
|
+
payload: z.boolean().optional(),
|
|
972
|
+
distinctId: z.string().optional(),
|
|
973
|
+
action: z.string().optional()
|
|
895
974
|
});
|
|
896
975
|
const latestEventItemSchema = z.object({
|
|
897
976
|
id: z.string(),
|
|
@@ -902,7 +981,9 @@ const latestEventItemSchema = z.object({
|
|
|
902
981
|
href: z.string(),
|
|
903
982
|
device: z.string(),
|
|
904
983
|
browser: z.string(),
|
|
905
|
-
payload: z.string().optional()
|
|
984
|
+
payload: z.string().optional(),
|
|
985
|
+
distinctId: z.string().optional(),
|
|
986
|
+
unique: z.boolean().optional()
|
|
906
987
|
});
|
|
907
988
|
const latestEventsResponseSchema = tinyBirdBaseSchema.extend({
|
|
908
989
|
data: z.array(latestEventItemSchema)
|
|
@@ -1014,7 +1095,7 @@ const currentUsersResponseSchema = tinyBirdBaseSchema.extend({
|
|
|
1014
1095
|
}))
|
|
1015
1096
|
});
|
|
1016
1097
|
const reservedPropertiesSchema = z.object({
|
|
1017
|
-
age: z.number().
|
|
1098
|
+
age: z.number().nullish(),
|
|
1018
1099
|
avatar: z.string().url().nullish(),
|
|
1019
1100
|
birthday: z.string().nullish(),
|
|
1020
1101
|
createdAt: z.string().nullish(),
|
|
@@ -1029,8 +1110,17 @@ const reservedPropertiesSchema = z.object({
|
|
|
1029
1110
|
title: z.string().nullish(),
|
|
1030
1111
|
username: z.string().nullish(),
|
|
1031
1112
|
website: z.string().nullish(),
|
|
1113
|
+
// Default Properties
|
|
1032
1114
|
$id: z.string().nullish(),
|
|
1033
|
-
$lastSeen: z.string().nullish()
|
|
1115
|
+
$lastSeen: z.string().nullish(),
|
|
1116
|
+
$unsubscribed: z.boolean().nullish(),
|
|
1117
|
+
$unsubscribeReason: z.enum(['manual', 'complained', 'bounced']).nullish(),
|
|
1118
|
+
// Stripe Properties
|
|
1119
|
+
$stripeCustomerId: z.string().nullish(),
|
|
1120
|
+
$stripeTotalPayments: z.number().or(z.string()).nullish(),
|
|
1121
|
+
$stripeTotalSpent: z.number().or(z.string()).nullish(),
|
|
1122
|
+
// Internal properties
|
|
1123
|
+
$_toDelete: z.boolean().nullish()
|
|
1034
1124
|
});
|
|
1035
1125
|
const contactPropertiesSchema = reservedPropertiesSchema.optional().and(z.record(z.union([z.string(), z.number(), z.boolean(), z.date(), z.null(), z.array(z.union([z.string(), z.number(), z.boolean(), z.date(), z.null()]))])));
|
|
1036
1126
|
const analyticsUserRawSchema = z.object({
|
|
@@ -1075,4 +1165,4 @@ const latestIdentifiesResponseSchema = tinyBirdBaseSchema.extend({
|
|
|
1075
1165
|
}))
|
|
1076
1166
|
});
|
|
1077
1167
|
|
|
1078
|
-
export { Saasco, TinybirdJobResponseSchema, analyticsEventSchema, analyticsUserRawSchema, analyticsUserSchema, baseTopRequestSchema, coerceReservedProperties, contactPropertiesSchema, currentUsersRequestSchema, currentUsersResponseSchema, getAnalyticsUserParamsSchema, idenfitySchema, kpiSchema, kpisRequestSchema, kpisResponseSchema, latestEventItemSchema, latestEventsRequestSchema, latestEventsResponseSchema, latestIdentifiesRequestSchema, latestIdentifiesResponseSchema, listUsersParamsSchema, reservedPropertiesSchema, tbAny, timezones, tinyBirdBaseSchema, topActionsResponseSchema, topBrowsersResponseSchema, topDevicesResponseSchema, topLocationsResponseSchema, topPagesResponseSchema, topSourcesResponseSchema, topSourcesSchema, userEventsResponseSchema };
|
|
1168
|
+
export { Saasco, TinybirdJobResponseSchema, analyticsEventSchema, analyticsUserRawSchema, analyticsUserSchema, baseTopRequestSchema, browserContextSchema, coerceReservedProperties, contactPropertiesSchema, createTrackedEventTypeSchema, currentUsersRequestSchema, currentUsersResponseSchema, getAnalyticsUserParamsSchema, getBrowserContext, idenfitySchema, kpiSchema, kpisRequestSchema, kpisResponseSchema, latestEventItemSchema, latestEventsRequestSchema, latestEventsResponseSchema, latestIdentifiesRequestSchema, latestIdentifiesResponseSchema, listUsersParamsSchema, reservedPropertiesSchema, serverContextSchema, tbAny, timezones, tinyBirdBaseSchema, topActionsResponseSchema, topBrowsersResponseSchema, topDevicesResponseSchema, topLocationsResponseSchema, topPagesResponseSchema, topSourcesResponseSchema, topSourcesSchema, trackedEventSchema, trackedEventTypesSchema, userEventsResponseSchema };
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
package/src/lib/analytics.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
declare global {
|
|
2
2
|
interface Window {
|
|
3
3
|
saascoAutoPageTrackingActive?: boolean;
|
|
4
|
+
saasco: Saasco;
|
|
4
5
|
}
|
|
5
6
|
}
|
|
6
7
|
export declare class Saasco {
|
|
7
8
|
private config;
|
|
8
|
-
private
|
|
9
|
+
private lastPageViewPath;
|
|
9
10
|
private isInitialized;
|
|
10
11
|
/**
|
|
11
12
|
* Creates an instance of Saasco SDK.
|
|
@@ -15,6 +16,8 @@ export declare class Saasco {
|
|
|
15
16
|
* @param config.autoPageTracking Whether to automatically track page views. Default is false.
|
|
16
17
|
* @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
|
|
17
18
|
* @param config.debug Whether to log debug information. Default is false.
|
|
19
|
+
* @param config.trackUrlParams Whether to track URL parameters. Default is true.
|
|
20
|
+
* @param config.trackHashChanges Whether to track hash changes. Default is true.
|
|
18
21
|
*/
|
|
19
22
|
constructor(config: {
|
|
20
23
|
projectId: string;
|
|
@@ -22,6 +25,8 @@ export declare class Saasco {
|
|
|
22
25
|
autoPageTracking?: boolean;
|
|
23
26
|
enabled?: boolean;
|
|
24
27
|
debug?: boolean;
|
|
28
|
+
trackUrlParams?: boolean;
|
|
29
|
+
trackHashChanges?: boolean;
|
|
25
30
|
});
|
|
26
31
|
init(): void;
|
|
27
32
|
disableDebug(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types';
|