@altertable/altertable-js 0.3.0 → 0.4.0
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/dist/index.global.js +46 -21
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +46 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.global.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
(() => {
|
|
2
|
+
// src/lib/safelyRunOnBrowser.ts
|
|
3
|
+
function safelyRunOnBrowser(callback, fallback = () => void 0) {
|
|
4
|
+
if (typeof window === "undefined") {
|
|
5
|
+
return fallback();
|
|
6
|
+
}
|
|
7
|
+
return callback({ window });
|
|
8
|
+
}
|
|
9
|
+
|
|
2
10
|
// src/core.ts
|
|
3
11
|
var DEFAULT_BASE_URL = "https://api.altertable.ai";
|
|
4
12
|
var DEFAULT_ENVIRONMENT = "production";
|
|
@@ -23,8 +31,14 @@
|
|
|
23
31
|
_userId;
|
|
24
32
|
_referrer;
|
|
25
33
|
constructor() {
|
|
26
|
-
this._referrer =
|
|
27
|
-
|
|
34
|
+
this._referrer = safelyRunOnBrowser(
|
|
35
|
+
({ window: window2 }) => window2.document.referrer || null,
|
|
36
|
+
() => null
|
|
37
|
+
);
|
|
38
|
+
this._lastUrl = safelyRunOnBrowser(
|
|
39
|
+
({ window: window2 }) => window2.location.href,
|
|
40
|
+
() => ""
|
|
41
|
+
);
|
|
28
42
|
this._sessionId = this._generateId("session");
|
|
29
43
|
this._visitorId = this._generateId("visitor");
|
|
30
44
|
this._userId = this._generateId("anonymous");
|
|
@@ -33,12 +47,16 @@
|
|
|
33
47
|
this._apiKey = apiKey;
|
|
34
48
|
this._config = config;
|
|
35
49
|
if (config.autoCapture !== false) {
|
|
36
|
-
|
|
50
|
+
if (this._lastUrl) {
|
|
51
|
+
this.page(this._lastUrl);
|
|
52
|
+
}
|
|
37
53
|
setInterval(() => {
|
|
38
54
|
this._checkForChanges();
|
|
39
55
|
}, AUTO_CAPTURE_INTERVAL);
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
57
|
+
window2.addEventListener("popstate", () => this._checkForChanges());
|
|
58
|
+
window2.addEventListener("hashchange", () => this._checkForChanges());
|
|
59
|
+
});
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
identify(userId) {
|
|
@@ -63,7 +81,7 @@
|
|
|
63
81
|
environment: this._config.environment || DEFAULT_ENVIRONMENT,
|
|
64
82
|
properties: {
|
|
65
83
|
[PROPERTY_LIB]: "@altertable/altertable-js",
|
|
66
|
-
[PROPERTY_LIB_VERSION]: "0.
|
|
84
|
+
[PROPERTY_LIB_VERSION]: "0.4.0",
|
|
67
85
|
[PROPERTY_RELEASE]: this._config.release,
|
|
68
86
|
// The above properties might be overridden by user-provided fields
|
|
69
87
|
// and the React library
|
|
@@ -72,12 +90,14 @@
|
|
|
72
90
|
});
|
|
73
91
|
}
|
|
74
92
|
_checkForChanges() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
94
|
+
const currentUrl = window2.location.href;
|
|
95
|
+
if (currentUrl !== this._lastUrl) {
|
|
96
|
+
this.page(currentUrl);
|
|
97
|
+
this._referrer = this._lastUrl;
|
|
98
|
+
this._lastUrl = currentUrl;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
81
101
|
}
|
|
82
102
|
_request(path, body) {
|
|
83
103
|
const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;
|
|
@@ -131,20 +151,25 @@
|
|
|
131
151
|
return `${prefix}-${Math.random().toString(36).substring(2)}`;
|
|
132
152
|
}
|
|
133
153
|
_getViewport() {
|
|
134
|
-
return
|
|
154
|
+
return safelyRunOnBrowser(
|
|
155
|
+
({ window: window2 }) => `${window2.innerWidth}x${window2.innerHeight}`,
|
|
156
|
+
() => "0x0"
|
|
157
|
+
);
|
|
135
158
|
}
|
|
136
159
|
};
|
|
137
160
|
|
|
138
161
|
// src/index.ts
|
|
139
162
|
var altertable = new Altertable();
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
164
|
+
const stub = window2.Altertable;
|
|
165
|
+
if (stub && Array.isArray(stub)) {
|
|
166
|
+
for (const item of stub) {
|
|
167
|
+
const method = item[0];
|
|
168
|
+
const args = item.slice(1);
|
|
169
|
+
altertable[method](...args);
|
|
170
|
+
}
|
|
146
171
|
}
|
|
147
|
-
|
|
148
|
-
|
|
172
|
+
window2.Altertable = altertable;
|
|
173
|
+
});
|
|
149
174
|
})();
|
|
150
175
|
//# sourceMappingURL=index.global.js.map
|
package/dist/index.global.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"sourcesContent":["export interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = document.referrer || null;\n this._lastUrl = window.location.href;\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n this.page(this._lastUrl);\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return `${window.innerWidth}x${window.innerHeight}`;\n }\n}\n","import { Altertable } from './core';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nconst stub = window.Altertable;\nif (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n}\n\nwindow.Altertable = altertable;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/safelyRunOnBrowser.ts","../src/core.ts","../src/index.ts"],"sourcesContent":["/** Runs code on browser environments safely. */\nexport function safelyRunOnBrowser<TReturn>(\n callback: (params: { window: typeof window }) => TReturn,\n /** Fallback to run on server environments. */\n fallback: () => TReturn = () => undefined as unknown as TReturn\n): TReturn {\n if (typeof window === 'undefined') {\n return fallback();\n }\n\n return callback({ window });\n}\n","import { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = safelyRunOnBrowser<string | null>(\n ({ window }) => window.document.referrer || null,\n () => null\n );\n this._lastUrl = safelyRunOnBrowser(\n ({ window }) => window.location.href,\n () => ''\n );\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n if (this._lastUrl) {\n this.page(this._lastUrl);\n }\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n safelyRunOnBrowser(({ window }) => {\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n });\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n safelyRunOnBrowser(({ window }) => {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n });\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return safelyRunOnBrowser(\n ({ window }) => `${window.innerWidth}x${window.innerHeight}`,\n () => '0x0'\n );\n }\n}\n","import { Altertable } from './core';\nimport { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nsafelyRunOnBrowser(({ window }) => {\n const stub = window.Altertable;\n if (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n }\n\n window.Altertable = altertable;\n});\n"],"mappings":"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","names":["window","window"]}
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,14 @@ __export(index_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
|
|
26
|
+
// src/lib/safelyRunOnBrowser.ts
|
|
27
|
+
function safelyRunOnBrowser(callback, fallback = () => void 0) {
|
|
28
|
+
if (typeof window === "undefined") {
|
|
29
|
+
return fallback();
|
|
30
|
+
}
|
|
31
|
+
return callback({ window });
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
// src/core.ts
|
|
27
35
|
var DEFAULT_BASE_URL = "https://api.altertable.ai";
|
|
28
36
|
var DEFAULT_ENVIRONMENT = "production";
|
|
@@ -47,8 +55,14 @@ var Altertable = class {
|
|
|
47
55
|
_userId;
|
|
48
56
|
_referrer;
|
|
49
57
|
constructor() {
|
|
50
|
-
this._referrer =
|
|
51
|
-
|
|
58
|
+
this._referrer = safelyRunOnBrowser(
|
|
59
|
+
({ window: window2 }) => window2.document.referrer || null,
|
|
60
|
+
() => null
|
|
61
|
+
);
|
|
62
|
+
this._lastUrl = safelyRunOnBrowser(
|
|
63
|
+
({ window: window2 }) => window2.location.href,
|
|
64
|
+
() => ""
|
|
65
|
+
);
|
|
52
66
|
this._sessionId = this._generateId("session");
|
|
53
67
|
this._visitorId = this._generateId("visitor");
|
|
54
68
|
this._userId = this._generateId("anonymous");
|
|
@@ -57,12 +71,16 @@ var Altertable = class {
|
|
|
57
71
|
this._apiKey = apiKey;
|
|
58
72
|
this._config = config;
|
|
59
73
|
if (config.autoCapture !== false) {
|
|
60
|
-
|
|
74
|
+
if (this._lastUrl) {
|
|
75
|
+
this.page(this._lastUrl);
|
|
76
|
+
}
|
|
61
77
|
setInterval(() => {
|
|
62
78
|
this._checkForChanges();
|
|
63
79
|
}, AUTO_CAPTURE_INTERVAL);
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
81
|
+
window2.addEventListener("popstate", () => this._checkForChanges());
|
|
82
|
+
window2.addEventListener("hashchange", () => this._checkForChanges());
|
|
83
|
+
});
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
identify(userId) {
|
|
@@ -87,7 +105,7 @@ var Altertable = class {
|
|
|
87
105
|
environment: this._config.environment || DEFAULT_ENVIRONMENT,
|
|
88
106
|
properties: {
|
|
89
107
|
[PROPERTY_LIB]: "@altertable/altertable-js",
|
|
90
|
-
[PROPERTY_LIB_VERSION]: "0.
|
|
108
|
+
[PROPERTY_LIB_VERSION]: "0.4.0",
|
|
91
109
|
[PROPERTY_RELEASE]: this._config.release,
|
|
92
110
|
// The above properties might be overridden by user-provided fields
|
|
93
111
|
// and the React library
|
|
@@ -96,12 +114,14 @@ var Altertable = class {
|
|
|
96
114
|
});
|
|
97
115
|
}
|
|
98
116
|
_checkForChanges() {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
118
|
+
const currentUrl = window2.location.href;
|
|
119
|
+
if (currentUrl !== this._lastUrl) {
|
|
120
|
+
this.page(currentUrl);
|
|
121
|
+
this._referrer = this._lastUrl;
|
|
122
|
+
this._lastUrl = currentUrl;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
105
125
|
}
|
|
106
126
|
_request(path, body) {
|
|
107
127
|
const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;
|
|
@@ -155,19 +175,24 @@ var Altertable = class {
|
|
|
155
175
|
return `${prefix}-${Math.random().toString(36).substring(2)}`;
|
|
156
176
|
}
|
|
157
177
|
_getViewport() {
|
|
158
|
-
return
|
|
178
|
+
return safelyRunOnBrowser(
|
|
179
|
+
({ window: window2 }) => `${window2.innerWidth}x${window2.innerHeight}`,
|
|
180
|
+
() => "0x0"
|
|
181
|
+
);
|
|
159
182
|
}
|
|
160
183
|
};
|
|
161
184
|
|
|
162
185
|
// src/index.ts
|
|
163
186
|
var altertable = new Altertable();
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
187
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
188
|
+
const stub = window2.Altertable;
|
|
189
|
+
if (stub && Array.isArray(stub)) {
|
|
190
|
+
for (const item of stub) {
|
|
191
|
+
const method = item[0];
|
|
192
|
+
const args = item.slice(1);
|
|
193
|
+
altertable[method](...args);
|
|
194
|
+
}
|
|
170
195
|
}
|
|
171
|
-
|
|
172
|
-
|
|
196
|
+
window2.Altertable = altertable;
|
|
197
|
+
});
|
|
173
198
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core.ts"],"sourcesContent":["import { Altertable } from './core';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nconst stub = window.Altertable;\nif (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n}\n\nwindow.Altertable = altertable;\n","export interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = document.referrer || null;\n this._lastUrl = window.location.href;\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n this.page(this._lastUrl);\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return `${window.innerWidth}x${window.innerHeight}`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuBA,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAIrB,IAAM,iBAAiB;AAEvB,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAE9B,IAAM,eAAe;AACrB,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AACrB,IAAM,uBAAuB;AAE7B,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,cAAc;AACZ,SAAK,YAAY,SAAS,YAAY;AACtC,SAAK,WAAW,OAAO,SAAS;AAChC,SAAK,aAAa,KAAK,YAAY,SAAS;AAC5C,SAAK,aAAa,KAAK,YAAY,SAAS;AAC5C,SAAK,UAAU,KAAK,YAAY,WAAW;AAAA,EAC7C;AAAA,EAEA,KAAK,QAAgB,SAAiB,CAAC,GAAG;AACxC,SAAK,UAAU;AACf,SAAK,UAAU;AAEf,QAAI,OAAO,gBAAgB,OAAO;AAChC,WAAK,KAAK,KAAK,QAAQ;AAEvB,kBAAY,MAAM;AAChB,aAAK,iBAAiB;AAAA,MACxB,GAAG,qBAAqB;AAExB,aAAO,iBAAiB,YAAY,MAAM,KAAK,iBAAiB,CAAC;AACjE,aAAO,iBAAiB,cAAc,MAAM,KAAK,iBAAiB,CAAC;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,SAAS,QAAgB;AAEvB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,KAAK,KAAa;AAChB,UAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,UAAM,mBAAmB,GAAG,UAAU,MAAM,GAAG,UAAU,QAAQ;AACjE,SAAK,MAAM,gBAAgB;AAAA,MACzB,CAAC,YAAY,GAAG;AAAA,MAChB,CAAC,mBAAmB,GAAG,KAAK,cAAc;AAAA,MAC1C,CAAC,mBAAmB,GAAG,KAAK,cAAc;AAAA,MAC1C,CAAC,iBAAiB,GAAG,KAAK,aAAa;AAAA,MACvC,CAAC,gBAAgB,GAAG,KAAK;AAAA,MACzB,GAAG,OAAO,YAAY,UAAU,YAAY;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAe,YAA8B;AACjD,SAAK,SAAS,UAAU;AAAA,MACtB;AAAA,MACA,SAAS,KAAK;AAAA,MACd,aAAa,KAAK,QAAQ,eAAe;AAAA,MACzC,YAAY;AAAA,QACV,CAAC,YAAY,GAAG;AAAA,QAChB,CAAC,oBAAoB,GAAG;AAAA,QACxB,CAAC,gBAAgB,GAAG,KAAK,QAAQ;AAAA;AAAA;AAAA,QAGjC,GAAI,cAAc,CAAC;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB;AACzB,UAAM,aAAa,OAAO,SAAS;AACnC,QAAI,eAAe,KAAK,UAAU;AAChC,WAAK,KAAK,UAAU;AACpB,WAAK,YAAY,KAAK;AACtB,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,SAAS,MAAc,MAAqB;AAClD,UAAM,MAAM,GAAG,KAAK,QAAQ,WAAW,gBAAgB,GAAG,IAAI;AAC9D,UAAM,UAAU,KAAK,UAAU,IAAI;AAEnC,QAAI,OAAO,cAAc,eAAe,UAAU,YAAY;AAC5D,YAAM,YAAY,GAAG,GAAG,WAAW,mBAAmB,KAAK,OAAO,CAAC;AACnE,YAAM,OAAO,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC7D,gBAAU,WAAW,WAAW,IAAI;AAAA,IACtC,OAAO;AACL,YAAM,KAAK;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,UAAU,KAAK,OAAO;AAAA,QACvC;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,gBAAwB;AAC9B,QAAI;AACF,UAAI,KAAK,eAAe,QAAQ,mBAAmB;AACnD,UAAI,CAAC,IAAI;AACP,aAAK,KAAK;AACV,uBAAe,QAAQ,qBAAqB,EAAE;AAAA,MAChD;AACA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEQ,gBAAwB;AAC9B,QAAI;AACF,UAAI,KAAK,aAAa,QAAQ,iBAAiB;AAC/C,UAAI,CAAC,IAAI;AACP,aAAK,KAAK;AACV,qBAAa,QAAQ,mBAAmB,EAAE;AAAA,MAC5C;AACA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEQ,YAAY,QAAwB;AAC1C,QACE,OAAO,WAAW,WAAW,eAC7B,OAAO,WAAW,OAAO,eAAe,YACxC;AACA,UAAI;AACF,eAAO,GAAG,MAAM,IAAI,OAAO,WAAW,CAAC;AAAA,MACzC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO,GAAG,MAAM,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC7D;AAAA,EAEQ,eAAuB;AAC7B,WAAO,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW;AAAA,EACnD;AACF;;;AD5KO,IAAM,aAAa,IAAI,WAAW;AAEzC,IAAM,OAAO,OAAO;AACpB,IAAI,QAAQ,MAAM,QAAQ,IAAI,GAAG;AAC/B,aAAW,QAAQ,MAAM;AACvB,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,OAAO,KAAK,MAAM,CAAC;AAEzB,IAAC,WAAW,MAA0B,EAAU,GAAG,IAAI;AAAA,EACzD;AACF;AAEA,OAAO,aAAa;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib/safelyRunOnBrowser.ts","../src/core.ts"],"sourcesContent":["import { Altertable } from './core';\nimport { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nsafelyRunOnBrowser(({ window }) => {\n const stub = window.Altertable;\n if (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n }\n\n window.Altertable = altertable;\n});\n","/** Runs code on browser environments safely. */\nexport function safelyRunOnBrowser<TReturn>(\n callback: (params: { window: typeof window }) => TReturn,\n /** Fallback to run on server environments. */\n fallback: () => TReturn = () => undefined as unknown as TReturn\n): TReturn {\n if (typeof window === 'undefined') {\n return fallback();\n }\n\n return callback({ window });\n}\n","import { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = safelyRunOnBrowser<string | null>(\n ({ window }) => window.document.referrer || null,\n () => null\n );\n this._lastUrl = safelyRunOnBrowser(\n ({ window }) => window.location.href,\n () => ''\n );\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n if (this._lastUrl) {\n this.page(this._lastUrl);\n }\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n safelyRunOnBrowser(({ window }) => {\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n });\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n safelyRunOnBrowser(({ window }) => {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n });\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return safelyRunOnBrowser(\n ({ window }) => `${window.innerWidth}x${window.innerHeight}`,\n () => '0x0'\n );\n }\n}\n"],"mappings":"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","names":["window","window"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// src/lib/safelyRunOnBrowser.ts
|
|
2
|
+
function safelyRunOnBrowser(callback, fallback = () => void 0) {
|
|
3
|
+
if (typeof window === "undefined") {
|
|
4
|
+
return fallback();
|
|
5
|
+
}
|
|
6
|
+
return callback({ window });
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
// src/core.ts
|
|
2
10
|
var DEFAULT_BASE_URL = "https://api.altertable.ai";
|
|
3
11
|
var DEFAULT_ENVIRONMENT = "production";
|
|
@@ -22,8 +30,14 @@ var Altertable = class {
|
|
|
22
30
|
_userId;
|
|
23
31
|
_referrer;
|
|
24
32
|
constructor() {
|
|
25
|
-
this._referrer =
|
|
26
|
-
|
|
33
|
+
this._referrer = safelyRunOnBrowser(
|
|
34
|
+
({ window: window2 }) => window2.document.referrer || null,
|
|
35
|
+
() => null
|
|
36
|
+
);
|
|
37
|
+
this._lastUrl = safelyRunOnBrowser(
|
|
38
|
+
({ window: window2 }) => window2.location.href,
|
|
39
|
+
() => ""
|
|
40
|
+
);
|
|
27
41
|
this._sessionId = this._generateId("session");
|
|
28
42
|
this._visitorId = this._generateId("visitor");
|
|
29
43
|
this._userId = this._generateId("anonymous");
|
|
@@ -32,12 +46,16 @@ var Altertable = class {
|
|
|
32
46
|
this._apiKey = apiKey;
|
|
33
47
|
this._config = config;
|
|
34
48
|
if (config.autoCapture !== false) {
|
|
35
|
-
|
|
49
|
+
if (this._lastUrl) {
|
|
50
|
+
this.page(this._lastUrl);
|
|
51
|
+
}
|
|
36
52
|
setInterval(() => {
|
|
37
53
|
this._checkForChanges();
|
|
38
54
|
}, AUTO_CAPTURE_INTERVAL);
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
56
|
+
window2.addEventListener("popstate", () => this._checkForChanges());
|
|
57
|
+
window2.addEventListener("hashchange", () => this._checkForChanges());
|
|
58
|
+
});
|
|
41
59
|
}
|
|
42
60
|
}
|
|
43
61
|
identify(userId) {
|
|
@@ -62,7 +80,7 @@ var Altertable = class {
|
|
|
62
80
|
environment: this._config.environment || DEFAULT_ENVIRONMENT,
|
|
63
81
|
properties: {
|
|
64
82
|
[PROPERTY_LIB]: "@altertable/altertable-js",
|
|
65
|
-
[PROPERTY_LIB_VERSION]: "0.
|
|
83
|
+
[PROPERTY_LIB_VERSION]: "0.4.0",
|
|
66
84
|
[PROPERTY_RELEASE]: this._config.release,
|
|
67
85
|
// The above properties might be overridden by user-provided fields
|
|
68
86
|
// and the React library
|
|
@@ -71,12 +89,14 @@ var Altertable = class {
|
|
|
71
89
|
});
|
|
72
90
|
}
|
|
73
91
|
_checkForChanges() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
93
|
+
const currentUrl = window2.location.href;
|
|
94
|
+
if (currentUrl !== this._lastUrl) {
|
|
95
|
+
this.page(currentUrl);
|
|
96
|
+
this._referrer = this._lastUrl;
|
|
97
|
+
this._lastUrl = currentUrl;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
80
100
|
}
|
|
81
101
|
_request(path, body) {
|
|
82
102
|
const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;
|
|
@@ -130,21 +150,26 @@ var Altertable = class {
|
|
|
130
150
|
return `${prefix}-${Math.random().toString(36).substring(2)}`;
|
|
131
151
|
}
|
|
132
152
|
_getViewport() {
|
|
133
|
-
return
|
|
153
|
+
return safelyRunOnBrowser(
|
|
154
|
+
({ window: window2 }) => `${window2.innerWidth}x${window2.innerHeight}`,
|
|
155
|
+
() => "0x0"
|
|
156
|
+
);
|
|
134
157
|
}
|
|
135
158
|
};
|
|
136
159
|
|
|
137
160
|
// src/index.ts
|
|
138
161
|
var altertable = new Altertable();
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
safelyRunOnBrowser(({ window: window2 }) => {
|
|
163
|
+
const stub = window2.Altertable;
|
|
164
|
+
if (stub && Array.isArray(stub)) {
|
|
165
|
+
for (const item of stub) {
|
|
166
|
+
const method = item[0];
|
|
167
|
+
const args = item.slice(1);
|
|
168
|
+
altertable[method](...args);
|
|
169
|
+
}
|
|
145
170
|
}
|
|
146
|
-
|
|
147
|
-
|
|
171
|
+
window2.Altertable = altertable;
|
|
172
|
+
});
|
|
148
173
|
export {
|
|
149
174
|
altertable
|
|
150
175
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core.ts","../src/index.ts"],"sourcesContent":["export interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = document.referrer || null;\n this._lastUrl = window.location.href;\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n this.page(this._lastUrl);\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return `${window.innerWidth}x${window.innerHeight}`;\n }\n}\n","import { Altertable } from './core';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nconst stub = window.Altertable;\nif (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n}\n\nwindow.Altertable = altertable;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/safelyRunOnBrowser.ts","../src/core.ts","../src/index.ts"],"sourcesContent":["/** Runs code on browser environments safely. */\nexport function safelyRunOnBrowser<TReturn>(\n callback: (params: { window: typeof window }) => TReturn,\n /** Fallback to run on server environments. */\n fallback: () => TReturn = () => undefined as unknown as TReturn\n): TReturn {\n if (typeof window === 'undefined') {\n return fallback();\n }\n\n return callback({ window });\n}\n","import { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport interface Config {\n /**\n * The base URL of the Altertable API.\n * @default https://api.altertable.ai\n */\n baseUrl?: string;\n /**\n * The environment of the application.\n * @default \"production\"\n */\n environment?: string;\n /**\n * Whether to automatically capture page views and events.\n * @default true\n */\n autoCapture?: boolean;\n /**\n * The release ID of the application.\n * This is helpful to identify the version of the application an event is coming from.\n */\n release?: string;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.altertable.ai';\nconst DEFAULT_ENVIRONMENT = 'production';\n\nexport type EventProperties = Record<string, unknown>;\n\nexport const PAGEVIEW_EVENT = '$pageview';\n\nexport const SESSION_STORAGE_KEY = 'altertable-session-id';\nexport const LOCAL_STORAGE_KEY = 'altertable-visitor-id';\nexport const AUTO_CAPTURE_INTERVAL = 100;\n\nexport const PROPERTY_URL = '$url';\nexport const PROPERTY_SESSION_ID = '$session_id';\nexport const PROPERTY_VISITOR_ID = '$visitor_id';\nexport const PROPERTY_VIEWPORT = '$viewport';\nexport const PROPERTY_REFERER = '$referer';\nexport const PROPERTY_RELEASE = '$release';\nexport const PROPERTY_LIB = '$lib';\nexport const PROPERTY_LIB_VERSION = '$lib_version';\n\nexport class Altertable {\n private _lastUrl: string;\n private _apiKey: string;\n private _config: Config;\n private _sessionId: string;\n private _visitorId: string;\n private _userId: string;\n private _referrer: string | null;\n\n constructor() {\n this._referrer = safelyRunOnBrowser<string | null>(\n ({ window }) => window.document.referrer || null,\n () => null\n );\n this._lastUrl = safelyRunOnBrowser(\n ({ window }) => window.location.href,\n () => ''\n );\n this._sessionId = this._generateId('session');\n this._visitorId = this._generateId('visitor');\n this._userId = this._generateId('anonymous');\n }\n\n init(apiKey: string, config: Config = {}) {\n this._apiKey = apiKey;\n this._config = config;\n\n if (config.autoCapture !== false) {\n if (this._lastUrl) {\n this.page(this._lastUrl);\n }\n\n setInterval(() => {\n this._checkForChanges();\n }, AUTO_CAPTURE_INTERVAL);\n\n safelyRunOnBrowser(({ window }) => {\n window.addEventListener('popstate', () => this._checkForChanges());\n window.addEventListener('hashchange', () => this._checkForChanges());\n });\n }\n }\n\n identify(userId: string) {\n // FIXME: dummy implementation\n this._userId = userId;\n }\n\n page(url: string) {\n const parsedUrl = new URL(url);\n const urlWithoutSearch = `${parsedUrl.origin}${parsedUrl.pathname}`;\n this.track(PAGEVIEW_EVENT, {\n [PROPERTY_URL]: urlWithoutSearch,\n [PROPERTY_SESSION_ID]: this._getSessionId(),\n [PROPERTY_VISITOR_ID]: this._getVisitorId(),\n [PROPERTY_VIEWPORT]: this._getViewport(),\n [PROPERTY_REFERER]: this._referrer,\n ...Object.fromEntries(parsedUrl.searchParams),\n });\n }\n\n track(event: string, properties?: EventProperties) {\n this._request('/track', {\n event,\n user_id: this._userId,\n environment: this._config.environment || DEFAULT_ENVIRONMENT,\n properties: {\n [PROPERTY_LIB]: __LIB__,\n [PROPERTY_LIB_VERSION]: __LIB_VERSION__,\n [PROPERTY_RELEASE]: this._config.release,\n // The above properties might be overridden by user-provided fields\n // and the React library\n ...(properties || {}),\n },\n });\n }\n\n private _checkForChanges() {\n safelyRunOnBrowser(({ window }) => {\n const currentUrl = window.location.href;\n if (currentUrl !== this._lastUrl) {\n this.page(currentUrl);\n this._referrer = this._lastUrl;\n this._lastUrl = currentUrl;\n }\n });\n }\n\n private _request(path: string, body: unknown): void {\n const url = `${this._config.baseUrl || DEFAULT_BASE_URL}${path}`;\n const payload = JSON.stringify(body);\n\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const beaconUrl = `${url}?apiKey=${encodeURIComponent(this._apiKey)}`;\n const blob = new Blob([payload], { type: 'application/json' });\n navigator.sendBeacon(beaconUrl, blob);\n } else {\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this._apiKey}`,\n },\n body: payload,\n });\n }\n }\n\n private _getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!id) {\n id = this._sessionId;\n sessionStorage.setItem(SESSION_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._sessionId;\n }\n }\n\n private _getVisitorId(): string {\n try {\n let id = localStorage.getItem(LOCAL_STORAGE_KEY);\n if (!id) {\n id = this._visitorId;\n localStorage.setItem(LOCAL_STORAGE_KEY, id);\n }\n return id;\n } catch {\n return this._visitorId;\n }\n }\n\n private _generateId(prefix: string): string {\n if (\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.randomUUID === 'function'\n ) {\n try {\n return `${prefix}-${crypto.randomUUID()}`;\n } catch {\n // Continue with Math.random() fallback.\n }\n }\n return `${prefix}-${Math.random().toString(36).substring(2)}`;\n }\n\n private _getViewport(): string {\n return safelyRunOnBrowser(\n ({ window }) => `${window.innerWidth}x${window.innerHeight}`,\n () => '0x0'\n );\n }\n}\n","import { Altertable } from './core';\nimport { safelyRunOnBrowser } from './lib/safelyRunOnBrowser';\n\nexport type { Altertable };\n\ndeclare global {\n interface Window {\n Altertable: Altertable | Array<Array<unknown>> | undefined;\n }\n}\n\nexport const altertable = new Altertable();\n\nsafelyRunOnBrowser(({ window }) => {\n const stub = window.Altertable;\n if (stub && Array.isArray(stub)) {\n for (const item of stub) {\n const method = item[0];\n const args = item.slice(1);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (altertable[method as keyof Altertable] as any)(...args);\n }\n }\n\n window.Altertable = altertable;\n});\n"],"mappings":"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","names":["window","window"]}
|