g5-analytics 1.0.2 → 1.1.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/api/groups.d.ts.map +1 -1
- package/dist/api/people.d.ts.map +1 -1
- package/dist/api/transport.d.ts +11 -2
- package/dist/api/transport.d.ts.map +1 -1
- package/dist/cjs-entry.d.ts +3 -0
- package/dist/cjs-entry.d.ts.map +1 -0
- package/dist/core/G5.d.ts +2 -0
- package/dist/core/G5.d.ts.map +1 -1
- package/dist/core/Persistence.d.ts +2 -1
- package/dist/core/Persistence.d.ts.map +1 -1
- package/dist/index.cjs +559 -0
- package/dist/index.cjs.js +3 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +555 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
package/dist/api/groups.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../src/api/groups.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;YAO/D,IAAI;
|
|
1
|
+
{"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../src/api/groups.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;YAO/D,IAAI;IAaZ,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAGxD"}
|
package/dist/api/people.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"people.d.ts","sourceRoot":"","sources":["../../src/api/people.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAEhE,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAiB;gBAErB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe;YAMvD,IAAI;
|
|
1
|
+
{"version":3,"file":"people.d.ts","sourceRoot":"","sources":["../../src/api/people.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAEhE,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAiB;gBAErB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe;YAMvD,IAAI;IAYZ,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnF,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtC"}
|
package/dist/api/transport.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { QueuedEvent } from '../types/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Send batch of events to /import endpoint.
|
|
4
|
+
* Includes x-g5-token header for authentication.
|
|
5
|
+
* Falls back from sendBeacon → fetch with keepalive.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sendEvents(apiHost: string, token: string, events: QueuedEvent[]): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Send a single request to a specific endpoint (/engage, /groups, /track).
|
|
10
|
+
* Includes x-g5-token header for authentication.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sendSingle(apiHost: string, token: string, endpoint: string, payload: Record<string, unknown>): Promise<void>;
|
|
4
13
|
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/api/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,wBAAsB,UAAU,
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/api/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cjs-entry.d.ts","sourceRoot":"","sources":["../src/cjs-entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,eAAe,EAAE,CAAA"}
|
package/dist/core/G5.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class G5Client {
|
|
|
11
11
|
private superProperties;
|
|
12
12
|
private timedEvents;
|
|
13
13
|
private optedOut;
|
|
14
|
+
private flushing;
|
|
14
15
|
people: People;
|
|
15
16
|
constructor(token: string, config?: G5Config);
|
|
16
17
|
track(eventName: string, properties?: TrackProperties): void;
|
|
@@ -29,6 +30,7 @@ export declare class G5Client {
|
|
|
29
30
|
has_opted_in_tracking(): boolean;
|
|
30
31
|
clear_opt_in_out_tracking(): void;
|
|
31
32
|
flush(): Promise<void>;
|
|
33
|
+
destroy(): void;
|
|
32
34
|
private startFlushTimer;
|
|
33
35
|
private bindPageUnload;
|
|
34
36
|
private generateInsertId;
|
package/dist/core/G5.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"G5.d.ts","sourceRoot":"","sources":["../../src/core/G5.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAe,MAAM,mBAAmB,CAAA;AAI1E,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAO9C,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,QAAQ,CAAQ;IAEjB,MAAM,EAAE,MAAM,CAAA;gBAET,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,QAAa;
|
|
1
|
+
{"version":3,"file":"G5.d.ts","sourceRoot":"","sources":["../../src/core/G5.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAe,MAAM,mBAAmB,CAAA;AAI1E,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAO9C,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,QAAQ,CAAQ;IAEjB,MAAM,EAAE,MAAM,CAAA;gBAET,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,QAAa;IA+BhD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,eAAoB,GAAG,IAAI;IAmChE,cAAc,CAAC,UAAU,GAAE,eAAoB,GAAG,IAAI;IAWtD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAS9B,KAAK,IAAI,IAAI;IAOb,QAAQ,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI;IAI3C,aAAa,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI;IAQhD,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIlC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAInC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IAKzD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IAIzD,eAAe,IAAI,IAAI;IAKvB,gBAAgB,IAAI,IAAI;IAMxB,sBAAsB,IAAI,OAAO;IAIjC,qBAAqB,IAAI,OAAO;IAIhC,yBAAyB,IAAI,IAAI;IAK3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB5B,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,gBAAgB;CAKzB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare class Persistence {
|
|
2
2
|
private prefix;
|
|
3
3
|
private mode;
|
|
4
|
-
|
|
4
|
+
private cookieDomain;
|
|
5
|
+
constructor(token: string, mode?: 'localStorage' | 'cookie' | 'none', cookieDomain?: string);
|
|
5
6
|
get(key: string): string | null;
|
|
6
7
|
set(key: string, value: string, days?: number): void;
|
|
7
8
|
remove(key: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Persistence.d.ts","sourceRoot":"","sources":["../../src/core/Persistence.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,IAAI,CAAoC;
|
|
1
|
+
{"version":3,"file":"Persistence.d.ts","sourceRoot":"","sources":["../../src/core/Persistence.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,IAAI,CAAoC;IAChD,OAAO,CAAC,YAAY,CAAQ;gBAG1B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,cAAc,GAAG,QAAQ,GAAG,MAAuB,EACzD,YAAY,SAAK;IAOnB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAc/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAYpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAYzB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,SAAS;CAQlB"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class Persistence {
|
|
4
|
+
prefix;
|
|
5
|
+
mode;
|
|
6
|
+
cookieDomain;
|
|
7
|
+
constructor(token, mode = 'localStorage', cookieDomain = '') {
|
|
8
|
+
this.prefix = `g5_${token}_`;
|
|
9
|
+
this.mode = mode;
|
|
10
|
+
this.cookieDomain = cookieDomain;
|
|
11
|
+
}
|
|
12
|
+
get(key) {
|
|
13
|
+
try {
|
|
14
|
+
if (this.mode === 'localStorage' && typeof localStorage !== 'undefined') {
|
|
15
|
+
return localStorage.getItem(this.prefix + key);
|
|
16
|
+
}
|
|
17
|
+
if (this.mode === 'cookie' && typeof document !== 'undefined') {
|
|
18
|
+
return this.getCookie(this.prefix + key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// localStorage or cookie access may throw in some environments
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
set(key, value, days) {
|
|
27
|
+
try {
|
|
28
|
+
if (this.mode === 'localStorage' && typeof localStorage !== 'undefined') {
|
|
29
|
+
localStorage.setItem(this.prefix + key, value);
|
|
30
|
+
}
|
|
31
|
+
else if (this.mode === 'cookie' && typeof document !== 'undefined') {
|
|
32
|
+
this.setCookie(this.prefix + key, value, days || 365);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Silently fail if storage is unavailable
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
remove(key) {
|
|
40
|
+
try {
|
|
41
|
+
if (this.mode === 'localStorage' && typeof localStorage !== 'undefined') {
|
|
42
|
+
localStorage.removeItem(this.prefix + key);
|
|
43
|
+
}
|
|
44
|
+
else if (this.mode === 'cookie' && typeof document !== 'undefined') {
|
|
45
|
+
this.setCookie(this.prefix + key, '', -1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Silently fail
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
getCookie(name) {
|
|
53
|
+
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
|
54
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
55
|
+
}
|
|
56
|
+
setCookie(name, value, days) {
|
|
57
|
+
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
58
|
+
let cookie = `${name}=${encodeURIComponent(value)};expires=${expires};path=/;SameSite=Lax`;
|
|
59
|
+
if (this.cookieDomain) {
|
|
60
|
+
cookie += `;domain=${this.cookieDomain}`;
|
|
61
|
+
}
|
|
62
|
+
document.cookie = cookie;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const QUEUE_KEY = 'event_queue';
|
|
67
|
+
const MAX_QUEUE_SIZE = 1000;
|
|
68
|
+
class EventQueue {
|
|
69
|
+
persistence;
|
|
70
|
+
queue;
|
|
71
|
+
constructor(persistence) {
|
|
72
|
+
this.persistence = persistence;
|
|
73
|
+
this.queue = this.load();
|
|
74
|
+
}
|
|
75
|
+
enqueue(event) {
|
|
76
|
+
if (this.queue.length >= MAX_QUEUE_SIZE) {
|
|
77
|
+
this.queue.shift(); // drop oldest
|
|
78
|
+
}
|
|
79
|
+
this.queue.push(event);
|
|
80
|
+
this.save();
|
|
81
|
+
}
|
|
82
|
+
flush() {
|
|
83
|
+
const items = [...this.queue];
|
|
84
|
+
this.queue = [];
|
|
85
|
+
this.save();
|
|
86
|
+
return items;
|
|
87
|
+
}
|
|
88
|
+
size() {
|
|
89
|
+
return this.queue.length;
|
|
90
|
+
}
|
|
91
|
+
load() {
|
|
92
|
+
try {
|
|
93
|
+
const raw = this.persistence.get(QUEUE_KEY);
|
|
94
|
+
return raw ? JSON.parse(raw) : [];
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
save() {
|
|
101
|
+
this.persistence.set(QUEUE_KEY, JSON.stringify(this.queue));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const DEVICE_ID_KEY = 'device_id';
|
|
106
|
+
function getOrCreateDeviceId(persistence) {
|
|
107
|
+
const existing = persistence.get(DEVICE_ID_KEY);
|
|
108
|
+
if (existing)
|
|
109
|
+
return existing;
|
|
110
|
+
const id = generateUUID();
|
|
111
|
+
persistence.set(DEVICE_ID_KEY, id);
|
|
112
|
+
return id;
|
|
113
|
+
}
|
|
114
|
+
function clearDeviceId(persistence) {
|
|
115
|
+
const newId = generateUUID();
|
|
116
|
+
persistence.set(DEVICE_ID_KEY, newId);
|
|
117
|
+
return newId;
|
|
118
|
+
}
|
|
119
|
+
function generateUUID() {
|
|
120
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
121
|
+
return crypto.randomUUID();
|
|
122
|
+
}
|
|
123
|
+
// Fallback for older environments
|
|
124
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
125
|
+
const r = (Math.random() * 16) | 0;
|
|
126
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
127
|
+
return v.toString(16);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const USER_ID_KEY = 'user_id';
|
|
132
|
+
class IdentityManager {
|
|
133
|
+
persistence;
|
|
134
|
+
_deviceId;
|
|
135
|
+
_userId;
|
|
136
|
+
constructor(persistence) {
|
|
137
|
+
this.persistence = persistence;
|
|
138
|
+
this._deviceId = getOrCreateDeviceId(persistence);
|
|
139
|
+
this._userId = persistence.get(USER_ID_KEY);
|
|
140
|
+
}
|
|
141
|
+
get deviceId() {
|
|
142
|
+
return this._deviceId;
|
|
143
|
+
}
|
|
144
|
+
get userId() {
|
|
145
|
+
return this._userId;
|
|
146
|
+
}
|
|
147
|
+
get distinctId() {
|
|
148
|
+
return this._userId || this._deviceId;
|
|
149
|
+
}
|
|
150
|
+
identify(userId) {
|
|
151
|
+
this._userId = userId;
|
|
152
|
+
this.persistence.set(USER_ID_KEY, userId);
|
|
153
|
+
}
|
|
154
|
+
reset() {
|
|
155
|
+
this._userId = null;
|
|
156
|
+
this.persistence.remove(USER_ID_KEY);
|
|
157
|
+
this._deviceId = clearDeviceId(this.persistence);
|
|
158
|
+
}
|
|
159
|
+
getIdentityProperties() {
|
|
160
|
+
const props = {
|
|
161
|
+
$device_id: this._deviceId,
|
|
162
|
+
};
|
|
163
|
+
if (this._userId) {
|
|
164
|
+
props['$user_id'] = this._userId;
|
|
165
|
+
}
|
|
166
|
+
return props;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Send batch of events to /import endpoint.
|
|
172
|
+
* Includes x-g5-token header for authentication.
|
|
173
|
+
* Falls back from sendBeacon → fetch with keepalive.
|
|
174
|
+
*/
|
|
175
|
+
async function sendEvents(apiHost, token, events) {
|
|
176
|
+
const url = `${apiHost}/import`;
|
|
177
|
+
const payload = events.map((e) => ({ event: e.event, properties: e.properties }));
|
|
178
|
+
const body = JSON.stringify(payload);
|
|
179
|
+
// sendBeacon for page-unload (can't set custom headers, token is in payload)
|
|
180
|
+
if (typeof navigator !== 'undefined' && navigator.sendBeacon) {
|
|
181
|
+
const blob = new Blob([body], { type: 'application/json' });
|
|
182
|
+
if (navigator.sendBeacon(url, blob))
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Fallback: fetch with token header
|
|
186
|
+
await fetch(url, {
|
|
187
|
+
method: 'POST',
|
|
188
|
+
headers: {
|
|
189
|
+
'Content-Type': 'application/json',
|
|
190
|
+
'x-g5-token': token,
|
|
191
|
+
},
|
|
192
|
+
body,
|
|
193
|
+
keepalive: true,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Send a single request to a specific endpoint (/engage, /groups, /track).
|
|
198
|
+
* Includes x-g5-token header for authentication.
|
|
199
|
+
*/
|
|
200
|
+
async function sendSingle(apiHost, token, endpoint, payload) {
|
|
201
|
+
await fetch(`${apiHost}${endpoint}`, {
|
|
202
|
+
method: 'POST',
|
|
203
|
+
headers: {
|
|
204
|
+
'Content-Type': 'application/json',
|
|
205
|
+
'x-g5-token': token,
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify(payload),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
class People {
|
|
212
|
+
apiHost;
|
|
213
|
+
token;
|
|
214
|
+
identity;
|
|
215
|
+
constructor(apiHost, token, identity) {
|
|
216
|
+
this.apiHost = apiHost;
|
|
217
|
+
this.token = token;
|
|
218
|
+
this.identity = identity;
|
|
219
|
+
}
|
|
220
|
+
async send(ops) {
|
|
221
|
+
try {
|
|
222
|
+
await sendSingle(this.apiHost, this.token, '/engage', {
|
|
223
|
+
$distinct_id: this.identity.distinctId,
|
|
224
|
+
$token: this.token,
|
|
225
|
+
...ops,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
console.warn('[G5] people operation failed', err);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async set(properties) {
|
|
233
|
+
await this.send({ $set: properties });
|
|
234
|
+
}
|
|
235
|
+
async set_once(properties) {
|
|
236
|
+
await this.send({ $set_once: properties });
|
|
237
|
+
}
|
|
238
|
+
async increment(property, value) {
|
|
239
|
+
const ops = typeof property === 'string' ? { [property]: value ?? 1 } : property;
|
|
240
|
+
await this.send({ $increment: ops });
|
|
241
|
+
}
|
|
242
|
+
async append(property, value) {
|
|
243
|
+
await this.send({ $append: { [property]: value } });
|
|
244
|
+
}
|
|
245
|
+
async union(property, values) {
|
|
246
|
+
await this.send({ $union: { [property]: values } });
|
|
247
|
+
}
|
|
248
|
+
async unset(property) {
|
|
249
|
+
await this.send({ $unset: Array.isArray(property) ? property : [property] });
|
|
250
|
+
}
|
|
251
|
+
async remove(property, value) {
|
|
252
|
+
await this.send({ $remove: { [property]: value } });
|
|
253
|
+
}
|
|
254
|
+
async delete_profile() {
|
|
255
|
+
await this.send({ $delete: '' });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
class GroupClient {
|
|
260
|
+
apiHost;
|
|
261
|
+
token;
|
|
262
|
+
groupKey;
|
|
263
|
+
groupId;
|
|
264
|
+
constructor(apiHost, token, groupKey, groupId) {
|
|
265
|
+
this.apiHost = apiHost;
|
|
266
|
+
this.token = token;
|
|
267
|
+
this.groupKey = groupKey;
|
|
268
|
+
this.groupId = groupId;
|
|
269
|
+
}
|
|
270
|
+
async send(ops) {
|
|
271
|
+
try {
|
|
272
|
+
await sendSingle(this.apiHost, this.token, '/groups', {
|
|
273
|
+
$token: this.token,
|
|
274
|
+
$group_key: this.groupKey,
|
|
275
|
+
$group_id: this.groupId,
|
|
276
|
+
...ops,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
console.warn('[G5] group operation failed', err);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async set(properties) {
|
|
284
|
+
await this.send({ $set: properties });
|
|
285
|
+
}
|
|
286
|
+
async set_once(properties) {
|
|
287
|
+
await this.send({ $set_once: properties });
|
|
288
|
+
}
|
|
289
|
+
async increment(property, value = 1) {
|
|
290
|
+
await this.send({ $increment: { [property]: value } });
|
|
291
|
+
}
|
|
292
|
+
async unset(property) {
|
|
293
|
+
await this.send({ $unset: Array.isArray(property) ? property : [property] });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const DEFAULT_API_HOST = 'https://g5-api-757475034422.asia-south1.run.app';
|
|
298
|
+
const DEFAULT_BATCH_SIZE = 50;
|
|
299
|
+
const DEFAULT_FLUSH_INTERVAL = 10000; // 10s
|
|
300
|
+
class G5Client {
|
|
301
|
+
token;
|
|
302
|
+
config;
|
|
303
|
+
persistence;
|
|
304
|
+
queue;
|
|
305
|
+
identity;
|
|
306
|
+
flushTimer = null;
|
|
307
|
+
superProperties = {};
|
|
308
|
+
timedEvents = new Map();
|
|
309
|
+
optedOut = false;
|
|
310
|
+
flushing = false;
|
|
311
|
+
people;
|
|
312
|
+
constructor(token, config = {}) {
|
|
313
|
+
if (!token || typeof token !== 'string') {
|
|
314
|
+
throw new Error('[G5] init() requires a valid project token string');
|
|
315
|
+
}
|
|
316
|
+
this.token = token;
|
|
317
|
+
this.config = {
|
|
318
|
+
apiHost: config.apiHost || DEFAULT_API_HOST,
|
|
319
|
+
batchSize: Math.max(1, Math.min(config.batchSize || DEFAULT_BATCH_SIZE, 2000)),
|
|
320
|
+
flushInterval: Math.max(1000, config.flushInterval || DEFAULT_FLUSH_INTERVAL),
|
|
321
|
+
debug: config.debug || false,
|
|
322
|
+
persistence: config.persistence || 'localStorage',
|
|
323
|
+
cookieDomain: config.cookieDomain || '',
|
|
324
|
+
};
|
|
325
|
+
this.persistence = new Persistence(token, this.config.persistence, this.config.cookieDomain);
|
|
326
|
+
this.queue = new EventQueue(this.persistence);
|
|
327
|
+
this.identity = new IdentityManager(this.persistence);
|
|
328
|
+
this.people = new People(this.config.apiHost, token, this.identity);
|
|
329
|
+
// Restore opt-out state
|
|
330
|
+
this.optedOut = this.persistence.get('opted_out') === 'true';
|
|
331
|
+
this.startFlushTimer();
|
|
332
|
+
this.bindPageUnload();
|
|
333
|
+
if (this.config.debug) {
|
|
334
|
+
console.log('[G5] initialized', { token: token.slice(0, 8) + '...', apiHost: this.config.apiHost });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
track(eventName, properties = {}) {
|
|
338
|
+
if (this.optedOut)
|
|
339
|
+
return;
|
|
340
|
+
if (!eventName || typeof eventName !== 'string')
|
|
341
|
+
return;
|
|
342
|
+
const now = Date.now();
|
|
343
|
+
const timedStart = this.timedEvents.get(eventName);
|
|
344
|
+
if (timedStart !== undefined) {
|
|
345
|
+
properties['$duration'] = (now - timedStart) / 1000;
|
|
346
|
+
this.timedEvents.delete(eventName);
|
|
347
|
+
}
|
|
348
|
+
const event = {
|
|
349
|
+
event: eventName,
|
|
350
|
+
properties: {
|
|
351
|
+
...this.superProperties,
|
|
352
|
+
...properties,
|
|
353
|
+
...this.identity.getIdentityProperties(),
|
|
354
|
+
token: this.token,
|
|
355
|
+
distinct_id: this.identity.distinctId,
|
|
356
|
+
time: Math.floor(now / 1000),
|
|
357
|
+
$insert_id: this.generateInsertId(),
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
this.queue.enqueue(event);
|
|
361
|
+
if (this.queue.size() >= this.config.batchSize) {
|
|
362
|
+
this.flush();
|
|
363
|
+
}
|
|
364
|
+
if (this.config.debug) {
|
|
365
|
+
console.log('[G5] track', eventName, event.properties);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
track_pageview(properties = {}) {
|
|
369
|
+
if (typeof window === 'undefined')
|
|
370
|
+
return;
|
|
371
|
+
this.track('$pageview', {
|
|
372
|
+
$current_url: window.location.href,
|
|
373
|
+
$pathname: window.location.pathname,
|
|
374
|
+
$title: document.title,
|
|
375
|
+
$referrer: document.referrer || undefined,
|
|
376
|
+
...properties,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
identify(userId) {
|
|
380
|
+
if (!userId || typeof userId !== 'string') {
|
|
381
|
+
if (this.config.debug)
|
|
382
|
+
console.warn('[G5] identify() requires a non-empty string userId');
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
this.identity.identify(userId);
|
|
386
|
+
this.track('$identify', {});
|
|
387
|
+
}
|
|
388
|
+
reset() {
|
|
389
|
+
this.flush();
|
|
390
|
+
this.identity.reset();
|
|
391
|
+
this.superProperties = {};
|
|
392
|
+
this.timedEvents.clear();
|
|
393
|
+
}
|
|
394
|
+
register(properties) {
|
|
395
|
+
Object.assign(this.superProperties, properties);
|
|
396
|
+
}
|
|
397
|
+
register_once(properties) {
|
|
398
|
+
for (const [k, v] of Object.entries(properties)) {
|
|
399
|
+
if (!(k in this.superProperties)) {
|
|
400
|
+
this.superProperties[k] = v;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
unregister(property) {
|
|
405
|
+
delete this.superProperties[property];
|
|
406
|
+
}
|
|
407
|
+
time_event(eventName) {
|
|
408
|
+
this.timedEvents.set(eventName, Date.now());
|
|
409
|
+
}
|
|
410
|
+
set_group(groupKey, groupId) {
|
|
411
|
+
this.register({ [groupKey]: groupId });
|
|
412
|
+
return new GroupClient(this.config.apiHost, this.token, groupKey, groupId);
|
|
413
|
+
}
|
|
414
|
+
get_group(groupKey, groupId) {
|
|
415
|
+
return new GroupClient(this.config.apiHost, this.token, groupKey, groupId);
|
|
416
|
+
}
|
|
417
|
+
opt_in_tracking() {
|
|
418
|
+
this.optedOut = false;
|
|
419
|
+
this.persistence.set('opted_out', 'false');
|
|
420
|
+
}
|
|
421
|
+
opt_out_tracking() {
|
|
422
|
+
this.flush();
|
|
423
|
+
this.optedOut = true;
|
|
424
|
+
this.persistence.set('opted_out', 'true');
|
|
425
|
+
}
|
|
426
|
+
has_opted_out_tracking() {
|
|
427
|
+
return this.optedOut;
|
|
428
|
+
}
|
|
429
|
+
has_opted_in_tracking() {
|
|
430
|
+
return !this.optedOut;
|
|
431
|
+
}
|
|
432
|
+
clear_opt_in_out_tracking() {
|
|
433
|
+
this.persistence.remove('opted_out');
|
|
434
|
+
this.optedOut = false;
|
|
435
|
+
}
|
|
436
|
+
async flush() {
|
|
437
|
+
// Prevent concurrent flushes
|
|
438
|
+
if (this.flushing)
|
|
439
|
+
return;
|
|
440
|
+
this.flushing = true;
|
|
441
|
+
try {
|
|
442
|
+
const events = this.queue.flush();
|
|
443
|
+
if (events.length === 0)
|
|
444
|
+
return;
|
|
445
|
+
await sendEvents(this.config.apiHost, this.token, events);
|
|
446
|
+
if (this.config.debug) {
|
|
447
|
+
console.log(`[G5] flushed ${events.length} events`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
if (this.config.debug)
|
|
452
|
+
console.error('[G5] flush failed', err);
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
this.flushing = false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
destroy() {
|
|
459
|
+
if (this.flushTimer) {
|
|
460
|
+
clearInterval(this.flushTimer);
|
|
461
|
+
this.flushTimer = null;
|
|
462
|
+
}
|
|
463
|
+
this.flush();
|
|
464
|
+
}
|
|
465
|
+
startFlushTimer() {
|
|
466
|
+
if (this.flushTimer)
|
|
467
|
+
clearInterval(this.flushTimer);
|
|
468
|
+
this.flushTimer = setInterval(() => this.flush(), this.config.flushInterval);
|
|
469
|
+
}
|
|
470
|
+
bindPageUnload() {
|
|
471
|
+
if (typeof window !== 'undefined') {
|
|
472
|
+
window.addEventListener('visibilitychange', () => {
|
|
473
|
+
if (document.visibilityState === 'hidden')
|
|
474
|
+
this.flush();
|
|
475
|
+
});
|
|
476
|
+
window.addEventListener('beforeunload', () => this.flush());
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
generateInsertId() {
|
|
480
|
+
const ts = Date.now().toString(36);
|
|
481
|
+
const rand = Math.random().toString(36).slice(2, 8);
|
|
482
|
+
return `${ts}${rand}`.slice(0, 36);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
let defaultInstance = null;
|
|
487
|
+
// Singleton API (Mixpanel-style usage)
|
|
488
|
+
const G5 = {
|
|
489
|
+
init(token, config = {}) {
|
|
490
|
+
if (defaultInstance) {
|
|
491
|
+
defaultInstance.destroy();
|
|
492
|
+
}
|
|
493
|
+
defaultInstance = new G5Client(token, config);
|
|
494
|
+
return defaultInstance;
|
|
495
|
+
},
|
|
496
|
+
track(eventName, properties) {
|
|
497
|
+
defaultInstance?.track(eventName, properties);
|
|
498
|
+
},
|
|
499
|
+
track_pageview(properties) {
|
|
500
|
+
defaultInstance?.track_pageview(properties);
|
|
501
|
+
},
|
|
502
|
+
identify(userId) {
|
|
503
|
+
defaultInstance?.identify(userId);
|
|
504
|
+
},
|
|
505
|
+
reset() {
|
|
506
|
+
defaultInstance?.reset();
|
|
507
|
+
},
|
|
508
|
+
register(properties) {
|
|
509
|
+
defaultInstance?.register(properties);
|
|
510
|
+
},
|
|
511
|
+
register_once(properties) {
|
|
512
|
+
defaultInstance?.register_once(properties);
|
|
513
|
+
},
|
|
514
|
+
unregister(property) {
|
|
515
|
+
defaultInstance?.unregister(property);
|
|
516
|
+
},
|
|
517
|
+
time_event(eventName) {
|
|
518
|
+
defaultInstance?.time_event(eventName);
|
|
519
|
+
},
|
|
520
|
+
set_group(groupKey, groupId) {
|
|
521
|
+
return defaultInstance?.set_group(groupKey, groupId);
|
|
522
|
+
},
|
|
523
|
+
get_group(groupKey, groupId) {
|
|
524
|
+
return defaultInstance?.get_group(groupKey, groupId);
|
|
525
|
+
},
|
|
526
|
+
opt_in_tracking() {
|
|
527
|
+
defaultInstance?.opt_in_tracking();
|
|
528
|
+
},
|
|
529
|
+
opt_out_tracking() {
|
|
530
|
+
defaultInstance?.opt_out_tracking();
|
|
531
|
+
},
|
|
532
|
+
has_opted_out_tracking() {
|
|
533
|
+
return defaultInstance?.has_opted_out_tracking() ?? false;
|
|
534
|
+
},
|
|
535
|
+
has_opted_in_tracking() {
|
|
536
|
+
return defaultInstance?.has_opted_in_tracking() ?? true;
|
|
537
|
+
},
|
|
538
|
+
clear_opt_in_out_tracking() {
|
|
539
|
+
defaultInstance?.clear_opt_in_out_tracking();
|
|
540
|
+
},
|
|
541
|
+
get people() {
|
|
542
|
+
return defaultInstance?.people;
|
|
543
|
+
},
|
|
544
|
+
flush() {
|
|
545
|
+
return defaultInstance?.flush() ?? Promise.resolve();
|
|
546
|
+
},
|
|
547
|
+
destroy() {
|
|
548
|
+
defaultInstance?.destroy();
|
|
549
|
+
defaultInstance = null;
|
|
550
|
+
},
|
|
551
|
+
create(token, config = {}) {
|
|
552
|
+
return new G5Client(token, config);
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// CJS/UMD entry — exports the G5 singleton directly as module.exports
|
|
557
|
+
|
|
558
|
+
module.exports = G5;
|
|
559
|
+
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
class Persistence {
|
|
6
4
|
prefix;
|
|
7
5
|
mode;
|
|
@@ -468,6 +466,7 @@ const G5 = {
|
|
|
468
466
|
},
|
|
469
467
|
};
|
|
470
468
|
|
|
471
|
-
exports
|
|
472
|
-
|
|
469
|
+
// CJS/UMD entry — exports the G5 singleton directly as module.exports
|
|
470
|
+
|
|
471
|
+
module.exports = G5;
|
|
473
472
|
//# sourceMappingURL=index.cjs.js.map
|