saasco-sdk 0.1.7 → 0.1.8

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
@@ -166,6 +166,7 @@ saasco.debug(true);
166
166
 
167
167
  Saasco has reserved some properties that have semantic meanings for contacts and, and will handle them in special ways.
168
168
  For example, Saasco always expects email to be a string of the user’s email address, this is important for when sending emails using the marketing app.
169
+ The SDK will do its best to match these properties, eg (created_at will be mapped to createdAt), but if possible you should use the reserved properties.
169
170
 
170
171
  ### Reserved Contact Properties
171
172
 
@@ -180,7 +181,6 @@ For example, Saasco always expects email to be a string of the user’s email ad
180
181
  | firstName | String | First name of a user |
181
182
  | displayName | String | The prefered users display name, will default to "firstName lastName" |
182
183
  | gender | String | Gender of a user |
183
- | id | String | The ID of the user from your database, coerced to a string. eg 1 becomes "1" |
184
184
  | lastName | String | Last name of a user |
185
185
  | name | String | Full name of a user. If you only pass a first and last name Segment automatically fills in the full name for you. |
186
186
  | phone | String | Phone number of a user |
@@ -195,8 +195,8 @@ Any property that starts with `$` is a property that has been generated by the S
195
195
 
196
196
  | Property | Display Name | Description |
197
197
  | ----------------------- | --------------------------- | -------------------------------------------------------------------------------------- |
198
+ | $id | ID | The ID of the user from your database, coerced to a string. eg 1 becomes "1" |
198
199
  | $city | City | The city of the user parsed from the IP. |
199
- | $region | Region | The region of the user parsed from the IP |
200
200
  | $countryCode | Country Code | The country of the user parsed from the IP property. |
201
201
  | $latitude | Latitude | Latitude of the user's IP location. |
202
202
  | $longitude | Longitude | Longitude of the user's IP location. |
@@ -205,7 +205,7 @@ Any property that starts with `$` is a property that has been generated by the S
205
205
  | $screenHeight | Screen Height | The most recent height of the device screen in pixels |
206
206
  | $screenWidth | Screen Width | The most recent width of the device screen in pixels |
207
207
  | $screenDpi | Screen DPI | The most recent Pixel density of the device screen. |
208
- | $lastSeen | Updated at | The last time a user profile property was set or updated |
208
+ | $lastSeen | Last Seen | The last time a user was identified while active was not false in the context |
209
209
  | $os | Operating System | The most recent OS of the user. |
210
210
  | $browser | Browser | The most recent browser of the user. |
211
211
  | $browserVersion | Browser Version | The most recent bowser version of the user. |
@@ -242,7 +242,6 @@ Our SDKs automatically collect certain properties on every event or user profile
242
242
  | Property | Display Name | Description |
243
243
  | ---------------- | --------------------------- | -------------------------------------------------------------------------------- |
244
244
  | $city | City | The city of the user parsed from the IP. |
245
- | $region | Region | The region of the user parsed from the IP |
246
245
  | $countryCode | Country Code | The country of the user parsed from the IP property. |
247
246
  | $latitude | Latitude | Latitude of the user's IP location. |
248
247
  | $longitude | Longitude | Longitude of the user's IP location. |
package/index.cjs.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var tslib = require('tslib');
5
6
  var uuid = require('@lukeed/uuid');
6
7
  var zod = require('zod');
7
8
 
@@ -433,7 +434,6 @@ const timezones = {
433
434
  'Asia/Calcutta': 'IN'
434
435
  };
435
436
 
436
- /* eslint-disable @typescript-eslint/no-explicit-any */
437
437
  const isBrowser = typeof window !== 'undefined';
438
438
  let userId = null;
439
439
  const PREF = 'saasco-sdk';
