saasco-sdk 0.1.21 → 0.1.23

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
@@ -54,7 +54,7 @@ You can also [manually track pages](https://www.notion.so/Manual-Page-Tracking-i
54
54
 
55
55
  ## Tracking Events
56
56
 
57
- With events you can track custom actions users are taking on your site with event properties.
57
+ With events you can track custom actions users are taking on your site with event properties. The track method supports both client-side (oarameter-style) and server-side (object-style) usage patterns.
58
58
 
59
59
  Each event has 2 components:
60
60
 
@@ -66,6 +66,11 @@ _We like to follow segments [Object Action Framework](https://segment.com/academ
66
66
 
67
67
  We currently have limited support for properties, but in the future we will support complex querying and actions based on event properties.
68
68
 
69
+ ### Client Usage
70
+
71
+ For client-side tracking, use the Segment-compatible syntax.
72
+ This will automatically assign userId based on identify calls during the session
73
+
69
74
  ```tsx
70
75
  // Import saasco
71
76
  import { saasco } from '../lib/saasco.ts';
@@ -80,6 +85,24 @@ saasco.track("Searched Movies", {
80
85
  });
81
86
  ```
82
87
 
88
+ ### Server Usage (Object Style)
89
+
90
+ For server-side tracking, use the object-style syntax.
91
+ You must provide a userId for server side tracking events.
92
+
93
+ ```tsx
94
+ // Import saasco
95
+ import { saasco } from '../lib/saasco.ts';
96
+
97
+ // Track an event with full control
98
+ saasco.track({
99
+ event: "User Signed Up",
100
+ userId: "user_123",
101
+ properties: { plan: "Pro" },
102
+ context: { source: "server" },
103
+ });
104
+ ```
105
+
83
106
  ## Identifying Users
84
107
 
85
108
  By default Saasco does not track any identifiable data about users, just anonymous user ids and session ids. However if you want to tie events to users you can identify users which will connect events to users in your CRM and power tools like drip campaigns and customer support.
package/index.cjs.js CHANGED
@@ -6,7 +6,7 @@ var tslib = require('tslib');
6
6
  var uuid = require('@lukeed/uuid');
7
7
  var zod = require('zod');
8
8
 
9
- var version = "0.1.21";
9
+ var version = "0.1.23";
10
10
 
11
11
  const timezones = {
12
12
  'Asia/Barnaul': 'RU',
@@ -469,6 +469,7 @@ function getBrowserContext() {
469
469
  }
470
470
 
471
471
  const isBrowser = typeof window !== 'undefined';
472
+ const isServer = !isBrowser;
472
473
  const PREF = 'saasco-sdk';
473
474
  const data = {};
474
475
  function storeData(key, value, ttl) {
@@ -476,7 +477,7 @@ function storeData(key, value, ttl) {
476
477
  value,
477
478
  expiry: new Date().getTime() + ttl
478
479
  };
479
- if (!isBrowser) {
480
+ if (isServer) {
480
481
  if (value === undefined) {
481
482
  delete data[key];
482
483
  return;
@@ -489,7 +490,7 @@ function storeData(key, value, ttl) {
489
490
  localStorage.setItem(fullKey, JSON.stringify(item));
490
491
  }
491
492
  function retrieveData(key) {
492
- if (!isBrowser) {
493
+ if (isServer) {
493
494
  const item = data[key];
494
495
  if (!item) return null;
495
496
  if (Date.now() > item.expiry) {
@@ -592,37 +593,46 @@ class Saasco {
592
593
  this.config.debug = true;
593
594
  this.log('Debug mode activated.');
594
595
  }
595
- /**
596
- * The track method lets you record the actions your users perform.
597
- * Its good to keep a conistent naming convention for your events.
598
- * We like the Object Action Framework from segment:
599
- * https://segment.com/academy/collecting-data/naming-conventions-for-clean-data/
600
- *
601
- * @param name The name of the event eg "Song Played"
602
- * @param properties The properties of the event eg { genre: "Classics", song: "Never Gonna Give You Up" }
603
- */
604
- track(name,
605
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
606
- properties, context) {
596
+ track(actionOrPayload, propertiesOrNothing, contextOrNothing) {
607
597
  if (!this.config.projectId) {
608
598
  const response = 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.");
609
599
  return Promise.resolve(response);
610
600
  }
611
601
  setSessionId();
612
602
  setAnonmousId();
613
- const browserContext = getBrowserContext();
603
+ const hasAction = typeof actionOrPayload === 'string';
604
+ const hasPayload = typeof actionOrPayload === 'object';
605
+ // Must do payload on the server
606
+ if (isServer && hasAction) {
607
+ const response = this.error('When calling track from the server you must pass a payload object with a userId in order to track events. For example: track({ event: "Song Played", userId: "user_123", properties: { song: "Song Name" } })');
608
+ return Promise.resolve(response);
609
+ }
610
+ // On server events we require a userId or an anonymousId
611
+ if (isServer && hasPayload && !actionOrPayload.userId && !actionOrPayload.anonymousId) {
612
+ const response = this.error('When calling track from the server you must pass a payload object with either a userId or an anonymousId in order to track events. For example:\n\ntrack({ event: "Song Played", userId: "user_123", properties: { song: "Song Name" } }). \n\nIf providing an anonymousId this must be provided from the client side otherwise we will not have a user to connect the event to.');
613
+ return Promise.resolve(response);
614
+ }
615
+ const action = hasAction ? actionOrPayload : actionOrPayload.event;
616
+ const properties = hasAction ? propertiesOrNothing : actionOrPayload.properties;
617
+ const context = hasAction ? contextOrNothing : actionOrPayload.context;
618
+ const sessionId = (hasAction ? undefined : actionOrPayload.sessionId) || getSessionId();
619
+ const anonymousId = (hasAction ? undefined : actionOrPayload.anonymousId) || getAnonymousId();
620
+ const distinctId = (hasAction ? undefined : actionOrPayload.userId) || getUserId();
621
+ // Only gets browser context if in the browser
622
+ const browserContext = isBrowser ? getBrowserContext() || {} : {};
614
623
  const data = {
615
624
  id: uuid.v4(),
616
625
  timestamp: new Date().toISOString(),
617
- action: name,
626
+ action,
618
627
  version,
619
- sessionId: getSessionId(),
620
- anonymousId: getAnonymousId(),
621
- distinctId: getUserId(),
628
+ sessionId,
629
+ anonymousId,
630
+ distinctId,
622
631
  projectId: this.config.projectId,
623
- payload: JSON.stringify(Object.assign(Object.assign({}, browserContext || {}), {
632
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
624
633
  properties: properties || {}
625
634
  })),
635
+ source: isBrowser ? 'client' : 'server',
626
636
  context: JSON.stringify(context || {})
627
637
  };
628
638
  return this.doRequest('events', data);
@@ -635,7 +645,7 @@ class Saasco {
635
645
  */
636
646
  page() {
637
647
  var _a, _b;
638
- if (!isBrowser) {
648
+ if (isServer) {
639
649
  console.warn('Saasco page tracking is only available in the browser');
640
650
  return;
641
651
  }
@@ -782,7 +792,7 @@ class Saasco {
782
792
  // Disable auto page tracking if the config is set to false
783
793
  if (!((_a = this.config.autoPageTracking) === null || _a === void 0 ? void 0 : _a.enabled)) return;
784
794
  // Prevent running on the server
785
- if (!isBrowser) return console.warn('Saasco auto page tracking is only available in the browser');
795
+ if (isServer) return console.warn('Saasco auto page tracking is only available in the browser');
786
796
  // Prevent intitializing auto page tracking more than once
787
797
  if (window.saascoAutoPageTrackingActive) {
788
798
  this.log('Auto Page Tracking already enabled');
package/index.esm.js CHANGED
@@ -2,7 +2,7 @@ import { __awaiter } from 'tslib';
2
2
  import { v4 } from '@lukeed/uuid';
3
3
  import { z } from 'zod';
4
4
 
5
- var version = "0.1.21";
5
+ var version = "0.1.23";
6
6
 
7
7
  const timezones = {
8
8
  'Asia/Barnaul': 'RU',
@@ -465,6 +465,7 @@ function getBrowserContext() {
465
465
  }
466
466
 
467
467
  const isBrowser = typeof window !== 'undefined';
468
+ const isServer = !isBrowser;
468
469
  const PREF = 'saasco-sdk';
469
470
  const data = {};
470
471
  function storeData(key, value, ttl) {
@@ -472,7 +473,7 @@ function storeData(key, value, ttl) {
472
473
  value,
473
474
  expiry: new Date().getTime() + ttl
474
475
  };
475
- if (!isBrowser) {
476
+ if (isServer) {
476
477
  if (value === undefined) {
477
478
  delete data[key];
478
479
  return;
@@ -485,7 +486,7 @@ function storeData(key, value, ttl) {
485
486
  localStorage.setItem(fullKey, JSON.stringify(item));
486
487
  }
487
488
  function retrieveData(key) {
488
- if (!isBrowser) {
489
+ if (isServer) {
489
490
  const item = data[key];
490
491
  if (!item) return null;
491
492
  if (Date.now() > item.expiry) {
@@ -588,37 +589,46 @@ class Saasco {
588
589
  this.config.debug = true;
589
590
  this.log('Debug mode activated.');
590
591
  }
591
- /**
592
- * The track method lets you record the actions your users perform.
593
- * Its good to keep a conistent naming convention for your events.
594
- * We like the Object Action Framework from segment:
595
- * https://segment.com/academy/collecting-data/naming-conventions-for-clean-data/
596
- *
597
- * @param name The name of the event eg "Song Played"
598
- * @param properties The properties of the event eg { genre: "Classics", song: "Never Gonna Give You Up" }
599
- */
600
- track(name,
601
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
602
- properties, context) {
592
+ track(actionOrPayload, propertiesOrNothing, contextOrNothing) {
603
593
  if (!this.config.projectId) {
604
594
  const response = 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.");
605
595
  return Promise.resolve(response);
606
596
  }
607
597
  setSessionId();
608
598
  setAnonmousId();
609
- const browserContext = getBrowserContext();
599
+ const hasAction = typeof actionOrPayload === 'string';
600
+ const hasPayload = typeof actionOrPayload === 'object';
601
+ // Must do payload on the server
602
+ if (isServer && hasAction) {
603
+ const response = this.error('When calling track from the server you must pass a payload object with a userId in order to track events. For example: track({ event: "Song Played", userId: "user_123", properties: { song: "Song Name" } })');
604
+ return Promise.resolve(response);
605
+ }
606
+ // On server events we require a userId or an anonymousId
607
+ if (isServer && hasPayload && !actionOrPayload.userId && !actionOrPayload.anonymousId) {
608
+ const response = this.error('When calling track from the server you must pass a payload object with either a userId or an anonymousId in order to track events. For example:\n\ntrack({ event: "Song Played", userId: "user_123", properties: { song: "Song Name" } }). \n\nIf providing an anonymousId this must be provided from the client side otherwise we will not have a user to connect the event to.');
609
+ return Promise.resolve(response);
610
+ }
611
+ const action = hasAction ? actionOrPayload : actionOrPayload.event;
612
+ const properties = hasAction ? propertiesOrNothing : actionOrPayload.properties;
613
+ const context = hasAction ? contextOrNothing : actionOrPayload.context;
614
+ const sessionId = (hasAction ? undefined : actionOrPayload.sessionId) || getSessionId();
615
+ const anonymousId = (hasAction ? undefined : actionOrPayload.anonymousId) || getAnonymousId();
616
+ const distinctId = (hasAction ? undefined : actionOrPayload.userId) || getUserId();
617
+ // Only gets browser context if in the browser
618
+ const browserContext = isBrowser ? getBrowserContext() || {} : {};
610
619
  const data = {
611
620
  id: v4(),
612
621
  timestamp: new Date().toISOString(),
613
- action: name,
622
+ action,
614
623
  version,
615
- sessionId: getSessionId(),
616
- anonymousId: getAnonymousId(),
617
- distinctId: getUserId(),
624
+ sessionId,
625
+ anonymousId,
626
+ distinctId,
618
627
  projectId: this.config.projectId,
619
- payload: JSON.stringify(Object.assign(Object.assign({}, browserContext || {}), {
628
+ payload: JSON.stringify(Object.assign(Object.assign({}, browserContext), {
620
629
  properties: properties || {}
621
630
  })),
631
+ source: isBrowser ? 'client' : 'server',
622
632
  context: JSON.stringify(context || {})
623
633
  };
624
634
  return this.doRequest('events', data);
@@ -631,7 +641,7 @@ class Saasco {
631
641
  */
632
642
  page() {
633
643
  var _a, _b;
634
- if (!isBrowser) {
644
+ if (isServer) {
635
645
  console.warn('Saasco page tracking is only available in the browser');
636
646
  return;
637
647
  }
@@ -778,7 +788,7 @@ class Saasco {
778
788
  // Disable auto page tracking if the config is set to false
779
789
  if (!((_a = this.config.autoPageTracking) === null || _a === void 0 ? void 0 : _a.enabled)) return;
780
790
  // Prevent running on the server
781
- if (!isBrowser) return console.warn('Saasco auto page tracking is only available in the browser');
791
+ if (isServer) return console.warn('Saasco auto page tracking is only available in the browser');
782
792
  // Prevent intitializing auto page tracking more than once
783
793
  if (window.saascoAutoPageTrackingActive) {
784
794
  this.log('Auto Page Tracking already enabled');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasco-sdk",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.0",
6
6
  "@lukeed/uuid": "^2.0.1",
@@ -4,6 +4,19 @@ declare global {
4
4
  saasco: Saasco;
5
5
  }
6
6
  }
7
+ type Identity = {
8
+ userId: string | number;
9
+ anonymousId?: string | number;
10
+ } | {
11
+ anonymousId: string | number;
12
+ userId?: string | number;
13
+ };
14
+ type TrackPayload = Identity & {
15
+ event: string;
16
+ sessionId?: string;
17
+ properties?: Record<string, any>;
18
+ context?: Record<string, any>;
19
+ };
7
20
  type DoRequestResponse = {
8
21
  success: boolean;
9
22
  message: string;
@@ -38,17 +51,14 @@ export declare class Saasco {
38
51
  disableDebug(): void;
39
52
  enableDebug(): void;
40
53
  /**
41
- * The track method lets you record the actions your users perform.
42
- * Its good to keep a conistent naming convention for your events.
43
- * We like the Object Action Framework from segment:
44
- * https://segment.com/academy/collecting-data/naming-conventions-for-clean-data/
45
- *
46
- * @param name The name of the event eg "Song Played"
47
- * @param properties The properties of the event eg { genre: "Classics", song: "Never Gonna Give You Up" }
54
+ * Track events with support for both client (Segment-style) and server (object-style) usage
55
+ * Client: track('User Signed Up', { plan: 'Pro' }, { source: 'client' })
56
+ * Server: track({ event: 'User Signed Up', userId: 'user_123', properties: { plan: 'Pro' } })
48
57
  */
49
- track(name: string, properties?: Record<string, any>, context?: {
58
+ track(action: string, properties?: Record<string, any>, context?: {
50
59
  active?: boolean;
51
60
  }): Promise<DoRequestResponse>;
61
+ track(payload: TrackPayload): Promise<DoRequestResponse>;
52
62
  /**
53
63
  * The page method lets you record page views on your website
54
64
  * This records the page title and path and names the event useing the reserved property "Page Viewed"