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.
@@ -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;IASZ,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"}
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"}
@@ -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;IAQZ,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"}
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"}
@@ -1,4 +1,13 @@
1
1
  import { QueuedEvent } from '../types/index.js';
2
- export declare function sendEvents(apiHost: string, events: QueuedEvent[]): Promise<void>;
3
- export declare function sendSingle(apiHost: string, endpoint: string, payload: Record<string, unknown>): Promise<void>;
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,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBtF;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAMf"}
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,3 @@
1
+ import G5 from './index.js';
2
+ export default G5;
3
+ //# sourceMappingURL=cjs-entry.d.ts.map
@@ -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;
@@ -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;IAoBhD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,eAAoB,GAAG,IAAI;IAkChE,cAAc,CAAC,UAAU,GAAE,eAAoB,GAAG,IAAI;IAUtD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM9B,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;IAa5B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,gBAAgB;CAKzB"}
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
- constructor(token: string, mode?: 'localStorage' | 'cookie' | 'none');
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;gBAEpC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,cAAc,GAAG,QAAQ,GAAG,MAAuB;IAKpF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAU/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAQpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQzB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,SAAS;CAIlB"}
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.G5Client = G5Client;
472
- exports.default = G5;
469
+ // CJS/UMD entry — exports the G5 singleton directly as module.exports
470
+
471
+ module.exports = G5;
473
472
  //# sourceMappingURL=index.cjs.js.map