@altertable/altertable-js 0.5.0 → 0.5.2

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 ADDED
@@ -0,0 +1,306 @@
1
+ # @altertable/altertable-js
2
+
3
+ JavaScript SDK for capturing and sending analytics events to Altertable.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @altertable/altertable-js
9
+ # or
10
+ pnpm add @altertable/altertable-js
11
+ # or
12
+ yarn add @altertable/altertable-js
13
+ # or
14
+ bun add @altertable/altertable-js
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```javascript
20
+ import { altertable } from '@altertable/altertable-js';
21
+
22
+ // Initialize with your API key
23
+ altertable.init('YOUR_API_KEY');
24
+
25
+ // Track an event
26
+ altertable.track('Step Completed', {
27
+ step: 1,
28
+ });
29
+
30
+ // Identify a user
31
+ altertable.identify('u_01jza857w4f23s1hf2s61befmw', {
32
+ email: 'john.doe@example.com',
33
+ name: 'John Doe',
34
+ company: 'Acme Corp',
35
+ role: 'Software Engineer',
36
+ });
37
+
38
+ // Update user traits
39
+ altertable.updateTraits({
40
+ onboarding_completed: true,
41
+ });
42
+ ```
43
+
44
+ ## Features
45
+
46
+ - **Automatic page view tracking** – Captures page views automatically
47
+ - **Session management** – Handles visitor and session IDs automatically
48
+ - **Event queuing** – Queues events when offline or consent is pending
49
+ - **Privacy compliance** – Built-in tracking consent management
50
+ - **Multiple storage options** – localStorage, cookies, or both
51
+ - **TypeScript support** – Full TypeScript definitions included
52
+ - **Lightweight** – Minimal bundle size with no external dependencies
53
+
54
+ ## API Reference
55
+
56
+ ### Initialization
57
+
58
+ #### `altertable.init(apiKey, config?)`
59
+
60
+ Initializes the Altertable SDK with your API key and optional configuration.
61
+
62
+ **Parameters:**
63
+
64
+ | Parameter | Type | Required | Description |
65
+ | --------- | --------------------------------------- | -------- | ----------------------- |
66
+ | `apiKey` | `string` | Yes | Your Altertable API key |
67
+ | `config` | [`AltertableConfig`](#altertableconfig) | No | Configuration options |
68
+
69
+ **Example:**
70
+
71
+ ```javascript
72
+ altertable.init('YOUR_API_KEY', {
73
+ environment: 'development',
74
+ });
75
+ ```
76
+
77
+ ### Event Tracking
78
+
79
+ #### `altertable.track(event, properties?)`
80
+
81
+ Tracks a custom event with optional properties.
82
+
83
+ **Parameters:**
84
+
85
+ | Parameter | Type | Required | Default | Description |
86
+ | ------------ | ------------------------------------- | -------- | ------- | ----------------------- |
87
+ | `event` | `string` | Yes | - | The event name |
88
+ | `properties` | [`EventProperties`](#eventproperties) | No | `{}` | Custom event properties |
89
+
90
+ **Example:**
91
+
92
+ ```javascript
93
+ altertable.track('Purchase Completed', {
94
+ product_id: 'p_01jza8fr5efvgbxxdd1bwkd0m5',
95
+ amount: 29.99,
96
+ currency: 'USD',
97
+ });
98
+ ```
99
+
100
+ #### `altertable.page(url)`
101
+
102
+ Tracks a page view event.
103
+
104
+ When [`autoCapture`](#autocapture) is enabled, this method is automatically called when the page URL changes.
105
+
106
+ **Parameters:**
107
+
108
+ | Parameter | Type | Required | Description |
109
+ | --------- | -------- | -------- | ------------ |
110
+ | `url` | `string` | Yes | The page URL |
111
+
112
+ **Example:**
113
+
114
+ ```javascript
115
+ altertable.page('https://example.com/products');
116
+ ```
117
+
118
+ ### User Identification
119
+
120
+ #### `altertable.identify(userId, traits?)`
121
+
122
+ Identifies a user with their ID and optional traits.
123
+
124
+ **Parameters:**
125
+
126
+ | Parameter | Type | Required | Default | Description |
127
+ | --------- | --------------------------- | -------- | ------- | ---------------------------- |
128
+ | `userId` | `string` | Yes | - | The user's unique identifier |
129
+ | `traits` | [`UserTraits`](#usertraits) | No | `{}` | User properties |
130
+
131
+ **Example:**
132
+
133
+ ```javascript
134
+ altertable.identify('u_01jza857w4f23s1hf2s61befmw', {
135
+ email: 'john.doe@example.com',
136
+ name: 'John Doe',
137
+ company: 'Acme Corp',
138
+ role: 'Software Engineer',
139
+ });
140
+ ```
141
+
142
+ #### `altertable.updateTraits(traits)`
143
+
144
+ Updates user traits for the current user.
145
+
146
+ **Parameters:**
147
+
148
+ | Parameter | Type | Required | Description |
149
+ | --------- | --------------------------- | -------- | ------------------------- |
150
+ | `traits` | [`UserTraits`](#usertraits) | Yes | User properties to update |
151
+
152
+ **Example:**
153
+
154
+ ```javascript
155
+ altertable.updateTraits({
156
+ onboarding_completed: true,
157
+ });
158
+ ```
159
+
160
+ ### Session Management
161
+
162
+ #### `altertable.reset(options?)`
163
+
164
+ Resets visitor and session IDs.
165
+
166
+ **Parameters:**
167
+
168
+ | Parameter | Type | Required | Default | Description |
169
+ | ------------------------ | --------- | -------- | ------- | --------------------------- |
170
+ | `options` | `object` | No | `{}` | Reset options |
171
+ | `options.resetVisitorId` | `boolean` | No | `false` | Whether to reset visitor ID |
172
+ | `options.resetSessionId` | `boolean` | No | `true` | Whether to reset session ID |
173
+
174
+ **Example:**
175
+
176
+ ```javascript
177
+ // Reset session only (default)
178
+ altertable.reset();
179
+
180
+ // Reset both visitor and session
181
+ altertable.reset({
182
+ resetVisitorId: true,
183
+ resetSessionId: true,
184
+ });
185
+ ```
186
+
187
+ ### Configuration
188
+
189
+ #### `altertable.configure(updates)`
190
+
191
+ Updates the configuration after initialization.
192
+
193
+ **Parameters:**
194
+
195
+ | Parameter | Type | Required | Description |
196
+ | --------- | ------------------------------------------------ | -------- | --------------------- |
197
+ | `updates` | [`Partial<AltertableConfig>`](#altertableconfig) | Yes | Configuration updates |
198
+
199
+ **Example:**
200
+
201
+ ```javascript
202
+ altertable.configure({
203
+ trackingConsent: 'granted',
204
+ });
205
+ ```
206
+
207
+ ### Privacy & Consent
208
+
209
+ #### `altertable.getTrackingConsent()`
210
+
211
+ Returns the current tracking consent state.
212
+
213
+ **Returns:** [`TrackingConsentType`](#trackingconsenttype)
214
+
215
+ **Example:**
216
+
217
+ ```javascript
218
+ const consent = altertable.getTrackingConsent();
219
+ if (consent === 'granted') {
220
+ // Tracking is allowed
221
+ }
222
+ ```
223
+
224
+ ## Types
225
+
226
+ ### `AltertableConfig`
227
+
228
+ Configuration options for the Altertable SDK.
229
+
230
+ | Property | Type | Default | Description |
231
+ | ----------------- | --------------------------------------------- | ----------------------------- | ------------------------------------------------------ |
232
+ | `baseUrl` | `string` | `"https://api.altertable.ai"` | The base URL of the Altertable API |
233
+ | `environment` | `string` | `"production"` | The environment of the application |
234
+ | `autoCapture` | `boolean` | `true` | Whether to automatically capture page views and events |
235
+ | `release` | `string` | - | The release ID of the application |
236
+ | `debug` | `boolean` | `false` | Whether to log events to the console |
237
+ | `persistence` | [`StorageType`](#storagetype) | `"localStorage+cookie"` | The persistence strategy for storing IDs |
238
+ | `trackingConsent` | [`TrackingConsentType`](#trackingconsenttype) | `"pending"` | The tracking consent state |
239
+
240
+ ### `EventProperties`
241
+
242
+ Custom properties for events.
243
+
244
+ ```typescript
245
+ type EventProperties = Record<string, unknown>;
246
+ ```
247
+
248
+ **Example:**
249
+
250
+ ```javascript
251
+ {
252
+ product_id: 'p_01jza8fr5efvgbxxdd1bwkd0m5',
253
+ amount: 29.99,
254
+ currency: 'USD',
255
+ category: 'electronics',
256
+ user_type: 'premium'
257
+ }
258
+ ```
259
+
260
+ ### `UserTraits`
261
+
262
+ User properties for identification.
263
+
264
+ ```typescript
265
+ type UserTraits = Record<string, unknown>;
266
+ ```
267
+
268
+ **Example:**
269
+
270
+ ```javascript
271
+ {
272
+ email: 'john.doe@example.com',
273
+ name: 'John Doe',
274
+ company: 'Acme Corp',
275
+ role: 'Software Engineer',
276
+ plan: 'premium',
277
+ signup_date: '2024-01-15'
278
+ }
279
+ ```
280
+
281
+ ### `StorageType`
282
+
283
+ Available storage strategies.
284
+
285
+ | Value | Description |
286
+ | ----------------------- | ------------------------------------- |
287
+ | `"localStorage"` | Use localStorage only |
288
+ | `"sessionStorage"` | Use sessionStorage only |
289
+ | `"cookie"` | Use cookies only |
290
+ | `"memory"` | Use in-memory storage (not persisted) |
291
+ | `"localStorage+cookie"` | Use localStorage with cookie fallback |
292
+
293
+ ### `TrackingConsentType`
294
+
295
+ Available tracking consent states.
296
+
297
+ | Value | Description |
298
+ | ------------- | ------------------------------------- |
299
+ | `"granted"` | User has granted consent for tracking |
300
+ | `"denied"` | User has denied consent for tracking |
301
+ | `"pending"` | User hasn't made a decision yet |
302
+ | `"dismissed"` | User dismissed the consent prompt |
303
+
304
+ ## License
305
+
306
+ [MIT](./LICENSE)
package/dist/index.d.mts CHANGED
@@ -61,6 +61,7 @@ declare class Altertable {
61
61
  private _referrer;
62
62
  private _sessionManager;
63
63
  private _storage;
64
+ private _storageKey;
64
65
  constructor();
65
66
  init(apiKey: string, config?: AltertableConfig): () => void;
66
67
  configure(updates: Partial<AltertableConfig>): void;
package/dist/index.d.ts CHANGED
@@ -61,6 +61,7 @@ declare class Altertable {
61
61
  private _referrer;
62
62
  private _sessionManager;
63
63
  private _storage;
64
+ private _storageKey;
64
65
  constructor();
65
66
  init(apiKey: string, config?: AltertableConfig): () => void;
66
67
  configure(updates: Partial<AltertableConfig>): void;
@@ -1,9 +1,9 @@
1
- /*! @altertable/altertable-js 0.5.0 | MIT License | Altertable | https://github.com/altertable-ai/altertable-js */
2
- var Altertable=(()=>{var v=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var he=(n,e)=>{for(var t in e)v(n,t,{get:e[t],enumerable:!0})},Ee=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of _e(e))!fe.call(n,r)&&r!==t&&v(n,r,{get:()=>e[r],enumerable:!(s=pe(e,r))||s.enumerable});return n};var me=n=>Ee(v({},"__esModule",{value:!0}),n);var De={};he(De,{TrackingConsent:()=>i,altertable:()=>D});function w(n,e){return(...t)=>[n,...t].join(e)}var x="https://api.altertable.ai",P="production",U="localStorage+cookie",N="atbl",Se=w(N,"."),g=Se("check"),p=N,L="session",$="visitor",Ie=1e3*60,O=100,V=30*Ie,M=1e3,B="$pageview",z="$lib",F="$lib_version",G="$referer",Y="$release",q="$url",K="$viewport",i={DENIED:"denied",DISMISSED:"dismissed",GRANTED:"granted",PENDING:"pending"},T=["anonymous_id","anonymous","distinct_id","distinctid","false","guest","id","not_authenticated","true","undefined","user_id","user","visitor_id","visitor"],y=new Set(["[object Object]","0","NaN","none","None","null"]);var h=class{_queue=[];_queueMaxSize;constructor(e){this._queueMaxSize=e}enqueue(e,t,s){this._queue.length>=this._queueMaxSize&&this._queue.shift(),this._queue.push({eventType:e,payload:t,context:s,sentAt:new Date})}flush(){let e=[...this._queue];return this._queue=[],e}clear(){this._queue=[]}getSize(){return this._queue.length}};function o(n,e=()=>{}){return typeof window>"u"?e():n({window})}function Q(){return o(({window:n})=>`${n.innerWidth}x${n.innerHeight}`,()=>null)}function l(n,e){if(!n)throw new Error("Invariant failed")}function X(n){return{log:(...e)=>{console.log(`[${n}]`,...e)},logHeader:()=>{let e="Altertable v0.5.0 %c\u2022 Debug mode enabled";E.current[e]||(E.current[e]=!0,console.log(e,"color: #64748b;"))},logEvent:(e,{trackingConsent:t})=>{let[s,r]=Te(e.event),[a,c]=ye(e.environment),[H,J]=be(e.timestamp),[Z,ee]=Ce(t);console.groupCollapsed(`[${n}] %c${s}%c [${a}] %c(${H}) %c${Z}`,r,c,J,ee);let[te,ne]=k("User ID"),[se,re]=b(e.user_id??"Not set"),[ie,oe]=k("Visitor ID"),[ae,le]=b(e.visitor_id??"Not set"),[ce,ge]=k("Session ID"),[ue,de]=b(e.session_id??"Not set");console.log(`%c${te} %c${se}`,ne,re),console.log(`%c${ie} %c${ae}`,oe,le),console.log(`%c${ce} %c${ue}`,ge,de),console.table(e.properties),console.groupEnd()},warn:(...e)=>{console.warn(`[${n}]`,...e)},warnDev:(e,...t)=>{return;if(!r){E.current[s]=!0;let a=`[${n}] ${s}`;console.warn(a,...t);try{throw new Error(a)}catch{}}},error:(...e)=>{console.error(`[${n}]`,...e)}}}var E={current:{}};function ve(n){return new Date(n).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}function Te(n){return[n,"background: #1e293b; color: #f1f5f9; padding: 2px 8px; border-radius: 6px; font-weight: 400;"]}function ye(n){return[n,`color: ${ke(n)}; font-weight: 400;`]}function ke(n){switch(n.toLocaleLowerCase().startsWith("prod")?"production":n){case"production":return"#ef4444";default:return"#3b82f6"}}function be(n){return[ve(n),"color: #64748b; font-weight: 400;"]}function k(n){return[n,"color: #64748b; font-size: 11px;"]}function b(n){return[n,'background: #f8fafc; color: #1e293b; padding: 2px 8px; border: 1px solid #e2e8f0; border-radius: 6px; font-family: "SF Mono", "Monaco", monospace; font-size: 11px;']}function Ce(n){switch(n){case i.GRANTED:return["",""];case i.DENIED:return["DENIED","background: #ef4444; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"];case i.PENDING:case i.DISMISSED:return["PENDING","background: #f59e0b; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"];default:return["UNKNOWN","background: #6b7280; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"]}}function C(n){if(typeof globalThis.crypto<"u"&&typeof globalThis.crypto.randomUUID=="function")try{return`${n}-${crypto.randomUUID()}`}catch{}return`${n}-${Math.random().toString(36).substring(2)}`}var m=class{_logger;_storage;_sessionData;_defaultTrackingConsent;constructor(e){this._storage=e.storage,this._logger=e.logger,this._defaultTrackingConsent=e.defaultTrackingConsent??i.PENDING,this._sessionData=this._createDefaultSessionData()}init(){let e=this._storage.getItem(p);if(!e){this._sessionData=this._createDefaultSessionData(),this._persistToStorage();return}try{let t=JSON.parse(e);this._sessionData={visitorId:t.visitorId||this._generateVisitorId(),sessionId:t.sessionId||this._generateSessionId(),userId:t.userId||null,lastEventAt:t.lastEventAt||null,trackingConsent:Re(t.trackingConsent)?t.trackingConsent:this._defaultTrackingConsent}}catch{this._logger.warnDev("Failed to parse storage data. Resetting session data."),this._sessionData=this._createDefaultSessionData()}this._persistToStorage()}getVisitorId(){return this._sessionData.visitorId}getSessionId(){return this._sessionData.sessionId}getUserId(){return this._sessionData.userId}getLastEventAt(){return this._sessionData.lastEventAt}getTrackingConsent(){return this._sessionData.trackingConsent}setUserId(e){this._sessionData.userId=e,this._persistToStorage()}setTrackingConsent(e){this._sessionData.trackingConsent=e,this._persistToStorage()}updateLastEventAt(e){this._sessionData.lastEventAt=e,this._persistToStorage()}renewSessionIfNeeded(){return this._shouldRenewSession()?(this._renewSession(),this._persistToStorage(),!0):!1}reset({resetVisitorId:e=!1,resetSessionId:t=!0,resetTrackingConsent:s=!1}={}){e&&(this._sessionData.visitorId=this._generateVisitorId()),t&&(this._sessionData.sessionId=this._generateSessionId()),s&&(this._sessionData.trackingConsent=this._defaultTrackingConsent),this._sessionData.userId=null,this._sessionData.lastEventAt=null,this._persistToStorage()}_createDefaultSessionData(){return{visitorId:this._generateVisitorId(),sessionId:this._generateSessionId(),userId:null,lastEventAt:null,trackingConsent:this._defaultTrackingConsent}}_generateSessionId(){return C(L)}_generateVisitorId(){return C($)}_shouldRenewSession(){let{lastEventAt:e}=this._sessionData;if(!e)return!0;let t=new Date().getTime(),s=new Date(e).getTime();return t-s>V}_renewSession(){this._sessionData.sessionId=this._generateSessionId(),this._sessionData.lastEventAt=null}_persistToStorage(){try{this._storage.setItem(p,JSON.stringify(this._sessionData))}catch{this._logger.warnDev("Failed to persist session data to storage.")}}};function Re(n){return typeof n=="string"&&Object.values(i).includes(n)}function A(n,e,t){for(let s of t){let r=e.getItem(s);r!==null&&(n.setItem(s,r),e.removeItem(s))}}var u=class{store={};getItem(e){return this.store[e]??null}setItem(e,t){this.store[e]=t}removeItem(e){delete this.store[e]}migrate(e,t){A(this,e,t)}},f=class{getItem(e){return o(({window:t})=>{let s=t.document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"));return s?decodeURIComponent(s[2]):null},()=>null)}setItem(e,t){o(({window:s})=>{s.document.cookie=`${e}=${encodeURIComponent(t)}; path=/;`})}removeItem(e){o(({window:t})=>{t.document.cookie=`${e}=; Max-Age=0; path=/;`})}migrate(e,t){A(this,e,t)}},d=class{constructor(e){this.storage=e}getItem(e){return o(({window:t})=>{try{return t[this.storage].getItem(e)}catch{return null}},()=>null)}setItem(e,t){o(({window:s})=>{try{s[this.storage].setItem(e,t)}catch{}})}removeItem(e){o(({window:t})=>{try{t[this.storage].removeItem(e)}catch{}})}migrate(e,t){A(this,e,t)}},R=class{localStore=new d("localStorage");cookieStore=new f;getItem(e){return this.localStore.getItem(e)??this.cookieStore.getItem(e)}setItem(e,t){this.localStore.setItem(e,t),this.cookieStore.setItem(e,t)}removeItem(e){this.localStore.removeItem(e),this.cookieStore.removeItem(e)}migrate(e,t){for(let s of t){let r=e.getItem(s);r!==null&&(this.localStore.setItem(s,r),this.cookieStore.setItem(s,r))}for(let s of t)e.removeItem(s)}};function _(n){return o(({window:e})=>{try{if(n==="cookie"){e.document.cookie=`${g}=1`;let t=e.document.cookie.indexOf(`${g}=`)!==-1;return e.document.cookie=`${g}=; Max-Age=0`,t}else return e[n].setItem(g,"1"),e[n].removeItem(g),!0}catch{return!1}},()=>!1)}function S(n,e){let{onFallback:t}=e;switch(n){case"localStorage":return _("localStorage")?new d("localStorage"):(t("localStorage not supported, falling back to localStorage+cookie."),S("localStorage+cookie",e));case"localStorage+cookie":{let s=_("localStorage"),r=_("cookie");return s&&r?new R:r?(t("localStorage+cookie not fully supported, falling back to cookie."),new f):s?(t("cookie not supported, falling back to localStorage."),new d("localStorage")):(t("Neither localStorage nor cookie supported, falling back to memory."),new u)}case"sessionStorage":return _("sessionStorage")?new d("sessionStorage"):(t("sessionStorage not supported, falling back to memory."),new u);case"cookie":return _("cookie")?new f:(t("cookie not supported, falling back to memory."),new u);case"memory":return new u;default:throw new Error(`Unknown storage type: "${n}". Valid types are: localStorage, sessionStorage, cookie, memory, localStorage+cookie.`)}}var Ae=[...T,...y].map(n=>`- "${n}"`).join(`
3
- `),j=`List of reserved identifiers:
4
- ${Ae}`;function W(n){if(!n||n.trim()==="")throw new Error("User ID cannot be empty or contain only whitespace.");if(T.some(s=>n.toLowerCase()===s.toLowerCase()))throw new Error(`User ID "${n}" is a reserved identifier and cannot be used.
1
+ /*! @altertable/altertable-js 0.5.2 | MIT License | Altertable | https://github.com/altertable-ai/altertable-js */
2
+ var Altertable=(()=>{var I=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var _e=Object.prototype.hasOwnProperty;var he=(n,e)=>{for(var t in e)I(n,t,{get:e[t],enumerable:!0})},fe=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of pe(e))!_e.call(n,r)&&r!==t&&I(n,r,{get:()=>e[r],enumerable:!(s=de(e,r))||s.enumerable});return n};var Ee=n=>fe(I({},"__esModule",{value:!0}),n);var Ae={};he(Ae,{TrackingConsent:()=>i,altertable:()=>w});function x(n,e){return(...t)=>[n,...t].join(e)}var P="https://api.altertable.ai",S="production",U="localStorage+cookie",me="atbl",T=x(me,"."),c=T("check"),N="session",L="visitor",ve=1e3*60,$=100,V=30*ve,O=1e3,M="$pageview",B="$lib",z="$lib_version",F="$referer",K="$release",q="$url",G="$viewport",i={DENIED:"denied",DISMISSED:"dismissed",GRANTED:"granted",PENDING:"pending"},y=["anonymous_id","anonymous","distinct_id","distinctid","false","guest","id","not_authenticated","true","undefined","user_id","user","visitor_id","visitor"],k=new Set(["[object Object]","0","NaN","none","None","null"]);var h=class{_queue=[];_queueMaxSize;constructor(e){this._queueMaxSize=e}enqueue(e,t,s){this._queue.length>=this._queueMaxSize&&this._queue.shift(),this._queue.push({eventType:e,payload:t,context:s,sentAt:new Date})}flush(){let e=[...this._queue];return this._queue=[],e}clear(){this._queue=[]}getSize(){return this._queue.length}};function o(n,e=()=>{}){return typeof window>"u"?e():n({window})}function Y(){return o(({window:n})=>`${n.innerWidth}x${n.innerHeight}`,()=>null)}function a(n,e){if(!n)throw new Error("Invariant failed")}function Q(n){return{log:(...e)=>{console.log(`[${n}]`,...e)},logHeader:()=>{let e="Altertable v0.5.2 %c\u2022 Debug mode enabled";f.current[e]||(f.current[e]=!0,console.log(e,"color: #64748b;"))},logEvent:(e,{trackingConsent:t})=>{let[s,r]=Se(e.event),[g,l]=Te(e.environment),[W,H]=ke(e.timestamp),[J,Z]=be(t);console.groupCollapsed(`[${n}] %c${s}%c [${g}] %c(${W}) %c${J}`,r,l,H,Z);let[ee,te]=b("User ID"),[ne,se]=C(e.user_id??"Not set"),[re,ie]=b("Visitor ID"),[oe,ae]=C(e.visitor_id??"Not set"),[ge,le]=b("Session ID"),[ce,ue]=C(e.session_id??"Not set");console.log(`%c${ee} %c${ne}`,te,se),console.log(`%c${re} %c${oe}`,ie,ae),console.log(`%c${ge} %c${ce}`,le,ue),console.table(e.properties),console.groupEnd()},warn:(...e)=>{console.warn(`[${n}]`,...e)},warnDev:(e,...t)=>{return;if(!r){f.current[s]=!0;let g=`[${n}] ${s}`;console.warn(g,...t);try{throw new Error(g)}catch{}}},error:(...e)=>{console.error(`[${n}]`,...e)}}}var f={current:{}};function Ie(n){return new Date(n).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}function Se(n){return[n,"background: #1e293b; color: #f1f5f9; padding: 2px 8px; border-radius: 6px; font-weight: 400;"]}function Te(n){return[n,`color: ${ye(n)}; font-weight: 400;`]}function ye(n){switch(n.toLocaleLowerCase().startsWith("prod")?"production":n){case"production":return"#ef4444";default:return"#3b82f6"}}function ke(n){return[Ie(n),"color: #64748b; font-weight: 400;"]}function b(n){return[n,"color: #64748b; font-size: 11px;"]}function C(n){return[n,'background: #f8fafc; color: #1e293b; padding: 2px 8px; border: 1px solid #e2e8f0; border-radius: 6px; font-family: "SF Mono", "Monaco", monospace; font-size: 11px;']}function be(n){switch(n){case i.GRANTED:return["",""];case i.DENIED:return["DENIED","background: #ef4444; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"];case i.PENDING:case i.DISMISSED:return["PENDING","background: #f59e0b; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"];default:return["UNKNOWN","background: #6b7280; color: #ffffff; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 600;"]}}function R(n){if(typeof globalThis.crypto<"u"&&typeof globalThis.crypto.randomUUID=="function")try{return`${n}-${crypto.randomUUID()}`}catch{}return`${n}-${Math.random().toString(36).substring(2)}`}var E=class{_defaultTrackingConsent;_logger;_sessionData;_storage;_storageKey;constructor(e){this._storage=e.storage,this._storageKey=e.storageKey,this._logger=e.logger,this._defaultTrackingConsent=e.defaultTrackingConsent??i.PENDING,this._sessionData=this._createDefaultSessionData()}init(){let e=this._storage.getItem(this._storageKey);if(!e){this._sessionData=this._createDefaultSessionData(),this._persistToStorage();return}try{let t=JSON.parse(e);this._sessionData={visitorId:t.visitorId||this._generateVisitorId(),sessionId:t.sessionId||this._generateSessionId(),userId:t.userId||null,lastEventAt:t.lastEventAt||null,trackingConsent:Ce(t.trackingConsent)?t.trackingConsent:this._defaultTrackingConsent}}catch{this._logger.warnDev("Failed to parse storage data. Resetting session data."),this._sessionData=this._createDefaultSessionData()}this._persistToStorage()}getVisitorId(){return this._sessionData.visitorId}getSessionId(){return this._sessionData.sessionId}getUserId(){return this._sessionData.userId}getLastEventAt(){return this._sessionData.lastEventAt}getTrackingConsent(){return this._sessionData.trackingConsent}setUserId(e){this._sessionData.userId=e,this._persistToStorage()}setTrackingConsent(e){this._sessionData.trackingConsent=e,this._persistToStorage()}updateLastEventAt(e){this._sessionData.lastEventAt=e,this._persistToStorage()}renewSessionIfNeeded(){return this._shouldRenewSession()?(this._renewSession(),this._persistToStorage(),!0):!1}reset({resetVisitorId:e=!1,resetSessionId:t=!0,resetTrackingConsent:s=!1}={}){e&&(this._sessionData.visitorId=this._generateVisitorId()),t&&(this._sessionData.sessionId=this._generateSessionId()),s&&(this._sessionData.trackingConsent=this._defaultTrackingConsent),this._sessionData.userId=null,this._sessionData.lastEventAt=null,this._persistToStorage()}_createDefaultSessionData(){return{visitorId:this._generateVisitorId(),sessionId:this._generateSessionId(),userId:null,lastEventAt:null,trackingConsent:this._defaultTrackingConsent}}_generateSessionId(){return R(N)}_generateVisitorId(){return R(L)}_shouldRenewSession(){let{lastEventAt:e}=this._sessionData;if(!e)return!0;let t=new Date().getTime(),s=new Date(e).getTime();return t-s>V}_renewSession(){this._sessionData.sessionId=this._generateSessionId(),this._sessionData.lastEventAt=null}_persistToStorage(){try{this._storage.setItem(this._storageKey,JSON.stringify(this._sessionData))}catch{this._logger.warnDev("Failed to persist session data to storage.")}}};function Ce(n){return typeof n=="string"&&Object.values(i).includes(n)}function D(n,e,t){for(let s of t){let r=e.getItem(s);r!==null&&(n.setItem(s,r),e.removeItem(s))}}var u=class{store={};getItem(e){return this.store[e]??null}setItem(e,t){this.store[e]=t}removeItem(e){delete this.store[e]}migrate(e,t){D(this,e,t)}},_=class{getItem(e){return o(({window:t})=>{let s=t.document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"));return s?decodeURIComponent(s[2]):null},()=>null)}setItem(e,t){o(({window:s})=>{s.document.cookie=`${e}=${encodeURIComponent(t)}; path=/;`})}removeItem(e){o(({window:t})=>{t.document.cookie=`${e}=; Max-Age=0; path=/;`})}migrate(e,t){D(this,e,t)}},d=class{constructor(e){this.storage=e}getItem(e){return o(({window:t})=>{try{return t[this.storage].getItem(e)}catch{return null}},()=>null)}setItem(e,t){o(({window:s})=>{try{s[this.storage].setItem(e,t)}catch{}})}removeItem(e){o(({window:t})=>{try{t[this.storage].removeItem(e)}catch{}})}migrate(e,t){D(this,e,t)}},A=class{localStore=new d("localStorage");cookieStore=new _;getItem(e){return this.localStore.getItem(e)??this.cookieStore.getItem(e)}setItem(e,t){this.localStore.setItem(e,t),this.cookieStore.setItem(e,t)}removeItem(e){this.localStore.removeItem(e),this.cookieStore.removeItem(e)}migrate(e,t){for(let s of t){let r=e.getItem(s);r!==null&&(this.localStore.setItem(s,r),this.cookieStore.setItem(s,r))}for(let s of t)e.removeItem(s)}};function p(n){return o(({window:e})=>{try{if(n==="cookie"){e.document.cookie=`${c}=1`;let t=e.document.cookie.indexOf(`${c}=`)!==-1;return e.document.cookie=`${c}=; Max-Age=0`,t}else return e[n].setItem(c,"1"),e[n].removeItem(c),!0}catch{return!1}},()=>!1)}function m(n,e){let{onFallback:t}=e;switch(n){case"localStorage":return p("localStorage")?new d("localStorage"):(t("localStorage not supported, falling back to localStorage+cookie."),m("localStorage+cookie",e));case"localStorage+cookie":{let s=p("localStorage"),r=p("cookie");return s&&r?new A:r?(t("localStorage+cookie not fully supported, falling back to cookie."),new _):s?(t("cookie not supported, falling back to localStorage."),new d("localStorage")):(t("Neither localStorage nor cookie supported, falling back to memory."),new u)}case"sessionStorage":return p("sessionStorage")?new d("sessionStorage"):(t("sessionStorage not supported, falling back to memory."),new u);case"cookie":return p("cookie")?new _:(t("cookie not supported, falling back to memory."),new u);case"memory":return new u;default:throw new Error(`Unknown storage type: "${n}". Valid types are: localStorage, sessionStorage, cookie, memory, localStorage+cookie.`)}}var Re=[...y,...k].map(n=>`- "${n}"`).join(`
3
+ `),X=`List of reserved identifiers:
4
+ ${Re}`;function j(n){if(!n||n.trim()==="")throw new Error("User ID cannot be empty or contain only whitespace.");if(y.some(s=>n.toLowerCase()===s.toLowerCase()))throw new Error(`User ID "${n}" is a reserved identifier and cannot be used.
5
5
 
6
- `+j);if(y.has(n))throw new Error(`User ID "${n}" is a reserved identifier and cannot be used.
6
+ `+X);if(k.has(n))throw new Error(`User ID "${n}" is a reserved identifier and cannot be used.
7
7
 
8
- `+j)}var I=class{_apiKey;_cleanupAutoCapture;_config;_eventQueue;_isInitialized=!1;_lastUrl;_logger=X("Altertable");_referrer;_sessionManager;_storage;constructor(){this._lastUrl=null,this._referrer=null,this._eventQueue=new h(M)}init(e,t={}){this._apiKey=e,this._config=t,this._referrer=o(({window:r})=>r.document.referrer||null,()=>null),this._lastUrl=o(({window:r})=>r.location.href||null,()=>null);let s=t.persistence??U;return this._storage=S(s,{onFallback:r=>this._logger.warn(r)}),this._sessionManager=new m({storage:this._storage,logger:this._logger,defaultTrackingConsent:t.trackingConsent??i.PENDING}),this._sessionManager.init(),this._isInitialized=!0,this._config.debug&&this._logger.logHeader(),this._handleAutoCaptureChange(t.autoCapture??!0),()=>{this._cleanupAutoCapture?.()}}configure(e){if(l(this._isInitialized,"The client must be initialized with init() before configuring."),e.autoCapture!==void 0&&e.autoCapture!==this._config.autoCapture&&this._handleAutoCaptureChange(e.autoCapture),e.persistence!==void 0&&e.persistence!==this._config.persistence){let s=this._storage;this._storage=S(e.persistence,{onFallback:r=>this._logger.warn(r)}),this._storage.migrate(s,[p])}let t=this._sessionManager.getTrackingConsent();if(e.trackingConsent!==void 0&&e.trackingConsent!==t)if(this._sessionManager.setTrackingConsent(e.trackingConsent),t!==i.GRANTED&&e.trackingConsent===i.GRANTED){let s=this._eventQueue.flush();s.length>0&&s.forEach(r=>{this._processEvent(r.eventType,r.payload,r.context)})}else e.trackingConsent===i.DENIED&&this._eventQueue.clear();this._config={...this._config,...e}}_handleAutoCaptureChange(e){if(this._cleanupAutoCapture?.(),e){this._lastUrl&&this.page(this._lastUrl);let t=this._checkForChanges.bind(this),s=setInterval(t,O);o(({window:r})=>{r.addEventListener("popstate",t),r.addEventListener("hashchange",t)}),this._cleanupAutoCapture=()=>{clearInterval(s),o(({window:r})=>{r.removeEventListener("popstate",t),r.removeEventListener("hashchange",t)})}}else this._cleanupAutoCapture=void 0}identify(e,t={}){l(this._isInitialized,"The client must be initialized with init() before identifying users.");try{W(e)}catch(r){throw new Error(`[Altertable] ${r.message}`)}this._sessionManager.setUserId(e);let s=this._getEventContext();this._processEvent("identify",{environment:s.environment,traits:t,user_id:e,visitor_id:s.visitor_id},s)}updateTraits(e){let t=this._sessionManager.getUserId();l(t,"User must be identified with identify() before updating traits.");let s=this._getEventContext();this._processEvent("identify",{environment:s.environment,traits:e,user_id:t,visitor_id:s.visitor_id},s)}reset({resetVisitorId:e=!1,resetSessionId:t=!0}={}){l(this._isInitialized,"The client must be initialized with init() before resetting."),this._sessionManager.reset({resetVisitorId:e,resetSessionId:t})}page(e){l(this._isInitialized,"The client must be initialized with init() before tracking page views.");let t=new URL(e),s=`${t.origin}${t.pathname}`;this.track(B,{[q]:s,[K]:Q(),[G]:this._referrer,...Object.fromEntries(t.searchParams)})}track(e,t={}){l(this._isInitialized,"The client must be initialized with init() before tracking events."),this._sessionManager.renewSessionIfNeeded();let s=new Date().toISOString();this._sessionManager.updateLastEventAt(s);let r=this._getEventContext(),a={timestamp:s,event:e,environment:r.environment,user_id:r.user_id,session_id:r.session_id,visitor_id:r.visitor_id,properties:{[z]:"@altertable/altertable-js",[F]:"0.5.0",[Y]:this._config.release,...t}};if(this._processEvent("track",a,r),this._config.debug){let c=this._sessionManager.getTrackingConsent();this._logger.logEvent(a,{trackingConsent:c})}}getTrackingConsent(){return this._sessionManager.getTrackingConsent()}_checkForChanges(){o(({window:e})=>{if(!this._config.autoCapture)return;let t=e.location.href;t!==this._lastUrl&&(this.page(t),this._referrer=this._lastUrl,this._lastUrl=t)})}_getEventContext(){return{environment:this._config.environment||P,user_id:this._sessionManager.getUserId(),visitor_id:this._sessionManager.getVisitorId(),session_id:this._sessionManager.getSessionId()}}_processEvent(e,t,s){switch(this._sessionManager.getTrackingConsent()){case i.GRANTED:this._request(`/${e}`,t);break;case i.PENDING:case i.DISMISSED:this._eventQueue.enqueue(e,t,s);break;case i.DENIED:break}}_request(e,t){l(this._apiKey,"Missing API key"),l(this._config,"Missing configuration");let s=`${this._config.baseUrl||x}${e}`,r=JSON.stringify(t);if(typeof navigator<"u"&&navigator.sendBeacon){let a=`${s}?apiKey=${encodeURIComponent(this._apiKey)}`,c=new Blob([r],{type:"application/json"});navigator.sendBeacon(a,c)}else fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this._apiKey}`},body:r})}};var D=new I;o(({window:n})=>{let e=n.Altertable;if(e&&Array.isArray(e))for(let t of e){let s=t[0],r=t.slice(1);D[s](...r)}n.Altertable=D});return me(De);})();
8
+ `+X)}var v=class{_apiKey;_cleanupAutoCapture;_config;_eventQueue;_isInitialized=!1;_lastUrl;_logger=Q("Altertable");_referrer;_sessionManager;_storage;_storageKey;constructor(){this._lastUrl=null,this._referrer=null,this._eventQueue=new h(O)}init(e,t={}){a(e,"Missing API key"),this._apiKey=e,this._config=t,this._storageKey=T(e,this._config.environment||S),this._referrer=o(({window:r})=>r.document.referrer||null,()=>null),this._lastUrl=o(({window:r})=>r.location.href||null,()=>null);let s=t.persistence??U;return this._storage=m(s,{onFallback:r=>this._logger.warn(r)}),this._sessionManager=new E({storage:this._storage,storageKey:this._storageKey,logger:this._logger,defaultTrackingConsent:t.trackingConsent??i.PENDING}),this._sessionManager.init(),this._isInitialized=!0,this._config.debug&&this._logger.logHeader(),this._handleAutoCaptureChange(t.autoCapture??!0),()=>{this._cleanupAutoCapture?.()}}configure(e){if(a(this._isInitialized,"The client must be initialized with init() before configuring."),e.autoCapture!==void 0&&e.autoCapture!==this._config.autoCapture&&this._handleAutoCaptureChange(e.autoCapture),e.persistence!==void 0&&e.persistence!==this._config.persistence){let s=this._storage;this._storage=m(e.persistence,{onFallback:r=>this._logger.warn(r)}),this._storage.migrate(s,[this._storageKey])}let t=this._sessionManager.getTrackingConsent();if(e.trackingConsent!==void 0&&e.trackingConsent!==t)if(this._sessionManager.setTrackingConsent(e.trackingConsent),t!==i.GRANTED&&e.trackingConsent===i.GRANTED){let s=this._eventQueue.flush();s.length>0&&s.forEach(r=>{this._processEvent(r.eventType,r.payload,r.context)})}else e.trackingConsent===i.DENIED&&this._eventQueue.clear();this._config={...this._config,...e}}_handleAutoCaptureChange(e){if(this._cleanupAutoCapture?.(),e){this._lastUrl&&this.page(this._lastUrl);let t=this._checkForChanges.bind(this),s=setInterval(t,$);o(({window:r})=>{r.addEventListener("popstate",t),r.addEventListener("hashchange",t)}),this._cleanupAutoCapture=()=>{clearInterval(s),o(({window:r})=>{r.removeEventListener("popstate",t),r.removeEventListener("hashchange",t)})}}else this._cleanupAutoCapture=void 0}identify(e,t={}){a(this._isInitialized,"The client must be initialized with init() before identifying users.");try{j(e)}catch(r){throw new Error(`[Altertable] ${r.message}`)}this._sessionManager.setUserId(e);let s=this._getEventContext();this._processEvent("identify",{environment:s.environment,traits:t,user_id:e,visitor_id:s.visitor_id},s)}updateTraits(e){let t=this._sessionManager.getUserId();a(t,"User must be identified with identify() before updating traits.");let s=this._getEventContext();this._processEvent("identify",{environment:s.environment,traits:e,user_id:t,visitor_id:s.visitor_id},s)}reset({resetVisitorId:e=!1,resetSessionId:t=!0}={}){a(this._isInitialized,"The client must be initialized with init() before resetting."),this._sessionManager.reset({resetVisitorId:e,resetSessionId:t})}page(e){a(this._isInitialized,"The client must be initialized with init() before tracking page views.");let t=new URL(e),s=`${t.origin}${t.pathname}`;this.track(M,{[q]:s,[G]:Y(),[F]:this._referrer,...Object.fromEntries(t.searchParams)})}track(e,t={}){a(this._isInitialized,"The client must be initialized with init() before tracking events."),this._sessionManager.renewSessionIfNeeded();let s=new Date().toISOString();this._sessionManager.updateLastEventAt(s);let r=this._getEventContext(),g={timestamp:s,event:e,environment:r.environment,user_id:r.user_id,session_id:r.session_id,visitor_id:r.visitor_id,properties:{[B]:"@altertable/altertable-js",[z]:"0.5.2",[K]:this._config.release,...t}};if(this._processEvent("track",g,r),this._config.debug){let l=this._sessionManager.getTrackingConsent();this._logger.logEvent(g,{trackingConsent:l})}}getTrackingConsent(){return this._sessionManager.getTrackingConsent()}_checkForChanges(){o(({window:e})=>{if(!this._config.autoCapture)return;let t=e.location.href;t!==this._lastUrl&&(this.page(t),this._referrer=this._lastUrl,this._lastUrl=t)})}_getEventContext(){return{environment:this._config.environment||S,user_id:this._sessionManager.getUserId(),visitor_id:this._sessionManager.getVisitorId(),session_id:this._sessionManager.getSessionId()}}_processEvent(e,t,s){switch(this._sessionManager.getTrackingConsent()){case i.GRANTED:this._request(`/${e}`,t);break;case i.PENDING:case i.DISMISSED:this._eventQueue.enqueue(e,t,s);break;case i.DENIED:break}}_request(e,t){a(this._apiKey,"Missing API key"),a(this._config,"Missing configuration");let s=`${this._config.baseUrl||P}${e}`,r=JSON.stringify(t);if(typeof navigator<"u"&&navigator.sendBeacon){let g=`${s}?apiKey=${encodeURIComponent(this._apiKey)}`,l=new Blob([r],{type:"application/json"});navigator.sendBeacon(g,l)}else fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this._apiKey}`},body:r})}};var w=new v;o(({window:n})=>{let e=n.Altertable;if(e&&Array.isArray(e))for(let t of e){let s=t[0],r=t.slice(1);w[s](...r)}n.Altertable=w});return Ee(Ae);})();
9
9
  //# sourceMappingURL=index.global.js.map