saasco-sdk 0.1.22 → 0.1.24

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
@@ -3,8 +3,8 @@
3
3
  ---
4
4
 
5
5
  - [Privacy](#privacy)
6
- - [Getting Started](#initiate-the-lib)
7
- - [Init Automatic Page View Tracking](#init-automatic-page-view-tracking)
6
+ - [Getting Started](#getting-started)
7
+ - [Automatic Page View Tracking](#automatic-page-view-tracking)
8
8
  - [Tracking Events](#tracking-events)
9
9
  - [Identifying Users](#identifying-users)
10
10
  - [Debugging and Dev](#debugging-and-dev)
@@ -12,7 +12,7 @@
12
12
 
13
13
  <br />
14
14
 
15
- ## 🔒 Privacy
15
+ ## 🔒 Privacy
16
16
 
17
17
  By default Saasco is privacy friendly, using no cookies and obscuring all activity behind Anonymous IDs. However if you want to power more complex user tracking you can identify users and then all events they do will be attributed to them in your CRM. This can assist with customer support but also for things like drip campaigns and other marketing activities.
18
18
 
@@ -22,9 +22,9 @@ Install by running:
22
22
  `npm install saasco-sdk`
23
23
 
24
24
  Copy your Project ID from the project settings page in Saasco:
25
- [https://saasco.com/your-project/settings/project](https://saasco.com/your-projects/settings/project)
25
+ [https://www.saasco.com/projects/your-project/apps/dashboard/settings/project](https://www.saasco.com/projects/your-project/apps/dashboard/settings/project)
26
26
 
27
- Then import Saasco and initiate the lib with your Project ID.
27
+ Then import Saasco and initialize the lib with your Project ID.
28
28
 
29
29
  ```ts
30
30
  // lib/saasco.ts
@@ -35,7 +35,7 @@ export const saasco = new Saasco({ projectId: 'YOUR-PROJECT-ID' });
35
35
 
36
36
  ## Automatic Page View Tracking
37
37
 
38
- When you initiate the lib Saasco will automatically start tracking all page views in your app. By default, it tracks all URL changes, including query parameters and hash changes. You can customize this behavior using the `autoPageTracking` configuration object:
38
+ When you initialize the lib Saasco will automatically start tracking all page views in your app. By default, it tracks all URL changes, including query parameters and hash changes. You can customize this behavior using the `autoPageTracking` configuration object:
39
39
 
40
40
  ```typescript
41
41
  const analytics = new Saasco({
@@ -54,18 +54,23 @@ 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 (parameter-style) and server-side (object-style) usage patterns.
58
58
 
59
59
  Each event has 2 components:
60
60
 
61
61
  **Name** - this is the name of the action that was taken.
62
62
 
63
- _We like to follow segments [Object Action Framework](https://segment.com/academy/collecting-data/naming-conventions-for-clean-data/) for naming events._
63
+ _We like to follow Segment's [Object Action Framework](https://segment.com/academy/collecting-data/naming-conventions-for-clean-data/) for naming events._
64
64
 
65
- **Properties** - This is an object with the values of the event. Such as a the value, currency, or query.
65
+ **Properties** - This is an object with the values of the event. Such as the value, currency, or query.
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,25 @@ 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 so there is a contact to connect the events to.
92
+
93
+ ```tsx
94
+ // Import saasco
95
+ import { saasco } from '../lib/saasco.ts';
96
+
97
+ // Track an event and associate it with a user
98
+ saasco.track({
99
+ event: "Signed Up",
100
+ userId: "user_123",
101
+ properties: {
102
+ provider: 'email',
103
+ }
104
+ });
105
+ ```
106
+
83
107
  ## Identifying Users
84
108
 
85
109
  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.
@@ -110,7 +134,7 @@ function signedOut(){
110
134
 
111
135
  ### Identifying users who don't have an ID
112
136
 
113
- Often times you have a users contact details before they sign up for your site. This could be part of the signup flow, or if they were to subscribe to marketing emails before they sign up as a customer
137
+ Often times you have a user's contact details before they sign up for your site. This could be part of the signup flow, or if they were to subscribe to marketing emails before they sign up as a customer
114
138
 
115
139
  Saasco allows identifying users without an id by simply skipping the `ID` part of the identify call. This will add contacts to the CRM for email marketing and other tools before users register.
116
140
 
@@ -129,7 +153,7 @@ By doing this users will get tracked and added to your contacts, and as soon as
129
153
 
130
154
  ### Soft vs Full identify
131
155
 
132
- When users are identified without a `ID` we call this is a "Soft Identify". Users who are soft identified can also be called "Leads".
156
+ When users are identified without an `ID` we call this a "Soft Identify". Users who are soft identified can also be called "Leads".
133
157
  Once a user signs up and you identify them with an `ID` they will be fully registered and can be called "Customers"
134
158
 
135
159
  In the CRM when you identify a user, either soft or full, they become a contact.
@@ -152,43 +176,50 @@ export const saasco = new Saasco({
152
176
 
153
177
  #### Debugging
154
178
 
155
- You can turn on debugging when you initiate the repo or by running saasco.debug(true) in your code or the browser.
179
+ You can turn on debugging when you initialize the repo or by running `saasco.enableDebug()` in your code or the browser.
156
180
 
157
181
  ```tsx
158
182
  export const saasco = new Saasco({
159
183
  projectId: 'YOUR-PROJECT-ID',
160
184
  enabled: process.env['NODE_ENV'] === 'production',
161
185
  // Set to true to console log analytics events.
162
- // This works even when enabled is false - it just wont send the data
186
+ // This works even when enabled is false - it just won't send the data
163
187
  debug: true,
164
188
  });
165
189
  ```
166
190
 
167
- You can also enable debug mode by calling `saasco.debug(true)` anywhere in your code.
191
+ You can also enable debug mode by calling `saasco.enableDebug()` anywhere in your code.
168
192
 
169
193
  ```tsx
170
- saasco.debug(true);
194
+ saasco.enableDebug();
171
195
  // will console log "debug mode activated"
172
196
  ```
173
197
 
198
+ You can disable debug mode by calling `saasco.disableDebug()`.
199
+
200
+ ```tsx
201
+ saasco.disableDebug();
202
+ // will console log "debug mode deactivated"
203
+ ```
204
+
174
205
  ## Reserved Properties
175
206
 
176
- Saasco has reserved some properties that have semantic meanings for contacts and, and will handle them in special ways.
207
+ Saasco has reserved some properties that have semantic meanings for contacts and will handle them in special ways.
177
208
  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.
178
209
  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.
179
210
 
180
211
  ### Reserved Contact Properties
181
212
 
182
- | PROPTERTY | TYPE | DESCRIPTION |
213
+ | PROPERTY | TYPE | DESCRIPTION |
183
214
  | ----------- | ------ | ----------------------------------------------------------------------------------------------------------------- |
184
215
  | age | Number | Age of a user |
185
216
  | avatar | String | URL to an avatar image for the user |
186
217
  | birthday | Date | User's birthday |
187
- | createdAt | Date | Date the user's account was first created. We recomend recommend using ISO-8601 date strings. |
218
+ | createdAt | Date | Date the user's account was first created. We recommend using ISO-8601 date strings. |
188
219
  | description | String | Description of the user |
189
220
  | email | String | Email address of a user |
190
221
  | firstName | String | First name of a user |
191
- | displayName | String | The prefered users display name, will default to "firstName lastName" |
222
+ | displayName | String | The preferred user's display name, will default to "firstName lastName" |
192
223
  | gender | String | Gender of a user |
193
224
  | lastName | String | Last name of a user |
194
225
  | 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. |
@@ -213,11 +244,11 @@ Any property that starts with `$` is a property that has been generated by the S
213
244
  | $locale | Locale | The most recent preferred language of the user. |
214
245
  | $screenHeight | Screen Height | The most recent height of the device screen in pixels |
215
246
  | $screenWidth | Screen Width | The most recent width of the device screen in pixels |
216
- | $screenDpi | Screen DPI | The most recent Pixel density of the device screen. |
247
+ | $screenDpi | Screen DPI | The most recent pixel density of the device screen. |
217
248
  | $lastSeen | Last Seen | The last time a user was identified while active was not false in the context |
218
249
  | $os | Operating System | The most recent OS of the user. |
219
250
  | $browser | Browser | The most recent browser of the user. |
220
- | $browserVersion | Browser Version | The most recent bowser version of the user. |
251
+ | $browserVersion | Browser Version | The most recent browser version of the user. |
221
252
  | $initialReferrer | Initial Referrer | Referring URL when the user first arrived on your site. Defaults to "direct" |
222
253
  | $referrer | Last Touch Referrer | Referring URL when the user last interacted with your site. Defaults to "direct" |
223
254
  | $initialReferringDomain | Initial Referring Domain | Referring domain at first arrival. Defaults to "direct" |
@@ -249,11 +280,11 @@ Properties used to calculate revenue for different traffic sources and LTV for u
249
280
  | -------- | ------ | ----------------------------------------------------------------------------------------- |
250
281
  | revenue | Number | Amount of revenue an event resulted in. This should be a decimal value |
251
282
  | currency | String | Currency of the revenue an event resulted in. This should be sent in the ISO 4127 format. |
252
- | value | Number | An abstract numerical value used internally to score eventsm such as lead scoring. |
283
+ | value | Number | An abstract numerical value used internally to score events, such as lead scoring. |
253
284
 
254
285
  ### Default Event Properties
255
286
 
256
- Our SDKs automatically collect certain properties on every event or user profile. The default properties begin with a `$` and can be overwritten with your own identify calls, so we recomend avoiding leading `$` in your identify call properties to avoid conflicts.
287
+ Our SDKs automatically collect certain properties on every event or user profile. The default properties begin with a `$` and can be overwritten with your own identify calls, so we recommend avoiding leading `$` in your identify call properties to avoid conflicts.
257
288
 
258
289
  | Property | Display Name | Description |
259
290
  | ---------------- | --------------------------- | -------------------------------------------------------------------------------- |
@@ -320,16 +351,19 @@ saasco.track('Signed Up', {
320
351
  Event triggered when a user signs in.
321
352
  | Property | Description |
322
353
  |----------|--------------------------------------------------|
323
- | `method` | The method used for signing in (e.g., email, social media). |
354
+ | `provider` | The provider used for signing in (e.g., email, github, google). |
324
355
 
325
356
  Example:
326
357
 
327
358
  ```jsx
328
359
  saasco.track('Signed In', {
329
- method: 'email',
360
+ provider: 'email',
330
361
  });
331
362
  ```
332
363
 
364
+ Note:
365
+ When tracking Signed In events call identify('user_id', {email: '...'}) before the event to connect to the user.
366
+
333
367
  #### Signed Out
334
368
 
335
369
  Event triggered when a user signs out.
@@ -341,13 +375,16 @@ Example:
341
375
  saasco.track('Signed Out');
342
376
  ```
343
377
 
378
+ Note:
379
+ When tracking Signed Out events call identify(null) _after_ tracking the event to reset the session.
380
+
344
381
  #### Trial Started
345
382
 
346
383
  Event triggered when a user starts a trial.
347
384
  | Property | Description |
348
385
  |-------------------|---------------------------------------------------------------------|
349
386
  | `duration` | The duration of the trial in days |
350
- | `type`| Values can be `optIn` for then the user didn't provide a cc or `optOut` when the user provided a cc and it will automatically start and the end of the trial period|
387
+ | `type`| Values can be `optIn` for when the user didn't provide a cc or `optOut` when the user provided a cc and it will automatically start at the end of the trial period|
351
388
 
352
389
  Example:
353
390
 
@@ -357,10 +394,10 @@ saasco.track('Trial Started', { duration: 14, type: 'optOut' });
357
394
 
358
395
  #### Trial Ended
359
396
 
360
- Event triggered when a users trial ends.
397
+ Event triggered when a user's trial ends.
361
398
  | Property | Description |
362
399
  |-------------------|---------------------------------------------------------------------|
363
- | `daysLeftInTrial`| If a user manual upgrades before the end of the trial you can record this here|
400
+ | `daysLeftInTrial`| If a user manually upgrades before the end of the trial you can record this here|
364
401
 
365
402
  Example:
366
403
 
@@ -368,10 +405,10 @@ Example:
368
405
  saasco.track('Trial Ended', { daysLeftInTrial: 4 });
369
406
  ```
370
407
 
371
- #### Payment Ended
408
+ #### Payment Completed
372
409
 
373
410
  Event triggered when a payment is completed.
374
- This is may be called on the server side after a confirmation webhook.
411
+ This may be called on the server side after a confirmation webhook.
375
412
  This is helpful for recording ongoing subscription payments.
376
413
 
377
414
  | Property | Description |
@@ -435,7 +472,7 @@ Event triggered when a subscription is upgraded.
435
472
  Example:
436
473
 
437
474
  ```jsx
438
- saasco.track('Subscription Cancelled', {
475
+ saasco.track('Subscription Upgraded', {
439
476
  fromPlan: 'Monthly',
440
477
  toPlan: 'Annual',
441
478
  previousRevenue: 29,
@@ -452,13 +489,13 @@ Event triggered when a subscription is downgraded.
452
489
  | `toPlan` | The new plan. |
453
490
  | `previousRevenue` | The revenue from the previous plan. |
454
491
  | `newRevenue` | The revenue from the new plan. |
455
- | `revenue` | If the customer is refunded immediately then include a revenue number here, in the case of a downgrade this will be a negtive value. Only include the revenue here if it's not tracked on your backend or with a webhook |
492
+ | `revenue` | If the customer is refunded immediately then include a revenue number here, in the case of a downgrade this will be a negative value. Only include the revenue here if it's not tracked on your backend or with a webhook |
456
493
  | `currency` | The currency of the payment, assumed to be USD unless otherwise specified. |
457
494
 
458
495
  Example:
459
496
 
460
497
  ```jsx
461
- saasco.track('Subscription Cancelled', {
498
+ saasco.track('Subscription Downgraded', {
462
499
  fromPlan: 'Annual',
463
500
  toPlan: 'Monthly',
464
501
  previousRevenue: 129,
@@ -480,7 +517,7 @@ All properties should be added as data attributes in the format data-[prop name]
480
517
  ></script>
481
518
  ```
482
519
 
483
- All the properties for initiating the sdk can be passed in like this:
520
+ All the properties for initializing the sdk can be passed in like this:
484
521
 
485
522
  ```jsx
486
523
  <script
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.22";
9
+ var version = "0.1.24";
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) {
@@ -525,7 +526,7 @@ function setSessionId({
525
526
  function getAnonymousId() {
526
527
  return retrieveData(`anonymous-id`);
527
528
  }
528
- function setAnonmousId({
529
+ function setAnonymousId({
529
530
  reset
530
531
  } = {
531
532
  reset: false
@@ -581,7 +582,7 @@ class Saasco {
581
582
  this.log('Saasco initialized', this.config);
582
583
  if (this.config.debug) this.log('Debug mode active. This will log all events to the console.');
583
584
  if (!this.config.enabled) this.log('Analytics is disabled. No requests will be sent to the server.');
584
- this.initiAutoPageTracking();
585
+ this.initAutoPageTracking();
585
586
  this.isInitialized = true;
586
587
  }
587
588
  disableDebug() {
@@ -592,35 +593,43 @@ 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
- setAnonmousId();
613
- const browserContext = getBrowserContext();
602
+ setAnonymousId();
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
  })),
626
635
  source: isBrowser ? 'client' : 'server',
@@ -636,7 +645,7 @@ class Saasco {
636
645
  */
637
646
  page() {
638
647
  var _a, _b;
639
- if (!isBrowser) {
648
+ if (isServer) {
640
649
  console.warn('Saasco page tracking is only available in the browser');
641
650
  return;
642
651
  }
@@ -673,7 +682,7 @@ class Saasco {
673
682
  setSessionId({
674
683
  reset
675
684
  });
676
- const anonymousId = setAnonmousId({
685
+ const anonymousId = setAnonymousId({
677
686
  reset
678
687
  });
679
688
  // set the distinct Id to the userId
@@ -778,12 +787,12 @@ class Saasco {
778
787
  * It listens to url changes to track new pages every time the url changes
779
788
  * @returns
780
789
  */
781
- initiAutoPageTracking() {
790
+ initAutoPageTracking() {
782
791
  var _a, _b;
783
792
  // Disable auto page tracking if the config is set to false
784
793
  if (!((_a = this.config.autoPageTracking) === null || _a === void 0 ? void 0 : _a.enabled)) return;
785
794
  // Prevent running on the server
786
- 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');
787
796
  // Prevent intitializing auto page tracking more than once
788
797
  if (window.saascoAutoPageTrackingActive) {
789
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.22";
5
+ var version = "0.1.24";
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) {
@@ -521,7 +522,7 @@ function setSessionId({
521
522
  function getAnonymousId() {
522
523
  return retrieveData(`anonymous-id`);
523
524
  }
524
- function setAnonmousId({
525
+ function setAnonymousId({
525
526
  reset
526
527
  } = {
527
528
  reset: false
@@ -577,7 +578,7 @@ class Saasco {
577
578
  this.log('Saasco initialized', this.config);
578
579
  if (this.config.debug) this.log('Debug mode active. This will log all events to the console.');
579
580
  if (!this.config.enabled) this.log('Analytics is disabled. No requests will be sent to the server.');
580
- this.initiAutoPageTracking();
581
+ this.initAutoPageTracking();
581
582
  this.isInitialized = true;
582
583
  }
583
584
  disableDebug() {
@@ -588,35 +589,43 @@ 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
- setAnonmousId();
609
- const browserContext = getBrowserContext();
598
+ setAnonymousId();
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
  })),
622
631
  source: isBrowser ? 'client' : 'server',
@@ -632,7 +641,7 @@ class Saasco {
632
641
  */
633
642
  page() {
634
643
  var _a, _b;
635
- if (!isBrowser) {
644
+ if (isServer) {
636
645
  console.warn('Saasco page tracking is only available in the browser');
637
646
  return;
638
647
  }
@@ -669,7 +678,7 @@ class Saasco {
669
678
  setSessionId({
670
679
  reset
671
680
  });
672
- const anonymousId = setAnonmousId({
681
+ const anonymousId = setAnonymousId({
673
682
  reset
674
683
  });
675
684
  // set the distinct Id to the userId
@@ -774,12 +783,12 @@ class Saasco {
774
783
  * It listens to url changes to track new pages every time the url changes
775
784
  * @returns
776
785
  */
777
- initiAutoPageTracking() {
786
+ initAutoPageTracking() {
778
787
  var _a, _b;
779
788
  // Disable auto page tracking if the config is set to false
780
789
  if (!((_a = this.config.autoPageTracking) === null || _a === void 0 ? void 0 : _a.enabled)) return;
781
790
  // Prevent running on the server
782
- 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');
783
792
  // Prevent intitializing auto page tracking more than once
784
793
  if (window.saascoAutoPageTrackingActive) {
785
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.22",
3
+ "version": "0.1.24",
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"
@@ -99,6 +109,6 @@ export declare class Saasco {
99
109
  * It listens to url changes to track new pages every time the url changes
100
110
  * @returns
101
111
  */
102
- private initiAutoPageTracking;
112
+ private initAutoPageTracking;
103
113
  }
104
114
  export {};