@@ -501,6 +501,36 @@ function setAnonmousId({
501
501
  storeData(`anonymous-id`, anonymousId, 1000 * 60 * 60 * 24 * 365);
502
502
  return anonymousId;
503
503
  }
504
+ function getBrowserContext() {
505
+ var _a;
506
+ if (!isBrowser) return {};
507
+ const customNavigator = navigator;
508
+ 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';
509
+ // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
510
+ // Only has 96.63% global support, so we need to check for undefined
511
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
512
+ const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
513
+ const $href = window.location.href;
514
+ const $pathname = window.location.pathname;
515
+ const $referrer = document.referrer;
516
+ const $screenDPI = window.devicePixelRatio;
517
+ const $screenHeight = screen.height;
518
+ const $screenWidth = screen.width;
519
+ const $title = document.title;
520
+ const $userAgent = window.navigator.userAgent;
521
+ return {
522
+ $locale,
523
+ $location,
524
+ $href,
525
+ $pathname,
526
+ $referrer,
527
+ $screenDPI,
528
+ $screenHeight,
529
+ $screenWidth,
530
+ $title,
531
+ $userAgent
532
+ };
533
+ }
504
534
  class Saasco {
505
535
  /**
506
536
  * Creates an instance of Saasco SDK.
@@ -542,8 +572,7 @@ class Saasco {
542
572
  */
543
573
  track(name,
544
574
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
545
- properties) {
546
- var _a;
575
+ properties, context) {
547
576
  // Prevent duplicate Page View tracking
548
577
  if (name === 'Page View') {
549
578
  if (!isBrowser) {
@@ -556,20 +585,7 @@ class Saasco {
556
585
  }
557
586
  setSessionId();
558
587
  setAnonmousId();
559
- const customNavigator = isBrowser ? navigator : undefined;
560
- const $locale = isBrowser ? (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' : undefined;
561
- // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
562
- // Only has 96.63% global support, so we need to check for undefined
563
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
564
- const $location = isBrowser ? timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined' : undefined;
565
- const $href = isBrowser ? window.location.href : undefined;
566
- const $pathname = isBrowser ? window.location.pathname : undefined;
567
- const $referrer = isBrowser ? document.referrer : undefined;
568
- const $screenDPI = isBrowser ? window.devicePixelRatio : undefined;
569
- const $screenHeight = isBrowser ? screen.height : undefined;
570
- const $screenWidth = isBrowser ? screen.width : undefined;
571
- const $title = isBrowser ? document.title : undefined;
572
- const $userAgent = isBrowser ? window.navigator.userAgent : undefined;
588
+ const browserContext = getBrowserContext();
573
589
  const data = {
574
590
  id: uuid.v4(),
575
591
  timestamp: new Date().toISOString(),
@@ -578,21 +594,12 @@ class Saasco {
578
594
  sessionId: getSessionId(),
579
595
  anonymousId: getAnonymousId(),
580
596
  projectId: this.config.projectId,
581
- payload: JSON.stringify({
582
- $href,
583
- $locale,
584
- $location,
585
- $pathname,
586
- $referrer,
587
- $screenDPI,
588
- $screenHeight,
589
- $screenWidth,
590
- $title,
591
- $userAgent,
597
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
592
598
  properties: properties || {}
593
- })
599
+ })),
600
+ context: JSON.stringify(context || {})
594
601
  };
595
- this.doRequest('events', data);
602
+ return this.doRequest('events', data);
596
603
  }
597
604
  /**
598
605
  * The page method lets you record page views on your website
@@ -601,13 +608,13 @@ class Saasco {
601
608
  * Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
602
609
  */
603
610
  page() {
604
- this.track('Page View');
611
+ return this.track('Page View');
605
612
  }
606
- identify(distinctIdOrProperties, propertiesOrOptions, optionsOrNothing) {
613
+ identify(distinctIdOrProperties, propertiesOrContext, contextOrNothing) {
607
614
  const hasId = typeof distinctIdOrProperties === 'string' || typeof distinctIdOrProperties === 'number' || distinctIdOrProperties === null;
608
615
  const distinctId = hasId ? distinctIdOrProperties === null || distinctIdOrProperties === void 0 ? void 0 : distinctIdOrProperties.toString() : `soft_${uuid.v4()}`;
609
- const properties = hasId ? propertiesOrOptions : distinctIdOrProperties;
610
- const options = hasId ? optionsOrNothing : propertiesOrOptions;
616
+ const properties = hasId ? propertiesOrContext : distinctIdOrProperties;
617
+ const context = hasId ? contextOrNothing : propertiesOrContext;
611
618
  // When the user gets identified as null this will reset the users session and anonymous id
612
619
  // This should only be called when distinctId is null and there is an existing userId.
613
620
  // This means the user has logged out and we should reset the session and anonymous IDs
@@ -635,9 +642,9 @@ class Saasco {
635
642
  anonymousId,
636
643
  version: '2',
637
644
  payload: properties || {},
638
- options: options || {}
645
+ context: context || {}
639
646
  };
640
- this.doRequest('identify', data);
647
+ return this.doRequest('identify', data);
641
648
  }
642
649
  /**
643
650
  * Handles sending data to the Saasco API
@@ -646,25 +653,31 @@ class Saasco {
646
653
  * @param data
647
654
  */
648
655
  doRequest(path, data) {
649
- const base = this.config.proxy || 'https://www.saasco.com/api/';
650
- const url = `${base}${path}`;
651
- const logMessage = data.action === 'Page View' ? `Page View ${window.location.pathname}` // if its a page view, include pathname in console log
652
- : data.action || path;
653
- this.log(logMessage, data);
654
- // If analytics is disabled, don't send the request
655
- if (this.config.enabled === false) return;
656
- fetch(url, {
657
- method: 'POST',
658
- headers: {
659
- 'Content-Type': 'application/json'
660
- },
661
- body: JSON.stringify(data)
662
- }).then(response => {
663
- if (!response.ok) {
664
- throw new Error(response.status.toString());
656
+ return tslib.__awaiter(this, void 0, void 0, function* () {
657
+ const base = this.config.proxy || 'https://www.saasco.com/api/';
658
+ const url = `${base}${path}`;
659
+ const logMessage = data.action === 'Page View' ? `Page View ${window.location.pathname}` // if its a page view, include pathname in console log
660
+ : data.action || path;
661
+ this.log(logMessage, data);
662
+ // If analytics is disabled, don't send the request
663
+ if (this.config.enabled === false) return;
664
+ try {
665
+ const response = yield fetch(url, {
666
+ method: 'POST',
667
+ headers: {
668
+ 'Content-Type': 'application/json'
669
+ },
670
+ body: JSON.stringify(data)
671
+ });
672
+ if (!response.ok) {
673
+ throw new Error(response.status.toString());
674
+ }
675
+ return response;
676
+ } catch (error) {
677
+ const errorMessage = 'Error with Saasco request: ' + error.message;
678
+ console.error(errorMessage, path, data);
679
+ return errorMessage;
665
680
  }
666
- }).catch(e => {
667
- console.error('Error with Saasco request: ' + e.message, path, data);
668
681
  });
669
682
  }
670
683
  /**
@@ -673,14 +686,10 @@ class Saasco {
673
686
  log(...args) {
674
687
  if (!this.config.debug) return;
675
688
  const message = '◍ Saasco Debug';
676
- console.log(...[`\x1b[47m\x1b[30m ${message} \x1b[0m`,
689
+ console.info(...[`\x1b[47m\x1b[30m ${message} \x1b[0m`,
677
690
  // Message highlighted for easy finding
678
691
  ...args]);
679
692
  }
680
- getSearchParam(param) {
681
- if (typeof window === 'undefined') return undefined;
682
- return new URLSearchParams(window.location.search).get(param);
683
- }
684
693
  /**
685
694
  * If autoPageTracking is enabled, this will automatically track page views
686
695
  * It listens to url changes to track new pages every time the url changes
@@ -826,49 +835,69 @@ const tinyBirdBaseSchema = zod.z.object({
826
835
  }),
827
836
  rows: zod.z.number()
828
837
  });
838
+ const TinybirdJobResponseSchema = zod.z.object({
839
+ id: zod.z.string(),
840
+ job_id: zod.z.string(),
841
+ job_url: zod.z.string().url(),
842
+ job: zod.z.object({
843
+ kind: zod.z.string(),
844
+ id: zod.z.string(),
845
+ job_id: zod.z.string(),
846
+ status: zod.z.string(),
847
+ created_at: zod.z.string(),
848
+ updated_at: zod.z.string(),
849
+ started_at: zod.z.string().nullable(),
850
+ is_cancellable: zod.z.boolean(),
851
+ datasource: zod.z.object({
852
+ id: zod.z.string(),
853
+ name: zod.z.string()
854
+ }),
855
+ delete_condition: zod.z.string().optional()
856
+ }),
857
+ status: zod.z.string(),
858
+ delete_id: zod.z.string().optional(),
859
+ import_id: zod.z.string().optional()
860
+ });
829
861
  const kpisRequestSchema = zod.z.object({
830
862
  projectId: zod.z.string(),
831
863
  dateTo: zod.z.string().optional(),
832
864
  dateFrom: zod.z.string().optional(),
833
- referringDomain: zod.z.string().optional(),
865
+ referrer: zod.z.string().optional(),
834
866
  location: zod.z.string().optional()
835
867
  });
836
868
  const kpisResponseSchema = tinyBirdBaseSchema.extend({
837
869
  data: zod.z.array(zod.z.object({
838
870
  date: zod.z.string(),
839
- visits: zod.z.number(),
840
- pageviews: zod.z.number(),
871
+ users: zod.z.number(),
872
+ sessions: zod.z.number(),
873
+ pageViews: zod.z.number(),
874
+ events: zod.z.number(),
841
875
  bounceRate: zod.z.nullable(zod.z.number()),
842
876
  avgSessionSec: zod.z.number()
843
877
  }))
844
878
  });
845
- const eventsKpisResponseSchema = tinyBirdBaseSchema.extend({
846
- data: zod.z.array(zod.z.object({
847
- unique: zod.z.number(),
848
- total: zod.z.number()
849
- }))
850
- });
851
879
  const baseTopRequestSchema = zod.z.object({
852
880
  projectId: zod.z.string(),
853
881
  dateTo: zod.z.string().optional(),
854
882
  dateFrom: zod.z.string().optional(),
855
883
  limit: zod.z.number().optional(),
856
884
  skip: zod.z.number().optional(),
857
- referringDomain: zod.z.string().optional(),
885
+ referrer: zod.z.string().optional(),
858
886
  location: zod.z.string().optional()
859
887
  });
860
888
  const topPagesResponseSchema = tinyBirdBaseSchema.extend({
861
889
  data: zod.z.array(zod.z.object({
862
890
  pathname: zod.z.string(),
863
- visits: zod.z.number(),
864
- hits: zod.z.number()
891
+ users: zod.z.number(),
892
+ events: zod.z.number()
865
893
  }))
866
894
  });
867
895
  const topLocationsResponseSchema = tinyBirdBaseSchema.extend({
868
896
  data: zod.z.array(zod.z.object({
869
897
  location: zod.z.string(),
870
- visits: zod.z.number(),
871
- hits: zod.z.number(),
898
+ users: zod.z.number(),
899
+ sessions: zod.z.number(),
900
+ pageViews: zod.z.number(),
872
901
  bounceRate: zod.z.nullable(zod.z.number()),
873
902
  avgSessionSec: zod.z.number()
874
903
  }))
@@ -893,8 +922,9 @@ const topBrowsersResponseSchema = tinyBirdBaseSchema.extend({
893
922
  });
894
923
  const topSourcesSchema = zod.z.object({
895
924
  referrer: zod.z.string(),
896
- visits: zod.z.number(),
897
- hits: zod.z.number(),
925
+ users: zod.z.number(),
926
+ sessions: zod.z.number(),
927
+ pageViews: zod.z.number(),
898
928
  bounceRate: zod.z.nullable(zod.z.number()),
899
929
  avgSessionSec: zod.z.number()
900
930
  });
@@ -904,8 +934,8 @@ const topSourcesResponseSchema = tinyBirdBaseSchema.extend({
904
934
  const topActionsResponseSchema = tinyBirdBaseSchema.extend({
905
935
  data: zod.z.array(zod.z.object({
906
936
  action: zod.z.string(),
907
- unique: zod.z.number(),
908
- total: zod.z.number()
937
+ users: zod.z.number(),
938
+ events: zod.z.number()
909
939
  }))
910
940
  });
911
941
  const analyticsEventSchema = zod.z.object({
@@ -924,7 +954,7 @@ const userEventsResponseSchema = tinyBirdBaseSchema.extend({
924
954
  const currentUsersRequestSchema = zod.z.object({
925
955
  projectId: zod.z.string(),
926
956
  minutes: zod.z.number().optional(),
927
- referringDomain: zod.z.string().optional(),
957
+ referrer: zod.z.string().optional(),
928
958
  location: zod.z.string().optional()
929
959
  });
930
960
  const currentUsersResponseSchema = tinyBirdBaseSchema.extend({
@@ -933,7 +963,7 @@ const currentUsersResponseSchema = tinyBirdBaseSchema.extend({
933
963
  }))
934
964
  });
935
965
  const reservedPropertiesSchema = zod.z.object({
936
- age: zod.z.number().nullish(),
966
+ age: zod.z.number().or(zod.z.string()).nullish(),
937
967
  avatar: zod.z.string().url().nullish(),
938
968
  birthday: zod.z.string().nullish(),
939
969
  createdAt: zod.z.string().nullish(),
@@ -947,9 +977,11 @@ const reservedPropertiesSchema = zod.z.object({
947
977
  phone: zod.z.string().nullish(),
948
978
  title: zod.z.string().nullish(),
949
979
  username: zod.z.string().nullish(),
950
- website: zod.z.string().nullish()
980
+ website: zod.z.string().nullish(),
981
+ $id: zod.z.string().nullish(),
982
+ $lastSeen: zod.z.string().nullish()
951
983
  });
952
- const userPropertiesSchema = reservedPropertiesSchema.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()]))])));
984
+ 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()]))])));
953
985
  const analyticsUserRawSchema = zod.z.object({
954
986
  timestamp: zod.z.string(),
955
987
  distinctId: zod.z.string(),
@@ -959,7 +991,7 @@ const analyticsUserRawSchema = zod.z.object({
959
991
  const analyticsUserSchema = analyticsUserRawSchema.omit({
960
992
  payload: true
961
993
  }).and(zod.z.object({
962
- properties: userPropertiesSchema
994
+ properties: contactPropertiesSchema
963
995
  }));
964
996
  const listUsersParamsSchema = zod.z.object({
965
997
  projectId: zod.z.string(),
@@ -976,21 +1008,22 @@ const idenfitySchema = zod.z.object({
976
1008
  distinctId: zod.z.string(),
977
1009
  anonymousId: zod.z.string(),
978
1010
  version: zod.z.string(),
979
- payload: userPropertiesSchema,
980
- options: zod.z.object({
1011
+ payload: contactPropertiesSchema,
1012
+ context: zod.z.object({
981
1013
  active: zod.z.boolean().optional()
982
1014
  }).optional()
983
1015
  });
984
1016
 
985
1017
  exports.Saasco = Saasco;
1018
+ exports.TinybirdJobResponseSchema = TinybirdJobResponseSchema;
986
1019
  exports.analyticsEventSchema = analyticsEventSchema;
987
1020
  exports.analyticsUserRawSchema = analyticsUserRawSchema;
988
1021
  exports.analyticsUserSchema = analyticsUserSchema;
989
1022
  exports.baseTopRequestSchema = baseTopRequestSchema;
990
1023
  exports.coerceReservedProperties = coerceReservedProperties;
1024
+ exports.contactPropertiesSchema = contactPropertiesSchema;
991
1025
  exports.currentUsersRequestSchema = currentUsersRequestSchema;
992
1026
  exports.currentUsersResponseSchema = currentUsersResponseSchema;
993
- exports.eventsKpisResponseSchema = eventsKpisResponseSchema;
994
1027
  exports.getAnalyticsUserParamsSchema = getAnalyticsUserParamsSchema;
995
1028
  exports.idenfitySchema = idenfitySchema;
996
1029
  exports.kpisRequestSchema = kpisRequestSchema;
@@ -998,6 +1031,7 @@ exports.kpisResponseSchema = kpisResponseSchema;
998
1031
  exports.listUsersParamsSchema = listUsersParamsSchema;
999
1032
  exports.reservedPropertiesSchema = reservedPropertiesSchema;
1000
1033
  exports.tbAny = tbAny;
1034
+ exports.timezones = timezones;
1001
1035
  exports.tinyBirdBaseSchema = tinyBirdBaseSchema;
1002
1036
  exports.topActionsResponseSchema = topActionsResponseSchema;
1003
1037
  exports.topBrowsersResponseSchema = topBrowsersResponseSchema;
@@ -1007,4 +1041,3 @@ exports.topPagesResponseSchema = topPagesResponseSchema;
1007
1041
  exports.topSourcesResponseSchema = topSourcesResponseSchema;
1008
1042
  exports.topSourcesSchema = topSourcesSchema;
1009
1043
  exports.userEventsResponseSchema = userEventsResponseSchema;
1010
- exports.userPropertiesSchema = userPropertiesSchema;