saasco-sdk 0.1.6 → 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/index.esm.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { __awaiter } from 'tslib';
1
2
  import { v4 } from '@lukeed/uuid';
2
3
  import { z } from 'zod';
3
4
 
@@ -429,7 +430,6 @@ const timezones = {
429
430
  'Asia/Calcutta': 'IN'
430
431
  };
431
432
 
432
- /* eslint-disable @typescript-eslint/no-explicit-any */
433
433
  const isBrowser = typeof window !== 'undefined';
434
434
  let userId = null;
435
435
  const PREF = 'saasco-sdk';
@@ -497,6 +497,36 @@ function setAnonmousId({
497
497
  storeData(`anonymous-id`, anonymousId, 1000 * 60 * 60 * 24 * 365);
498
498
  return anonymousId;
499
499
  }
500
+ function getBrowserContext() {
501
+ var _a;
502
+ if (!isBrowser) return {};
503
+ const customNavigator = navigator;
504
+ 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';
505
+ // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
506
+ // Only has 96.63% global support, so we need to check for undefined
507
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
508
+ const $location = timezones[timezone] || ((_a = $locale === null || $locale === void 0 ? void 0 : $locale.split('-')) === null || _a === void 0 ? void 0 : _a[1]) || 'undefined';
509
+ const $href = window.location.href;
510
+ const $pathname = window.location.pathname;
511
+ const $referrer = document.referrer;
512
+ const $screenDPI = window.devicePixelRatio;
513
+ const $screenHeight = screen.height;
514
+ const $screenWidth = screen.width;
515
+ const $title = document.title;
516
+ const $userAgent = window.navigator.userAgent;
517
+ return {
518
+ $locale,
519
+ $location,
520
+ $href,
521
+ $pathname,
522
+ $referrer,
523
+ $screenDPI,
524
+ $screenHeight,
525
+ $screenWidth,
526
+ $title,
527
+ $userAgent
528
+ };
529
+ }
500
530
  class Saasco {
501
531
  /**
502
532
  * Creates an instance of Saasco SDK.
@@ -538,8 +568,7 @@ class Saasco {
538
568
  */
539
569
  track(name,
540
570
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
541
- properties) {
542
- var _a;
571
+ properties, context) {
543
572
  // Prevent duplicate Page View tracking
544
573
  if (name === 'Page View') {
545
574
  if (!isBrowser) {
@@ -552,20 +581,7 @@ class Saasco {
552
581
  }
553
582
  setSessionId();
554
583
  setAnonmousId();
555
- const customNavigator = isBrowser ? navigator : undefined;
556
- 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;
557
- // https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
558
- // Only has 96.63% global support, so we need to check for undefined
559
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
560
- 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;
561
- const $href = isBrowser ? window.location.href : undefined;
562
- const $pathname = isBrowser ? window.location.pathname : undefined;
563
- const $referrer = isBrowser ? document.referrer : undefined;
564
- const $screenDPI = isBrowser ? window.devicePixelRatio : undefined;
565
- const $screenHeight = isBrowser ? screen.height : undefined;
566
- const $screenWidth = isBrowser ? screen.width : undefined;
567
- const $title = isBrowser ? document.title : undefined;
568
- const $userAgent = isBrowser ? window.navigator.userAgent : undefined;
584
+ const browserContext = getBrowserContext();
569
585
  const data = {
570
586
  id: v4(),
571
587
  timestamp: new Date().toISOString(),
@@ -574,21 +590,12 @@ class Saasco {
574
590
  sessionId: getSessionId(),
575
591
  anonymousId: getAnonymousId(),
576
592
  projectId: this.config.projectId,
577
- payload: JSON.stringify({
578
- $href,
579
- $locale,
580
- $location,
581
- $pathname,
582
- $referrer,
583
- $screenDPI,
584
- $screenHeight,
585
- $screenWidth,
586
- $title,
587
- $userAgent,
593
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
588
594
  properties: properties || {}
589
- })
595
+ })),
596
+ context: JSON.stringify(context || {})
590
597
  };
591
- this.doRequest('events', data);
598
+ return this.doRequest('events', data);
592
599
  }
593
600
  /**
594
601
  * The page method lets you record page views on your website
@@ -597,18 +604,22 @@ class Saasco {
597
604
  * Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
598
605
  */
599
606
  page() {
600
- this.track('Page View');
607
+ return this.track('Page View');
601
608
  }
602
- identify(distinctIdOrProperties, propertiesOrOptions, optionsOrNothing) {
609
+ identify(distinctIdOrProperties, propertiesOrContext, contextOrNothing) {
603
610
  const hasId = typeof distinctIdOrProperties === 'string' || typeof distinctIdOrProperties === 'number' || distinctIdOrProperties === null;
604
611
  const distinctId = hasId ? distinctIdOrProperties === null || distinctIdOrProperties === void 0 ? void 0 : distinctIdOrProperties.toString() : `soft_${v4()}`;
605
- const properties = hasId ? propertiesOrOptions : distinctIdOrProperties;
606
- const options = hasId ? optionsOrNothing : propertiesOrOptions;
612
+ const properties = hasId ? propertiesOrContext : distinctIdOrProperties;
613
+ const context = hasId ? contextOrNothing : propertiesOrContext;
607
614
  // When the user gets identified as null this will reset the users session and anonymous id
608
615
  // This should only be called when distinctId is null and there is an existing userId.
609
616
  // This means the user has logged out and we should reset the session and anonymous IDs
610
- const reset = !distinctId && !!userId;
611
- if (reset) this.log('User logged out and session reset');
617
+ const userIdChangedToNull = !distinctId && !!userId;
618
+ if (userIdChangedToNull) this.log('User ID change to null. Session reset');
619
+ // If we have a userId, but a new user ID is provided, we should reset the session and anonymous IDs
620
+ const userIdChanged = !!userId && distinctId !== userId;
621
+ if (userIdChanged) this.log('User ID changed. Session reset');
622
+ const reset = userIdChangedToNull || userIdChanged;
612
623
  setSessionId({
613
624
  reset
614
625
  });
@@ -627,9 +638,9 @@ class Saasco {
627
638
  anonymousId,
628
639
  version: '2',
629
640
  payload: properties || {},
630
- options: options || {}
641
+ context: context || {}
631
642
  };
632
- this.doRequest('identify', data);
643
+ return this.doRequest('identify', data);
633
644
  }
634
645
  /**
635
646
  * Handles sending data to the Saasco API
@@ -638,25 +649,31 @@ class Saasco {
638
649
  * @param data
639
650
  */
640
651
  doRequest(path, data) {
641
- const base = this.config.proxy || 'https://www.saasco.com/api/';
642
- const url = `${base}${path}`;
643
- const logMessage = data.action === 'Page View' ? `Page View ${window.location.pathname}` // if its a page view, include pathname in console log
644
- : data.action || path;
645
- this.log(logMessage, data);
646
- // If analytics is disabled, don't send the request
647
- if (this.config.enabled === false) return;
648
- fetch(url, {
649
- method: 'POST',
650
- headers: {
651
- 'Content-Type': 'application/json'
652
- },
653
- body: JSON.stringify(data)
654
- }).then(response => {
655
- if (!response.ok) {
656
- throw new Error(response.status.toString());
652
+ return __awaiter(this, void 0, void 0, function* () {
653
+ const base = this.config.proxy || 'https://www.saasco.com/api/';
654
+ const url = `${base}${path}`;
655
+ const logMessage = data.action === 'Page View' ? `Page View ${window.location.pathname}` // if its a page view, include pathname in console log
656
+ : data.action || path;
657
+ this.log(logMessage, data);
658
+ // If analytics is disabled, don't send the request
659
+ if (this.config.enabled === false) return;
660
+ try {
661
+ const response = yield fetch(url, {
662
+ method: 'POST',
663
+ headers: {
664
+ 'Content-Type': 'application/json'
665
+ },
666
+ body: JSON.stringify(data)
667
+ });
668
+ if (!response.ok) {
669
+ throw new Error(response.status.toString());
670
+ }
671
+ return response;
672
+ } catch (error) {
673
+ const errorMessage = 'Error with Saasco request: ' + error.message;
674
+ console.error(errorMessage, path, data);
675
+ return errorMessage;
657
676
  }
658
- }).catch(e => {
659
- console.error('Error with Saasco request: ' + e.message, path, data);
660
677
  });
661
678
  }
662
679
  /**
@@ -665,14 +682,10 @@ class Saasco {
665
682
  log(...args) {
666
683
  if (!this.config.debug) return;
667
684
  const message = '◍ Saasco Debug';
668
- console.log(...[`\x1b[47m\x1b[30m ${message} \x1b[0m`,
685
+ console.info(...[`\x1b[47m\x1b[30m ${message} \x1b[0m`,
669
686
  // Message highlighted for easy finding
670
687
  ...args]);
671
688
  }
672
- getSearchParam(param) {
673
- if (typeof window === 'undefined') return undefined;
674
- return new URLSearchParams(window.location.search).get(param);
675
- }
676
689
  /**
677
690
  * If autoPageTracking is enabled, this will automatically track page views
678
691
  * It listens to url changes to track new pages every time the url changes
@@ -764,8 +777,7 @@ function coerceReservedProperties(properties) {
764
777
  schema: z.coerce.string().url().optional()
765
778
  }, {
766
779
  key: 'displayName',
767
- coerceFrom: ['display_name', 'displayName', 'user_display_name', 'userDisplayName', 'full_name', 'fullName', 'user_full_name', 'userFullName', 'complete_name', 'completeName', 'user_complete_name', 'userCompleteName', 'name', 'username'],
768
- schema: z.coerce.string().url().optional()
780
+ coerceFrom: ['display_name', 'displayName', 'user_display_name', 'userDisplayName', 'full_name', 'fullName', 'user_full_name', 'userFullName', 'complete_name', 'completeName', 'user_complete_name', 'userCompleteName', 'name', 'username']
769
781
  }];
770
782
  return coerce.reduce((acc, {
771
783
  key,
@@ -819,49 +831,69 @@ const tinyBirdBaseSchema = z.object({
819
831
  }),
820
832
  rows: z.number()
821
833
  });
834
+ const TinybirdJobResponseSchema = z.object({
835
+ id: z.string(),
836
+ job_id: z.string(),
837
+ job_url: z.string().url(),
838
+ job: z.object({
839
+ kind: z.string(),
840
+ id: z.string(),
841
+ job_id: z.string(),
842
+ status: z.string(),
843
+ created_at: z.string(),
844
+ updated_at: z.string(),
845
+ started_at: z.string().nullable(),
846
+ is_cancellable: z.boolean(),
847
+ datasource: z.object({
848
+ id: z.string(),
849
+ name: z.string()
850
+ }),
851
+ delete_condition: z.string().optional()
852
+ }),
853
+ status: z.string(),
854
+ delete_id: z.string().optional(),
855
+ import_id: z.string().optional()
856
+ });
822
857
  const kpisRequestSchema = z.object({
823
858
  projectId: z.string(),
824
859
  dateTo: z.string().optional(),
825
860
  dateFrom: z.string().optional(),
826
- referringDomain: z.string().optional(),
861
+ referrer: z.string().optional(),
827
862
  location: z.string().optional()
828
863
  });
829
864
  const kpisResponseSchema = tinyBirdBaseSchema.extend({
830
865
  data: z.array(z.object({
831
866
  date: z.string(),
832
- visits: z.number(),
833
- pageviews: z.number(),
867
+ users: z.number(),
868
+ sessions: z.number(),
869
+ pageViews: z.number(),
870
+ events: z.number(),
834
871
  bounceRate: z.nullable(z.number()),
835
872
  avgSessionSec: z.number()
836
873
  }))
837
874
  });
838
- const eventsKpisResponseSchema = tinyBirdBaseSchema.extend({
839
- data: z.array(z.object({
840
- unique: z.number(),
841
- total: z.number()
842
- }))
843
- });
844
875
  const baseTopRequestSchema = z.object({
845
876
  projectId: z.string(),
846
877
  dateTo: z.string().optional(),
847
878
  dateFrom: z.string().optional(),
848
879
  limit: z.number().optional(),
849
880
  skip: z.number().optional(),
850
- referringDomain: z.string().optional(),
881
+ referrer: z.string().optional(),
851
882
  location: z.string().optional()
852
883
  });
853
884
  const topPagesResponseSchema = tinyBirdBaseSchema.extend({
854
885
  data: z.array(z.object({
855
886
  pathname: z.string(),
856
- visits: z.number(),
857
- hits: z.number()
887
+ users: z.number(),
888
+ events: z.number()
858
889
  }))
859
890
  });
860
891
  const topLocationsResponseSchema = tinyBirdBaseSchema.extend({
861
892
  data: z.array(z.object({
862
893
  location: z.string(),
863
- visits: z.number(),
864
- hits: z.number(),
894
+ users: z.number(),
895
+ sessions: z.number(),
896
+ pageViews: z.number(),
865
897
  bounceRate: z.nullable(z.number()),
866
898
  avgSessionSec: z.number()
867
899
  }))
@@ -886,8 +918,9 @@ const topBrowsersResponseSchema = tinyBirdBaseSchema.extend({
886
918
  });
887
919
  const topSourcesSchema = z.object({
888
920
  referrer: z.string(),
889
- visits: z.number(),
890
- hits: z.number(),
921
+ users: z.number(),
922
+ sessions: z.number(),
923
+ pageViews: z.number(),
891
924
  bounceRate: z.nullable(z.number()),
892
925
  avgSessionSec: z.number()
893
926
  });
@@ -897,8 +930,8 @@ const topSourcesResponseSchema = tinyBirdBaseSchema.extend({
897
930
  const topActionsResponseSchema = tinyBirdBaseSchema.extend({
898
931
  data: z.array(z.object({
899
932
  action: z.string(),
900
- unique: z.number(),
901
- total: z.number()
933
+ users: z.number(),
934
+ events: z.number()
902
935
  }))
903
936
  });
904
937
  const analyticsEventSchema = z.object({
@@ -917,7 +950,7 @@ const userEventsResponseSchema = tinyBirdBaseSchema.extend({
917
950
  const currentUsersRequestSchema = z.object({
918
951
  projectId: z.string(),
919
952
  minutes: z.number().optional(),
920
- referringDomain: z.string().optional(),
953
+ referrer: z.string().optional(),
921
954
  location: z.string().optional()
922
955
  });
923
956
  const currentUsersResponseSchema = tinyBirdBaseSchema.extend({
@@ -926,7 +959,7 @@ const currentUsersResponseSchema = tinyBirdBaseSchema.extend({
926
959
  }))
927
960
  });
928
961
  const reservedPropertiesSchema = z.object({
929
- age: z.number().nullish(),
962
+ age: z.number().or(z.string()).nullish(),
930
963
  avatar: z.string().url().nullish(),
931
964
  birthday: z.string().nullish(),
932
965
  createdAt: z.string().nullish(),
@@ -940,9 +973,11 @@ const reservedPropertiesSchema = z.object({
940
973
  phone: z.string().nullish(),
941
974
  title: z.string().nullish(),
942
975
  username: z.string().nullish(),
943
- website: z.string().nullish()
976
+ website: z.string().nullish(),
977
+ $id: z.string().nullish(),
978
+ $lastSeen: z.string().nullish()
944
979
  });
945
- const userPropertiesSchema = reservedPropertiesSchema.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()]))])));
980
+ 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()]))])));
946
981
  const analyticsUserRawSchema = z.object({
947
982
  timestamp: z.string(),
948
983
  distinctId: z.string(),
@@ -952,7 +987,7 @@ const analyticsUserRawSchema = z.object({
952
987
  const analyticsUserSchema = analyticsUserRawSchema.omit({
953
988
  payload: true
954
989
  }).and(z.object({
955
- properties: userPropertiesSchema
990
+ properties: contactPropertiesSchema
956
991
  }));
957
992
  const listUsersParamsSchema = z.object({
958
993
  projectId: z.string(),
@@ -969,10 +1004,10 @@ const idenfitySchema = z.object({
969
1004
  distinctId: z.string(),
970
1005
  anonymousId: z.string(),
971
1006
  version: z.string(),
972
- payload: userPropertiesSchema,
973
- options: z.object({
1007
+ payload: contactPropertiesSchema,
1008
+ context: z.object({
974
1009
  active: z.boolean().optional()
975
1010
  }).optional()
976
1011
  });
977
1012
 
978
- export { Saasco, analyticsEventSchema, analyticsUserRawSchema, analyticsUserSchema, baseTopRequestSchema, coerceReservedProperties, currentUsersRequestSchema, currentUsersResponseSchema, eventsKpisResponseSchema, getAnalyticsUserParamsSchema, idenfitySchema, kpisRequestSchema, kpisResponseSchema, listUsersParamsSchema, reservedPropertiesSchema, tbAny, tinyBirdBaseSchema, topActionsResponseSchema, topBrowsersResponseSchema, topDevicesResponseSchema, topLocationsResponseSchema, topPagesResponseSchema, topSourcesResponseSchema, topSourcesSchema, userEventsResponseSchema, userPropertiesSchema };
1013
+ export { Saasco, TinybirdJobResponseSchema, analyticsEventSchema, analyticsUserRawSchema, analyticsUserSchema, baseTopRequestSchema, coerceReservedProperties, contactPropertiesSchema, currentUsersRequestSchema, currentUsersResponseSchema, getAnalyticsUserParamsSchema, idenfitySchema, kpisRequestSchema, kpisResponseSchema, listUsersParamsSchema, reservedPropertiesSchema, tbAny, timezones, tinyBirdBaseSchema, topActionsResponseSchema, topBrowsersResponseSchema, topDevicesResponseSchema, topLocationsResponseSchema, topPagesResponseSchema, topSourcesResponseSchema, topSourcesSchema, userEventsResponseSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasco-sdk",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.0",
6
6
  "@lukeed/uuid": "^2.0.1",
package/src/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './lib/analytics';
2
2
  export * from './lib/coerceReservedProperties';
3
+ export * from './lib/timezones';
3
4
  export * from './lib/types';
@@ -34,14 +34,16 @@ export declare class Saasco {
34
34
  * @param name The name of the event eg "Song Played"
35
35
  * @param properties The properties of the event eg { genre: "Classics", song: "Never Gonna Give You Up" }
36
36
  */
37
- track(name: string, properties?: Record<string, any>): void;
37
+ track(name: string, properties?: Record<string, any>, context?: {
38
+ active?: boolean;
39
+ }): Promise<string | Response | undefined> | undefined;
38
40
  /**
39
41
  * The page method lets you record page views on your website
40
42
  * This records the page title and path and names the event useing the reserved property "Page Viewed"
41
43
  *
42
44
  * Before implementing this make sure you have disabled the autoPageTracking in the config or you will get duplicate page views
43
45
  */
44
- page(): void;
46
+ page(): Promise<string | Response | undefined> | undefined;
45
47
  /**
46
48
  * The identify method lets you tie a user to their actions and record traits about them.
47
49
  * We recommend you call this when the user logs in and when any traits get updated.
@@ -49,12 +51,12 @@ export declare class Saasco {
49
51
  *
50
52
  * @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.
51
53
  * @param properties A dictionary of traits you know about the user like their email, name, plan etc.
52
- * @param options Options for the identify call such as whether the user is active.
54
+ * @param context Context for the identify call such as whether the user is active.
53
55
  */
54
- identify(properties: Record<string, any>, options?: {
56
+ identify(properties: Record<string, any>, context?: {
55
57
  active?: boolean;
56
58
  }): void;
57
- identify(distinctId: string | number | null, properties?: Record<string, any>, options?: {
59
+ identify(distinctId: string | number | null, properties?: Record<string, any>, context?: {
58
60
  active?: boolean;
59
61
  }): void;
60
62
  /**
@@ -68,7 +70,6 @@ export declare class Saasco {
68
70
  * @param args Arguments to be logged
69
71
  */
70
72
  private log;
71
- private getSearchParam;
72
73
  /**
73
74
  * If autoPageTracking is enabled, this will automatically track page views
74
75
  * It listens to url changes to track new pages every time the url changes