saasco-sdk 0.1.12 → 0.1.14

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 CHANGED
@@ -35,8 +35,8 @@ export const saasco = new Saasco({ projectId: 'YOUR-PROJECT-ID' });
35
35
 
36
36
  ## Init Automatic Page View Tracking
37
37
 
38
- When you initial the lib Saasco will automatically start tracking all page views in your app. There is no other configuration. It will automatically track url changes, even for SPAs like NextJs and Vue.
39
- You can also [manually track pages](https://www.notion.so/Manual-Page-Tracking-in-SPAs-2442fc7586dc4208ae8f669eb7561b1a?pvs=21) by opting our of automatic page tracking. For most use cases you don't need to do this.
38
+ When you initiate the lib Saasco will automatically start tracking all page views in your app. There is no other configuration. It will automatically track url changes, even for SPAs like NextJs and Vue.
39
+ You can also [manually track pages](https://www.notion.so/Manual-Page-Tracking-in-SPAs-2442fc7586dc4208ae8f669eb7561b1a?pvs=21) by opting out of automatic page tracking. For most use cases you don't need to do this.
40
40
 
41
41
  ```ts
42
42
  // ./app/index
@@ -228,6 +228,12 @@ Any property that starts with `$` is a property that has been generated by the S
228
228
  | $utmContent | Last Touch UTM Content | The UTM content tag from the URL a customer clicked during their last interaction. |
229
229
  | $unsubscribed | Unsubscribed | Whether the user has unsubscribed from all notifications |
230
230
 
231
+ ### Reserved Integration Properties
232
+
233
+ | Property | Display Name | Description |
234
+ | ----------------- | ------------------ | ------------------------------------------------ |
235
+ | $stripeCustomerId | Stripe Customer Id | The Stripe customer ID associated with this user |
236
+
231
237
  ### Reserved event properties
232
238
 
233
239
  Properties used to calculate revenue for different traffic sources and LTV for users.
package/index.cjs.js CHANGED
@@ -6,6 +6,8 @@ var tslib = require('tslib');
6
6
  var uuid = require('@lukeed/uuid');
7
7
  var zod = require('zod');
8
8
 
9
+ var version = "0.1.14";
10
+
9
11
  const timezones = {
10
12
  'Asia/Barnaul': 'RU',
11
13
  'Africa/Nouakchott': 'MR',
@@ -434,10 +436,39 @@ const timezones = {
434
436
  'Asia/Calcutta': 'IN'
435
437
  };
436
438
 
437
- var version = "0.1.12";
439
+ function getBrowserContext() {
440
+ var _a;
441
+ const isBrowser = typeof window !== 'undefined';
442
+ if (!isBrowser) return;
443
+ const customNavigator = navigator;
444
+ 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';
445
+ // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
446
+ // Only has 96.63% global support, so we need to check for undefined
447
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
448
+ const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
449
+ const $href = window.location.href;
450
+ const $pathname = window.location.pathname;
451
+ const $referrer = document.referrer;
452
+ const $screenDPI = window.devicePixelRatio;
453
+ const $screenHeight = screen.height;
454
+ const $screenWidth = screen.width;
455
+ const $title = document.title;
456
+ const $userAgent = window.navigator.userAgent;
457
+ return {
458
+ $locale,
459
+ $location,
460
+ $href,
461
+ $pathname,
462
+ $referrer,
463
+ $screenDPI,
464
+ $screenHeight,
465
+ $screenWidth,
466
+ $title,
467
+ $userAgent
468
+ };
469
+ }
438
470
 
439
471
  const isBrowser = typeof window !== 'undefined';
440
- let userId = null;
441
472
  const PREF = 'saasco-sdk';
442
473
  const data = {};
443
474
  function storeData(key, value, ttl) {
@@ -503,35 +534,11 @@ function setAnonmousId({
503
534
  storeData(`anonymous-id`, anonymousId, 1000 * 60 * 60 * 24 * 365);
504
535
  return anonymousId;
505
536
  }
506
- function getBrowserContext() {
507
- var _a;
508
- if (!isBrowser) return {};
509
- const customNavigator = navigator;
510
- 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';
511
- // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
512
- // Only has 96.63% global support, so we need to check for undefined
513
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
514
- const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
515
- const $href = window.location.href;
516
- const $pathname = window.location.pathname;
517
- const $referrer = document.referrer;
518
- const $screenDPI = window.devicePixelRatio;
519
- const $screenHeight = screen.height;
520
- const $screenWidth = screen.width;
521
- const $title = document.title;
522
- const $userAgent = window.navigator.userAgent;
523
- return {
524
- $locale,
525
- $location,
526
- $href,
527
- $pathname,
528
- $referrer,
529
- $screenDPI,
530
- $screenHeight,
531
- $screenWidth,
532
- $title,
533
- $userAgent
534
- };
537
+ function getUserId() {
538
+ return retrieveData(`user-id`);
539
+ }
540
+ function setUserId(userId) {
541
+ storeData(`user-id`, userId, 1000 * 60 * 60 * 24 * 365);
535
542
  }
536
543
  class Saasco {
537
544
  /**
@@ -555,9 +562,6 @@ class Saasco {
555
562
  this.config.enabled = this.config.enabled === undefined ? true : this.config.enabled;
556
563
  }
557
564
  init() {
558
- if (!this.config.projectId) {
559
- return this.error("Unable to initialize Saasco. Project ID is required but has not been provided. If you are using an env variable make sure it's set correctly.");
560
- }
561
565
  if (this.isInitialized) {
562
566
  this.log('Saasco is already initialized. Please check your code to ensure that init() is not being called multiple times.');
563
567
  return;
@@ -613,9 +617,9 @@ class Saasco {
613
617
  version,
614
618
  sessionId: getSessionId(),
615
619
  anonymousId: getAnonymousId(),
616
- distinctId: userId,
620
+ distinctId: getUserId(),
617
621
  projectId: this.config.projectId,
618
- payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
622
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext || {}), {
619
623
  properties: properties || {}
620
624
  })),
621
625
  context: JSON.stringify(context || {})
@@ -642,7 +646,7 @@ class Saasco {
642
646
  // When the user gets identified as null this will reset the users session and anonymous id
643
647
  // This should only be called when distinctId is null and there is an existing userId.
644
648
  // This means the user has logged out and we should reset the session and anonymous IDs
645
- const userIdChangedToNull = distinctId === null && !!userId;
649
+ const userIdChangedToNull = distinctId === null && !!getUserId();
646
650
  if (userIdChangedToNull) this.log('User ID change to null. Session reset');
647
651
  const reset = userIdChangedToNull;
648
652
  setSessionId({
@@ -652,7 +656,7 @@ class Saasco {
652
656
  reset
653
657
  });
654
658
  // set the distinct Id to the userId
655
- userId = distinctId;
659
+ setUserId(distinctId);
656
660
  // No distinctId provided so we don't track the user
657
661
  if (!distinctId) return;
658
662
  const data = {
@@ -691,13 +695,13 @@ class Saasco {
691
695
  body: JSON.stringify(data)
692
696
  });
693
697
  if (!response.ok) {
694
- throw new Error(response.status.toString());
698
+ const errorBody = yield response.json();
699
+ throw new Error(`${errorBody.message}: ${errorBody.errors ? `[${errorBody.errors.join(', ')}]` : ''}` || JSON.stringify(errorBody));
695
700
  }
696
701
  return response;
697
702
  } catch (error) {
698
- const errorMessage = 'Error with Saasco request: ' + error.message;
699
- console.error(errorMessage, path, data);
700
- return errorMessage;
703
+ this.error(`\nError Message: "${error.message}"`, `\nPath: "/${path}"`, `\nRequest Data: ${JSON.stringify(data, null, 2)}`);
704
+ return error.message;
701
705
  }
702
706
  });
703
707
  }
@@ -812,6 +816,9 @@ function coerceReservedProperties(properties) {
812
816
  }, {
813
817
  key: 'displayName',
814
818
  coerceFrom: ['display_name', 'displayName', 'user_display_name', 'userDisplayName', 'full_name', 'fullName', 'user_full_name', 'userFullName', 'complete_name', 'completeName', 'user_complete_name', 'userCompleteName', 'name', 'username']
819
+ }, {
820
+ key: '$stripeCustomerId',
821
+ coerceFrom: ['stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId']
815
822
  }];
816
823
  return coerce.reduce((acc, {
817
824
  key,
@@ -859,6 +866,61 @@ function coerceValue(properties, keys, schema) {
859
866
  return coercedValue;
860
867
  }
861
868
 
869
+ const browserContextSchema = zod.z.object({
870
+ $locale: zod.z.string(),
871
+ $location: zod.z.string(),
872
+ $href: zod.z.string(),
873
+ $pathname: zod.z.string(),
874
+ $referrer: zod.z.string(),
875
+ $screenDPI: zod.z.number(),
876
+ $screenHeight: zod.z.number(),
877
+ $screenWidth: zod.z.number(),
878
+ $title: zod.z.string(),
879
+ $userAgent: zod.z.string()
880
+ });
881
+ const serverContextSchema = zod.z.object({
882
+ $city: zod.z.string().optional(),
883
+ $country: zod.z.string().optional(),
884
+ $continent: zod.z.string().optional(),
885
+ $latitude: zod.z.number().optional(),
886
+ $longitude: zod.z.number().optional(),
887
+ $timezone: zod.z.string().optional(),
888
+ $userAgent: zod.z.string().optional(),
889
+ $referrer: zod.z.string().optional(),
890
+ $ip: zod.z.string().optional(),
891
+ $processedAt: zod.z.string().datetime().optional(),
892
+ $identityHash: zod.z.string().optional()
893
+ });
894
+ const trackedEventTypesSchema = zod.z.enum(['SHORTLINK_REDIRECT']);
895
+ const trackedEventSchema = zod.z.object({
896
+ id: zod.z.string().uuid(),
897
+ timestamp: zod.z.string().datetime(),
898
+ projectId: zod.z.string(),
899
+ version: zod.z.string(),
900
+ type: trackedEventTypesSchema,
901
+ payload: zod.z.object({
902
+ browserContext: browserContextSchema.optional(),
903
+ serverContext: serverContextSchema.optional(),
904
+ properties: zod.z.record(zod.z.string(), zod.z.any()).optional()
905
+ })
906
+ });
907
+ /**
908
+ * Creates a zod for tracking any type of event.
909
+ * Includes the base tracking schema and extends with any new schema
910
+ * @param type
911
+ * @param payloadSchema
912
+ * @returns
913
+ */
914
+ function createTrackedEventTypeSchema(type, payloadSchema) {
915
+ const typeSchema = zod.z.literal(type);
916
+ return trackedEventSchema.extend({
917
+ type: typeSchema,
918
+ payload: zod.z.object(Object.assign(Object.assign({}, trackedEventSchema.shape.payload.shape), {
919
+ properties: payloadSchema
920
+ }))
921
+ });
922
+ }
923
+
862
924
  const tbAny = zod.z.union([zod.z.string(), zod.z.number(), zod.z.array(zod.z.union([zod.z.string(), zod.z.number()]))]);
863
925
  const tinyBirdBaseSchema = zod.z.object({
864
926
  meta: zod.z.array(zod.z.object({
@@ -1037,7 +1099,11 @@ const reservedPropertiesSchema = zod.z.object({
1037
1099
  username: zod.z.string().nullish(),
1038
1100
  website: zod.z.string().nullish(),
1039
1101
  $id: zod.z.string().nullish(),
1040
- $lastSeen: zod.z.string().nullish()
1102
+ $lastSeen: zod.z.string().nullish(),
1103
+ // Stripe Properties
1104
+ $stripeCustomerId: zod.z.string().nullish(),
1105
+ $stripeTotalPayments: zod.z.number().or(zod.z.string()).nullish(),
1106
+ $stripeTotalSpent: zod.z.number().or(zod.z.string()).nullish()
1041
1107
  });
1042
1108
  const contactPropertiesSchema = reservedPropertiesSchema.optional().and(zod.z.record(zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.date(), zod.z.null(), zod.z.array(zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.date(), zod.z.null()]))])));
1043
1109
  const analyticsUserRawSchema = zod.z.object({
@@ -1088,11 +1154,14 @@ exports.analyticsEventSchema = analyticsEventSchema;
1088
1154
  exports.analyticsUserRawSchema = analyticsUserRawSchema;
1089
1155
  exports.analyticsUserSchema = analyticsUserSchema;
1090
1156
  exports.baseTopRequestSchema = baseTopRequestSchema;
1157
+ exports.browserContextSchema = browserContextSchema;
1091
1158
  exports.coerceReservedProperties = coerceReservedProperties;
1092
1159
  exports.contactPropertiesSchema = contactPropertiesSchema;
1160
+ exports.createTrackedEventTypeSchema = createTrackedEventTypeSchema;
1093
1161
  exports.currentUsersRequestSchema = currentUsersRequestSchema;
1094
1162
  exports.currentUsersResponseSchema = currentUsersResponseSchema;
1095
1163
  exports.getAnalyticsUserParamsSchema = getAnalyticsUserParamsSchema;
1164
+ exports.getBrowserContext = getBrowserContext;
1096
1165
  exports.idenfitySchema = idenfitySchema;
1097
1166
  exports.kpiSchema = kpiSchema;
1098
1167
  exports.kpisRequestSchema = kpisRequestSchema;
@@ -1104,6 +1173,7 @@ exports.latestIdentifiesRequestSchema = latestIdentifiesRequestSchema;
1104
1173
  exports.latestIdentifiesResponseSchema = latestIdentifiesResponseSchema;
1105
1174
  exports.listUsersParamsSchema = listUsersParamsSchema;
1106
1175
  exports.reservedPropertiesSchema = reservedPropertiesSchema;
1176
+ exports.serverContextSchema = serverContextSchema;
1107
1177
  exports.tbAny = tbAny;
1108
1178
  exports.timezones = timezones;
1109
1179
  exports.tinyBirdBaseSchema = tinyBirdBaseSchema;
@@ -1114,4 +1184,6 @@ exports.topLocationsResponseSchema = topLocationsResponseSchema;
1114
1184
  exports.topPagesResponseSchema = topPagesResponseSchema;
1115
1185
  exports.topSourcesResponseSchema = topSourcesResponseSchema;
1116
1186
  exports.topSourcesSchema = topSourcesSchema;
1187
+ exports.trackedEventSchema = trackedEventSchema;
1188
+ exports.trackedEventTypesSchema = trackedEventTypesSchema;
1117
1189
  exports.userEventsResponseSchema = userEventsResponseSchema;
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.14";
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
- var version = "0.1.12";
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 getBrowserContext() {
503
- var _a;
504
- if (!isBrowser) return {};
505
- const customNavigator = navigator;
506
- 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';
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
  /**
@@ -551,9 +558,6 @@ class Saasco {
551
558
  this.config.enabled = this.config.enabled === undefined ? true : this.config.enabled;
552
559
  }
553
560
  init() {
554
- if (!this.config.projectId) {
555
- return this.error("Unable to initialize Saasco. Project ID is required but has not been provided. If you are using an env variable make sure it's set correctly.");
556
- }
557
561
  if (this.isInitialized) {
558
562
  this.log('Saasco is already initialized. Please check your code to ensure that init() is not being called multiple times.');
559
563
  return;
@@ -609,9 +613,9 @@ class Saasco {
609
613
  version,
610
614
  sessionId: getSessionId(),
611
615
  anonymousId: getAnonymousId(),
612
- distinctId: userId,
616
+ distinctId: getUserId(),
613
617
  projectId: this.config.projectId,
614
- payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
618
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext || {}), {
615
619
  properties: properties || {}
616
620
  })),
617
621
  context: JSON.stringify(context || {})
@@ -638,7 +642,7 @@ class Saasco {
638
642
  // When the user gets identified as null this will reset the users session and anonymous id
639
643
  // This should only be called when distinctId is null and there is an existing userId.
640
644
  // This means the user has logged out and we should reset the session and anonymous IDs
641
- const userIdChangedToNull = distinctId === null && !!userId;
645
+ const userIdChangedToNull = distinctId === null && !!getUserId();
642
646
  if (userIdChangedToNull) this.log('User ID change to null. Session reset');
643
647
  const reset = userIdChangedToNull;
644
648
  setSessionId({
@@ -648,7 +652,7 @@ class Saasco {
648
652
  reset
649
653
  });
650
654
  // set the distinct Id to the userId
651
- userId = distinctId;
655
+ setUserId(distinctId);
652
656
  // No distinctId provided so we don't track the user
653
657
  if (!distinctId) return;
654
658
  const data = {
@@ -687,13 +691,13 @@ class Saasco {
687
691
  body: JSON.stringify(data)
688
692
  });
689
693
  if (!response.ok) {
690
- throw new Error(response.status.toString());
694
+ const errorBody = yield response.json();
695
+ throw new Error(`${errorBody.message}: ${errorBody.errors ? `[${errorBody.errors.join(', ')}]` : ''}` || JSON.stringify(errorBody));
691
696
  }
692
697
  return response;
693
698
  } catch (error) {
694
- const errorMessage = 'Error with Saasco request: ' + error.message;
695
- console.error(errorMessage, path, data);
696
- return errorMessage;
699
+ this.error(`\nError Message: "${error.message}"`, `\nPath: "/${path}"`, `\nRequest Data: ${JSON.stringify(data, null, 2)}`);
700
+ return error.message;
697
701
  }
698
702
  });
699
703
  }
@@ -808,6 +812,9 @@ function coerceReservedProperties(properties) {
808
812
  }, {
809
813
  key: 'displayName',
810
814
  coerceFrom: ['display_name', 'displayName', 'user_display_name', 'userDisplayName', 'full_name', 'fullName', 'user_full_name', 'userFullName', 'complete_name', 'completeName', 'user_complete_name', 'userCompleteName', 'name', 'username']
815
+ }, {
816
+ key: '$stripeCustomerId',
817
+ coerceFrom: ['stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId', 'stripe_customer_id', 'stripeCustomerId']
811
818
  }];
812
819
  return coerce.reduce((acc, {
813
820
  key,
@@ -855,6 +862,61 @@ function coerceValue(properties, keys, schema) {
855
862
  return coercedValue;
856
863
  }
857
864
 
865
+ const browserContextSchema = z.object({
866
+ $locale: z.string(),
867
+ $location: z.string(),
868
+ $href: z.string(),
869
+ $pathname: z.string(),
870
+ $referrer: z.string(),
871
+ $screenDPI: z.number(),
872
+ $screenHeight: z.number(),
873
+ $screenWidth: z.number(),
874
+ $title: z.string(),
875
+ $userAgent: z.string()
876
+ });
877
+ const serverContextSchema = z.object({
878
+ $city: z.string().optional(),
879
+ $country: z.string().optional(),
880
+ $continent: z.string().optional(),
881
+ $latitude: z.number().optional(),
882
+ $longitude: z.number().optional(),
883
+ $timezone: z.string().optional(),
884
+ $userAgent: z.string().optional(),
885
+ $referrer: z.string().optional(),
886
+ $ip: z.string().optional(),
887
+ $processedAt: z.string().datetime().optional(),
888
+ $identityHash: z.string().optional()
889
+ });
890
+ const trackedEventTypesSchema = z.enum(['SHORTLINK_REDIRECT']);
891
+ const trackedEventSchema = z.object({
892
+ id: z.string().uuid(),
893
+ timestamp: z.string().datetime(),
894
+ projectId: z.string(),
895
+ version: z.string(),
896
+ type: trackedEventTypesSchema,
897
+ payload: z.object({
898
+ browserContext: browserContextSchema.optional(),
899
+ serverContext: serverContextSchema.optional(),
900
+ properties: z.record(z.string(), z.any()).optional()
901
+ })
902
+ });
903
+ /**
904
+ * Creates a zod for tracking any type of event.
905
+ * Includes the base tracking schema and extends with any new schema
906
+ * @param type
907
+ * @param payloadSchema
908
+ * @returns
909
+ */
910
+ function createTrackedEventTypeSchema(type, payloadSchema) {
911
+ const typeSchema = z.literal(type);
912
+ return trackedEventSchema.extend({
913
+ type: typeSchema,
914
+ payload: z.object(Object.assign(Object.assign({}, trackedEventSchema.shape.payload.shape), {
915
+ properties: payloadSchema
916
+ }))
917
+ });
918
+ }
919
+
858
920
  const tbAny = z.union([z.string(), z.number(), z.array(z.union([z.string(), z.number()]))]);
859
921
  const tinyBirdBaseSchema = z.object({
860
922
  meta: z.array(z.object({
@@ -1033,7 +1095,11 @@ const reservedPropertiesSchema = z.object({
1033
1095
  username: z.string().nullish(),
1034
1096
  website: z.string().nullish(),
1035
1097
  $id: z.string().nullish(),
1036
- $lastSeen: z.string().nullish()
1098
+ $lastSeen: z.string().nullish(),
1099
+ // Stripe Properties
1100
+ $stripeCustomerId: z.string().nullish(),
1101
+ $stripeTotalPayments: z.number().or(z.string()).nullish(),
1102
+ $stripeTotalSpent: z.number().or(z.string()).nullish()
1037
1103
  });
1038
1104
  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()]))])));
1039
1105
  const analyticsUserRawSchema = z.object({
@@ -1078,4 +1144,4 @@ const latestIdentifiesResponseSchema = tinyBirdBaseSchema.extend({
1078
1144
  }))
1079
1145
  });
1080
1146
 
1081
- 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 };
1147
+ 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasco-sdk",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.0",
6
6
  "@lukeed/uuid": "^2.0.1",
package/src/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './lib/analytics';
2
2
  export * from './lib/coerceReservedProperties';
3
+ export * from './lib/getBrowserContext';
3
4
  export * from './lib/timezones';
5
+ export * from './lib/tracking';
4
6
  export * from './lib/types';
@@ -1,6 +1,7 @@
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 {
@@ -37,14 +38,14 @@ export declare class Saasco {
37
38
  */
38
39
  track(name: string, properties?: Record<string, any>, context?: {
39
40
  active?: boolean;
40
- }): void | Promise<string | Response | undefined>;
41
+ }): void | Promise<any>;
41
42
  /**
42
43
  * The page method lets you record page views on your website
43
44
  * This records the page title and path and names the event useing the reserved property "Page Viewed"
44
45
  *
45
46
  * Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
46
47
  */
47
- page(): void | Promise<string | Response | undefined>;
48
+ page(): void | Promise<any>;
48
49
  /**
49
50
  * The identify method lets you tie a user to their actions and record traits about them.
50
51
  * We recommend you call this when the user logs in and when any traits get updated.
@@ -0,0 +1,2 @@
1
+ import { BrowserContext } from './tracking/types';
2
+ export declare function getBrowserContext(): BrowserContext | undefined;
@@ -0,0 +1 @@
1
+ export * from './types';