@agentuity/frontend 0.0.110 → 0.0.112
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/analytics/beacon.d.ts +15 -0
- package/dist/analytics/beacon.d.ts.map +1 -0
- package/dist/analytics/beacon.js +177 -0
- package/dist/analytics/beacon.js.map +1 -0
- package/dist/analytics/collectors/clicks.d.ts +10 -0
- package/dist/analytics/collectors/clicks.d.ts.map +1 -0
- package/dist/analytics/collectors/clicks.js +84 -0
- package/dist/analytics/collectors/clicks.js.map +1 -0
- package/dist/analytics/collectors/errors.d.ts +5 -0
- package/dist/analytics/collectors/errors.d.ts.map +1 -0
- package/dist/analytics/collectors/errors.js +43 -0
- package/dist/analytics/collectors/errors.js.map +1 -0
- package/dist/analytics/collectors/forms.d.ts +5 -0
- package/dist/analytics/collectors/forms.d.ts.map +1 -0
- package/dist/analytics/collectors/forms.js +55 -0
- package/dist/analytics/collectors/forms.js.map +1 -0
- package/dist/analytics/collectors/pageview.d.ts +15 -0
- package/dist/analytics/collectors/pageview.d.ts.map +1 -0
- package/dist/analytics/collectors/pageview.js +64 -0
- package/dist/analytics/collectors/pageview.js.map +1 -0
- package/dist/analytics/collectors/scroll.d.ts +17 -0
- package/dist/analytics/collectors/scroll.d.ts.map +1 -0
- package/dist/analytics/collectors/scroll.js +93 -0
- package/dist/analytics/collectors/scroll.js.map +1 -0
- package/dist/analytics/collectors/spa.d.ts +10 -0
- package/dist/analytics/collectors/spa.d.ts.map +1 -0
- package/dist/analytics/collectors/spa.js +53 -0
- package/dist/analytics/collectors/spa.js.map +1 -0
- package/dist/analytics/collectors/visibility.d.ts +18 -0
- package/dist/analytics/collectors/visibility.d.ts.map +1 -0
- package/dist/analytics/collectors/visibility.js +81 -0
- package/dist/analytics/collectors/visibility.js.map +1 -0
- package/dist/analytics/collectors/webvitals.d.ts +6 -0
- package/dist/analytics/collectors/webvitals.d.ts.map +1 -0
- package/dist/analytics/collectors/webvitals.js +111 -0
- package/dist/analytics/collectors/webvitals.js.map +1 -0
- package/dist/analytics/events.d.ts +18 -0
- package/dist/analytics/events.d.ts.map +1 -0
- package/dist/analytics/events.js +126 -0
- package/dist/analytics/events.js.map +1 -0
- package/dist/analytics/index.d.ts +12 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +12 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/offline.d.ts +19 -0
- package/dist/analytics/offline.d.ts.map +1 -0
- package/dist/analytics/offline.js +145 -0
- package/dist/analytics/offline.js.map +1 -0
- package/dist/analytics/types.d.ts +113 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +2 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/analytics/utils/storage.d.ts +13 -0
- package/dist/analytics/utils/storage.d.ts.map +1 -0
- package/dist/analytics/utils/storage.js +63 -0
- package/dist/analytics/utils/storage.js.map +1 -0
- package/dist/analytics/utils/utm.d.ts +12 -0
- package/dist/analytics/utils/utm.d.ts.map +1 -0
- package/dist/analytics/utils/utm.js +27 -0
- package/dist/analytics/utils/utm.js.map +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +93 -15
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +51 -5
- package/dist/client/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/analytics/beacon.ts +203 -0
- package/src/analytics/collectors/clicks.ts +100 -0
- package/src/analytics/collectors/errors.ts +49 -0
- package/src/analytics/collectors/forms.ts +64 -0
- package/src/analytics/collectors/pageview.ts +76 -0
- package/src/analytics/collectors/scroll.ts +112 -0
- package/src/analytics/collectors/spa.ts +60 -0
- package/src/analytics/collectors/visibility.ts +94 -0
- package/src/analytics/collectors/webvitals.ts +129 -0
- package/src/analytics/events.ts +144 -0
- package/src/analytics/index.ts +21 -0
- package/src/analytics/offline.ts +163 -0
- package/src/analytics/types.ts +139 -0
- package/src/analytics/utils/storage.ts +64 -0
- package/src/analytics/utils/utm.ts +36 -0
- package/src/client/index.ts +109 -15
- package/src/client/types.ts +104 -17
- package/src/index.ts +18 -0
package/dist/client/types.d.ts
CHANGED
|
@@ -86,26 +86,61 @@ export interface StreamClient {
|
|
|
86
86
|
*/
|
|
87
87
|
cancel(): Promise<void>;
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Options object for endpoints without path params (optional query support).
|
|
91
|
+
*/
|
|
92
|
+
export interface EndpointOptionsWithQuery<Input = unknown, Query = Record<string, string>> {
|
|
93
|
+
input?: Input;
|
|
94
|
+
query?: Query;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Additional options that can be passed after positional path params.
|
|
98
|
+
*/
|
|
99
|
+
export interface EndpointExtraOptions<Input = unknown, Query = Record<string, string>> {
|
|
100
|
+
input?: Input;
|
|
101
|
+
query?: Query;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Convert a path params object to a tuple of its value types.
|
|
105
|
+
* Used for positional argument typing.
|
|
106
|
+
* Note: For proper ordering, we rely on the generated PathParamsTuple type.
|
|
107
|
+
*/
|
|
108
|
+
export type PathParamsToTuple<P> = P extends readonly [infer First, ...infer Rest] ? [First, ...PathParamsToTuple<Rest>] : P extends readonly [] ? [] : string[];
|
|
89
109
|
/**
|
|
90
110
|
* API endpoint - callable function for regular HTTP calls.
|
|
111
|
+
* - Without path params: accepts input directly OR options object with query
|
|
112
|
+
* - With path params: accepts positional arguments followed by optional options object
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // No path params
|
|
116
|
+
* client.hello.post({ name: 'World' })
|
|
117
|
+
*
|
|
118
|
+
* // Single path param
|
|
119
|
+
* client.users.userId.get('123')
|
|
120
|
+
*
|
|
121
|
+
* // Multiple path params
|
|
122
|
+
* client.orgs.orgId.members.memberId.get('org-1', 'user-2')
|
|
123
|
+
*
|
|
124
|
+
* // With additional options
|
|
125
|
+
* client.users.userId.get('123', { query: { include: 'posts' } })
|
|
91
126
|
*/
|
|
92
|
-
export type APIEndpoint<Input = unknown, Output = unknown> = (
|
|
127
|
+
export type APIEndpoint<Input = unknown, Output = unknown, PathParams = never, PathParamsTuple extends unknown[] = string[]> = [PathParams] extends [never] ? (inputOrOptions?: Input | EndpointOptionsWithQuery<Input>) => Promise<Output> : (...args: [...PathParamsTuple, options?: EndpointExtraOptions<Input>]) => Promise<Output>;
|
|
93
128
|
/**
|
|
94
129
|
* WebSocket endpoint - callable function that returns WebSocket client.
|
|
95
130
|
*/
|
|
96
|
-
export type WebSocketEndpoint<Input = unknown, _Output = unknown> = (
|
|
131
|
+
export type WebSocketEndpoint<Input = unknown, _Output = unknown, PathParams = never, PathParamsTuple extends unknown[] = string[]> = [PathParams] extends [never] ? (inputOrOptions?: Input | EndpointOptionsWithQuery<Input>) => WebSocketClient : (...args: [...PathParamsTuple, options?: EndpointExtraOptions<Input>]) => WebSocketClient;
|
|
97
132
|
/**
|
|
98
133
|
* Server-Sent Events endpoint - callable function that returns EventStream client.
|
|
99
134
|
*/
|
|
100
|
-
export type SSEEndpoint<Input = unknown, _Output = unknown> = (
|
|
135
|
+
export type SSEEndpoint<Input = unknown, _Output = unknown, PathParams = never, PathParamsTuple extends unknown[] = string[]> = [PathParams] extends [never] ? (inputOrOptions?: Input | EndpointOptionsWithQuery<Input>) => EventStreamClient : (...args: [...PathParamsTuple, options?: EndpointExtraOptions<Input>]) => EventStreamClient;
|
|
101
136
|
/**
|
|
102
137
|
* Streaming endpoint - callable function that returns Stream client.
|
|
103
138
|
*/
|
|
104
|
-
export type StreamEndpoint<Input = unknown, _Output = unknown> = (
|
|
139
|
+
export type StreamEndpoint<Input = unknown, _Output = unknown, PathParams = never, PathParamsTuple extends unknown[] = string[]> = [PathParams] extends [never] ? (inputOrOptions?: Input | EndpointOptionsWithQuery<Input>) => StreamClient : (...args: [...PathParamsTuple, options?: EndpointExtraOptions<Input>]) => StreamClient;
|
|
105
140
|
/**
|
|
106
141
|
* Route endpoint - discriminated union based on route type.
|
|
107
142
|
*/
|
|
108
|
-
export type RouteEndpoint<Input = unknown, Output = unknown, Type extends string = 'api'> = Type extends 'websocket' ? WebSocketEndpoint<Input, Output> : Type extends 'sse' ? SSEEndpoint<Input, Output> : Type extends 'stream' ? StreamEndpoint<Input, Output> : APIEndpoint<Input, Output>;
|
|
143
|
+
export type RouteEndpoint<Input = unknown, Output = unknown, Type extends string = 'api', PathParams = never, PathParamsTuple extends unknown[] = []> = Type extends 'websocket' ? WebSocketEndpoint<Input, Output, PathParams, PathParamsTuple> : Type extends 'sse' ? SSEEndpoint<Input, Output, PathParams, PathParamsTuple> : Type extends 'stream' ? StreamEndpoint<Input, Output, PathParams, PathParamsTuple> : APIEndpoint<Input, Output, PathParams, PathParamsTuple>;
|
|
109
144
|
/**
|
|
110
145
|
* Recursively build the client proxy type from a RouteRegistry.
|
|
111
146
|
*/
|
|
@@ -114,6 +149,17 @@ export type Client<R> = {
|
|
|
114
149
|
input: infer I;
|
|
115
150
|
output: infer O;
|
|
116
151
|
type: infer T;
|
|
152
|
+
params: infer P;
|
|
153
|
+
paramsTuple: infer PT;
|
|
154
|
+
} ? PT extends unknown[] ? RouteEndpoint<I, O, T extends string ? T : 'api', P, PT> : RouteEndpoint<I, O, T extends string ? T : 'api', P> : R[K] extends {
|
|
155
|
+
input: infer I;
|
|
156
|
+
output: infer O;
|
|
157
|
+
type: infer T;
|
|
158
|
+
params: infer P;
|
|
159
|
+
} ? RouteEndpoint<I, O, T extends string ? T : 'api', P> : R[K] extends {
|
|
160
|
+
input: infer I;
|
|
161
|
+
output: infer O;
|
|
162
|
+
type: infer T;
|
|
117
163
|
} ? RouteEndpoint<I, O, T extends string ? T : 'api'> : R[K] extends {
|
|
118
164
|
input: infer I;
|
|
119
165
|
output: infer O;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAElE;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;QACzD,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC1D,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;QAC9D,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC1D,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAElE;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;QACzD,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC1D,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;QAC9D,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B;;OAEG;IACH,EAAE,EAAE;QACH,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC1D,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IAEF;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IACxF,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IACpF,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GAC/E,CAAC,KAAK,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,GACnC,CAAC,SAAS,SAAS,EAAE,GACpB,EAAE,GACF,MAAM,EAAE,CAAC;AAEb;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,WAAW,CACtB,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,OAAO,EAChB,UAAU,GAAG,KAAK,EAClB,eAAe,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,IACzC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,CAAC,cAAc,CAAC,EAAE,KAAK,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAC7E,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE7F;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAC5B,KAAK,GAAG,OAAO,EACf,OAAO,GAAG,OAAO,EACjB,UAAU,GAAG,KAAK,EAClB,eAAe,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,IACzC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,CAAC,cAAc,CAAC,EAAE,KAAK,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,eAAe,GAC7E,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,KAAK,eAAe,CAAC;AAE7F;;GAEG;AACH,MAAM,MAAM,WAAW,CACtB,KAAK,GAAG,OAAO,EACf,OAAO,GAAG,OAAO,EACjB,UAAU,GAAG,KAAK,EAClB,eAAe,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,IACzC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,CAAC,cAAc,CAAC,EAAE,KAAK,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,iBAAiB,GAC/E,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,KAAK,iBAAiB,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,cAAc,CACzB,KAAK,GAAG,OAAO,EACf,OAAO,GAAG,OAAO,EACjB,UAAU,GAAG,KAAK,EAClB,eAAe,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,IACzC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,CAAC,cAAc,CAAC,EAAE,KAAK,GAAG,wBAAwB,CAAC,KAAK,CAAC,KAAK,YAAY,GAC1E,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,KAAK,YAAY,CAAC;AAE1F;;GAEG;AACH,MAAM,MAAM,aAAa,CACxB,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,OAAO,EAChB,IAAI,SAAS,MAAM,GAAG,KAAK,EAC3B,UAAU,GAAG,KAAK,EAClB,eAAe,SAAS,OAAO,EAAE,GAAG,EAAE,IACnC,IAAI,SAAS,WAAW,GACzB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,GAC7D,IAAI,SAAS,KAAK,GACjB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,GACvD,IAAI,SAAS,QAAQ,GACpB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,GAC1D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;KACtB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5B,KAAK,EAAE,MAAM,CAAC,CAAC;QACf,MAAM,EAAE,MAAM,CAAC,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC,CAAC;QACd,MAAM,EAAE,MAAM,CAAC,CAAC;QAChB,WAAW,EAAE,MAAM,EAAE,CAAC;KACtB,GACE,EAAE,SAAS,OAAO,EAAE,GACnB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GACxD,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,GACrD,CAAC,CAAC,CAAC,CAAC,SAAS;QACZ,KAAK,EAAE,MAAM,CAAC,CAAC;QACf,MAAM,EAAE,MAAM,CAAC,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC,CAAC;QACd,MAAM,EAAE,MAAM,CAAC,CAAC;KACf,GACD,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,GACpD,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,CAAA;KAAE,GAC9D,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,GACjD,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC/C,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,GAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAClB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACZ,KAAK;CACZ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export { WebSocketManager, type MessageHandler as WebSocketMessageHandler, type
|
|
|
8
8
|
export { EventStreamManager, type MessageHandler as EventStreamMessageHandler, type EventStreamCallbacks, type EventStreamManagerOptions, type EventStreamManagerState, } from './eventstream-manager';
|
|
9
9
|
export { createClient } from './client/index';
|
|
10
10
|
export type { Client, ClientOptions, RouteEndpoint, WebSocketClient, EventStreamClient, StreamClient, EventHandler, } from './client/types';
|
|
11
|
+
export { getAnalytics, track, initBeacon, trackPageview, createBaseEvent, getVisitorId, isOptedOut, setOptOut, getUTMParams, type AnalyticsClient, type AnalyticsEvent, type AnalyticsEventType, type AnalyticsBatchPayload, type AnalyticsPageConfig, } from './analytics';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EACN,gBAAgB,EAChB,KAAK,cAAc,IAAI,uBAAuB,EAC9C,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,EAClB,KAAK,cAAc,IAAI,yBAAyB,EAChD,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,GAC5B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACX,MAAM,EACN,aAAa,EACb,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,GACZ,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EACN,gBAAgB,EAChB,KAAK,cAAc,IAAI,uBAAuB,EAC9C,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,EAClB,KAAK,cAAc,IAAI,yBAAyB,EAChD,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,GAC5B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACX,MAAM,EACN,aAAa,EACb,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACN,YAAY,EACZ,KAAK,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,UAAU,EACV,SAAS,EACT,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACxB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,4 +7,6 @@ export { WebSocketManager, } from './websocket-manager';
|
|
|
7
7
|
export { EventStreamManager, } from './eventstream-manager';
|
|
8
8
|
// Export client implementation (local to this package)
|
|
9
9
|
export { createClient } from './client/index';
|
|
10
|
+
// Export analytics
|
|
11
|
+
export { getAnalytics, track, initBeacon, trackPageview, createBaseEvent, getVisitorId, isOptedOut, setOptOut, getUTMParams, } from './analytics';
|
|
10
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAgD,MAAM,aAAa,CAAC;AAEnG,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EACN,gBAAgB,GAKhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,GAKlB,MAAM,uBAAuB,CAAC;AAE/B,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAgD,MAAM,aAAa,CAAC;AAEnG,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EACN,gBAAgB,GAKhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,GAKlB,MAAM,uBAAuB,CAAC;AAE/B,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAW9C,mBAAmB;AACnB,OAAO,EACN,YAAY,EACZ,KAAK,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,UAAU,EACV,SAAS,EACT,YAAY,GAMZ,MAAM,aAAa,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentuity/frontend",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.112",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Agentuity employees and contributors",
|
|
6
6
|
"type": "module",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"prepublishOnly": "bun run clean && bun run build"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@agentuity/core": "0.0.
|
|
29
|
+
"@agentuity/core": "0.0.112"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@agentuity/test-utils": "0.0.
|
|
32
|
+
"@agentuity/test-utils": "0.0.112",
|
|
33
33
|
"@types/bun": "latest",
|
|
34
34
|
"bun-types": "latest",
|
|
35
35
|
"typescript": "^5.9.0"
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { AnalyticsPageConfig, AnalyticsClient } from './types';
|
|
2
|
+
import { initEventQueue, queueEvent, flushEvents } from './events';
|
|
3
|
+
import { initPageviewTracking, createBaseEvent, trackPageview } from './collectors/pageview';
|
|
4
|
+
import { initSPATracking } from './collectors/spa';
|
|
5
|
+
import { initClickTracking, initOutboundLinkTracking } from './collectors/clicks';
|
|
6
|
+
import { initScrollTracking } from './collectors/scroll';
|
|
7
|
+
import { initErrorTracking } from './collectors/errors';
|
|
8
|
+
import { initVisibilityTracking } from './collectors/visibility';
|
|
9
|
+
import { initFormTracking } from './collectors/forms';
|
|
10
|
+
import { initWebVitalsTracking } from './collectors/webvitals';
|
|
11
|
+
import { isOptedOut, setOptOut } from './utils/storage';
|
|
12
|
+
import { initOfflineSupport, getAndClearOfflineEvents } from './offline';
|
|
13
|
+
|
|
14
|
+
let initialized = false;
|
|
15
|
+
let trackingStarted = false;
|
|
16
|
+
let analyticsEnabled = true;
|
|
17
|
+
let consentRequired = false;
|
|
18
|
+
let consentGiven = false;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if analytics should run
|
|
22
|
+
*/
|
|
23
|
+
function shouldTrack(): boolean {
|
|
24
|
+
if (!analyticsEnabled) return false;
|
|
25
|
+
if (isOptedOut()) return false;
|
|
26
|
+
if (consentRequired && !consentGiven) return false;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the analytics beacon
|
|
32
|
+
* Called automatically when the script loads
|
|
33
|
+
*/
|
|
34
|
+
export function initBeacon(): void {
|
|
35
|
+
if (initialized) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const config = window.__AGENTUITY_ANALYTICS__;
|
|
40
|
+
if (!config || !config.enabled) {
|
|
41
|
+
analyticsEnabled = false;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
initialized = true;
|
|
46
|
+
consentRequired = config.requireConsent ?? false;
|
|
47
|
+
|
|
48
|
+
// If consent is required and not given, wait for optIn
|
|
49
|
+
if (consentRequired && !consentGiven) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
startTracking(config);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Start all tracking based on config
|
|
58
|
+
*/
|
|
59
|
+
function startTracking(config: AnalyticsPageConfig): void {
|
|
60
|
+
if (trackingStarted) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
trackingStarted = true;
|
|
64
|
+
|
|
65
|
+
// Initialize event queue
|
|
66
|
+
initEventQueue(config);
|
|
67
|
+
|
|
68
|
+
// Initialize offline support
|
|
69
|
+
initOfflineSupport(async () => {
|
|
70
|
+
// Flush offline events when coming back online
|
|
71
|
+
const offlineEvents = await getAndClearOfflineEvents();
|
|
72
|
+
for (const event of offlineEvents) {
|
|
73
|
+
queueEvent(event);
|
|
74
|
+
}
|
|
75
|
+
flushEvents();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Always track pageviews
|
|
79
|
+
initPageviewTracking();
|
|
80
|
+
|
|
81
|
+
// Initialize visibility tracking (for time on page)
|
|
82
|
+
initVisibilityTracking();
|
|
83
|
+
|
|
84
|
+
// Conditional tracking based on config (all default to true except requireConsent)
|
|
85
|
+
if (config.trackSPANavigation !== false) {
|
|
86
|
+
initSPATracking();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (config.trackClicks !== false) {
|
|
90
|
+
initClickTracking();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (config.trackOutboundLinks !== false) {
|
|
94
|
+
initOutboundLinkTracking();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (config.trackScroll !== false) {
|
|
98
|
+
initScrollTracking();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (config.trackErrors !== false) {
|
|
102
|
+
initErrorTracking();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (config.trackForms !== false) {
|
|
106
|
+
initFormTracking();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (config.trackWebVitals !== false) {
|
|
110
|
+
initWebVitalsTracking();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create the analytics client API
|
|
116
|
+
*/
|
|
117
|
+
function createClient(): AnalyticsClient {
|
|
118
|
+
return {
|
|
119
|
+
track(eventName: string, properties?: Record<string, unknown>): void {
|
|
120
|
+
if (!shouldTrack()) return;
|
|
121
|
+
|
|
122
|
+
const event = createBaseEvent('custom');
|
|
123
|
+
event.event_name = eventName;
|
|
124
|
+
if (properties) {
|
|
125
|
+
event.event_data = properties;
|
|
126
|
+
}
|
|
127
|
+
queueEvent(event);
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
identify(userId: string, traits?: Record<string, unknown>): void {
|
|
131
|
+
if (!shouldTrack()) return;
|
|
132
|
+
|
|
133
|
+
const event = createBaseEvent('custom');
|
|
134
|
+
event.event_name = 'identify';
|
|
135
|
+
event.event_data = {
|
|
136
|
+
user_id: userId,
|
|
137
|
+
...traits,
|
|
138
|
+
};
|
|
139
|
+
queueEvent(event);
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
pageview(path?: string): void {
|
|
143
|
+
if (!shouldTrack()) return;
|
|
144
|
+
trackPageview(path);
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
async flush(): Promise<void> {
|
|
148
|
+
flushEvents();
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
optOut(): void {
|
|
152
|
+
setOptOut(true);
|
|
153
|
+
analyticsEnabled = false;
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
optIn(): void {
|
|
157
|
+
setOptOut(false);
|
|
158
|
+
analyticsEnabled = true;
|
|
159
|
+
consentGiven = true;
|
|
160
|
+
|
|
161
|
+
// If consent was required and now given, start tracking
|
|
162
|
+
if (consentRequired && !trackingStarted) {
|
|
163
|
+
const config = window.__AGENTUITY_ANALYTICS__;
|
|
164
|
+
if (config) {
|
|
165
|
+
startTracking(config);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
isEnabled(): boolean {
|
|
171
|
+
return shouldTrack();
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Singleton client instance
|
|
177
|
+
let clientInstance: AnalyticsClient | null = null;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get the analytics client instance
|
|
181
|
+
*/
|
|
182
|
+
export function getAnalytics(): AnalyticsClient {
|
|
183
|
+
if (!clientInstance) {
|
|
184
|
+
clientInstance = createClient();
|
|
185
|
+
}
|
|
186
|
+
return clientInstance;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Convenience function to track a custom event
|
|
191
|
+
*/
|
|
192
|
+
export function track(eventName: string, properties?: Record<string, unknown>): void {
|
|
193
|
+
getAnalytics().track(eventName, properties);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Auto-initialize when script loads
|
|
197
|
+
if (typeof window !== 'undefined') {
|
|
198
|
+
if (document.readyState === 'loading') {
|
|
199
|
+
document.addEventListener('DOMContentLoaded', initBeacon);
|
|
200
|
+
} else {
|
|
201
|
+
initBeacon();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createBaseEvent } from './pageview';
|
|
2
|
+
import { queueEvent } from '../events';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initialize click tracking
|
|
6
|
+
* Tracks clicks on elements with data-analytics attribute
|
|
7
|
+
*/
|
|
8
|
+
export function initClickTracking(): void {
|
|
9
|
+
if (typeof document === 'undefined') {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
document.addEventListener(
|
|
14
|
+
'click',
|
|
15
|
+
(e) => {
|
|
16
|
+
const target = e.target as HTMLElement | null;
|
|
17
|
+
if (!target) return;
|
|
18
|
+
|
|
19
|
+
// Find closest element with data-analytics attribute
|
|
20
|
+
const analyticsElement = target.closest('[data-analytics]');
|
|
21
|
+
if (!analyticsElement) return;
|
|
22
|
+
|
|
23
|
+
const eventName = analyticsElement.getAttribute('data-analytics');
|
|
24
|
+
if (!eventName) return;
|
|
25
|
+
|
|
26
|
+
const event = createBaseEvent('click');
|
|
27
|
+
event.event_name = eventName;
|
|
28
|
+
|
|
29
|
+
// Collect additional data attributes
|
|
30
|
+
const eventData: Record<string, unknown> = {};
|
|
31
|
+
for (const attr of Array.from(analyticsElement.attributes)) {
|
|
32
|
+
if (attr.name.startsWith('data-analytics-')) {
|
|
33
|
+
const key = attr.name.replace('data-analytics-', '');
|
|
34
|
+
eventData[key] = attr.value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Add element info
|
|
39
|
+
eventData.tag = analyticsElement.tagName.toLowerCase();
|
|
40
|
+
if (analyticsElement.id) {
|
|
41
|
+
eventData.id = analyticsElement.id;
|
|
42
|
+
}
|
|
43
|
+
const text = (analyticsElement as HTMLElement).innerText?.slice(0, 100);
|
|
44
|
+
if (text) {
|
|
45
|
+
eventData.text = text;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (Object.keys(eventData).length > 0) {
|
|
49
|
+
event.event_data = eventData;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
queueEvent(event);
|
|
53
|
+
},
|
|
54
|
+
{ capture: true, passive: true }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Initialize outbound link tracking
|
|
60
|
+
*/
|
|
61
|
+
export function initOutboundLinkTracking(): void {
|
|
62
|
+
if (typeof document === 'undefined') {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
document.addEventListener(
|
|
67
|
+
'click',
|
|
68
|
+
(e) => {
|
|
69
|
+
const target = e.target as HTMLElement | null;
|
|
70
|
+
if (!target) return;
|
|
71
|
+
|
|
72
|
+
const link = target.closest('a');
|
|
73
|
+
if (!link) return;
|
|
74
|
+
|
|
75
|
+
const href = link.href;
|
|
76
|
+
if (!href) return;
|
|
77
|
+
|
|
78
|
+
// Check if it's an outbound link
|
|
79
|
+
try {
|
|
80
|
+
const url = new URL(href, window.location.origin);
|
|
81
|
+
if (url.hostname === window.location.hostname) {
|
|
82
|
+
return; // Same domain, not outbound
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const event = createBaseEvent('outbound_link');
|
|
86
|
+
event.event_name = 'outbound_link';
|
|
87
|
+
event.event_data = {
|
|
88
|
+
href,
|
|
89
|
+
hostname: url.hostname,
|
|
90
|
+
text: link.innerText?.slice(0, 100) || '',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
queueEvent(event);
|
|
94
|
+
} catch {
|
|
95
|
+
// Invalid URL, ignore
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{ capture: true, passive: true }
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createBaseEvent } from './pageview';
|
|
2
|
+
import { queueEvent } from '../events';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initialize JavaScript error tracking
|
|
6
|
+
*/
|
|
7
|
+
export function initErrorTracking(): void {
|
|
8
|
+
if (typeof window === 'undefined') {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Handle uncaught errors
|
|
13
|
+
window.addEventListener('error', (e) => {
|
|
14
|
+
const event = createBaseEvent('error');
|
|
15
|
+
event.event_name = 'js_error';
|
|
16
|
+
event.event_data = {
|
|
17
|
+
message: e.message || 'Unknown error',
|
|
18
|
+
filename: e.filename || '',
|
|
19
|
+
lineno: e.lineno || 0,
|
|
20
|
+
colno: e.colno || 0,
|
|
21
|
+
stack: e.error?.stack?.slice(0, 1000) || '',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
queueEvent(event);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Handle unhandled promise rejections
|
|
28
|
+
window.addEventListener('unhandledrejection', (e) => {
|
|
29
|
+
const event = createBaseEvent('error');
|
|
30
|
+
event.event_name = 'unhandled_rejection';
|
|
31
|
+
|
|
32
|
+
let message = 'Unhandled Promise Rejection';
|
|
33
|
+
let stack = '';
|
|
34
|
+
|
|
35
|
+
if (e.reason instanceof Error) {
|
|
36
|
+
message = e.reason.message;
|
|
37
|
+
stack = e.reason.stack?.slice(0, 1000) || '';
|
|
38
|
+
} else if (typeof e.reason === 'string') {
|
|
39
|
+
message = e.reason;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
event.event_data = {
|
|
43
|
+
message,
|
|
44
|
+
stack,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
queueEvent(event);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createBaseEvent } from './pageview';
|
|
2
|
+
import { queueEvent } from '../events';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initialize form submission tracking
|
|
6
|
+
*/
|
|
7
|
+
export function initFormTracking(): void {
|
|
8
|
+
if (typeof document === 'undefined') {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
document.addEventListener(
|
|
13
|
+
'submit',
|
|
14
|
+
(e) => {
|
|
15
|
+
const form = e.target as HTMLFormElement | null;
|
|
16
|
+
if (!form || form.tagName !== 'FORM') {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const event = createBaseEvent('form_submit');
|
|
21
|
+
event.event_name = 'form_submit';
|
|
22
|
+
|
|
23
|
+
const eventData: Record<string, unknown> = {};
|
|
24
|
+
|
|
25
|
+
// Form identification
|
|
26
|
+
if (form.id) {
|
|
27
|
+
eventData.form_id = form.id;
|
|
28
|
+
}
|
|
29
|
+
if (form.name) {
|
|
30
|
+
eventData.form_name = form.name;
|
|
31
|
+
}
|
|
32
|
+
if (form.action) {
|
|
33
|
+
eventData.form_action = form.action;
|
|
34
|
+
}
|
|
35
|
+
eventData.form_method = form.method || 'get';
|
|
36
|
+
|
|
37
|
+
// Count form fields (don't capture values for privacy)
|
|
38
|
+
const inputs = form.querySelectorAll('input, select, textarea');
|
|
39
|
+
eventData.field_count = inputs.length;
|
|
40
|
+
|
|
41
|
+
// Check for common form types
|
|
42
|
+
const hasEmail = form.querySelector('input[type="email"]') !== null;
|
|
43
|
+
const hasPassword = form.querySelector('input[type="password"]') !== null;
|
|
44
|
+
const hasSearch = form.querySelector('input[type="search"]') !== null;
|
|
45
|
+
|
|
46
|
+
if (hasEmail && hasPassword) {
|
|
47
|
+
eventData.form_type = 'auth';
|
|
48
|
+
} else if (hasEmail) {
|
|
49
|
+
eventData.form_type = 'email';
|
|
50
|
+
} else if (hasSearch) {
|
|
51
|
+
eventData.form_type = 'search';
|
|
52
|
+
} else if (hasPassword) {
|
|
53
|
+
eventData.form_type = 'password';
|
|
54
|
+
} else {
|
|
55
|
+
eventData.form_type = 'other';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
event.event_data = eventData;
|
|
59
|
+
|
|
60
|
+
queueEvent(event);
|
|
61
|
+
},
|
|
62
|
+
{ capture: true }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { AnalyticsEvent } from '../types';
|
|
2
|
+
import { queueEvent } from '../events';
|
|
3
|
+
import { getUTMParams } from '../utils/utm';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create a base event with common properties
|
|
7
|
+
*/
|
|
8
|
+
export function createBaseEvent(eventType: AnalyticsEvent['event_type']): AnalyticsEvent {
|
|
9
|
+
const utm = getUTMParams();
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
id: crypto.randomUUID
|
|
13
|
+
? crypto.randomUUID()
|
|
14
|
+
: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
timezone_offset: new Date().getTimezoneOffset(),
|
|
17
|
+
|
|
18
|
+
event_type: eventType,
|
|
19
|
+
|
|
20
|
+
url: window.location.href,
|
|
21
|
+
path: window.location.pathname,
|
|
22
|
+
referrer: document.referrer || '',
|
|
23
|
+
title: document.title || '',
|
|
24
|
+
|
|
25
|
+
screen_width: window.screen?.width || 0,
|
|
26
|
+
screen_height: window.screen?.height || 0,
|
|
27
|
+
viewport_width: window.innerWidth || 0,
|
|
28
|
+
viewport_height: window.innerHeight || 0,
|
|
29
|
+
device_pixel_ratio: window.devicePixelRatio || 1,
|
|
30
|
+
user_agent: navigator.userAgent || '',
|
|
31
|
+
language: navigator.language || '',
|
|
32
|
+
|
|
33
|
+
...utm,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Track a pageview event
|
|
39
|
+
*/
|
|
40
|
+
export function trackPageview(customPath?: string): void {
|
|
41
|
+
const event = createBaseEvent('pageview');
|
|
42
|
+
|
|
43
|
+
if (customPath) {
|
|
44
|
+
event.path = customPath;
|
|
45
|
+
event.url = window.location.origin + customPath;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Add performance timing if available
|
|
49
|
+
if (typeof performance !== 'undefined') {
|
|
50
|
+
const timing = performance.getEntriesByType('navigation')[0] as
|
|
51
|
+
| PerformanceNavigationTiming
|
|
52
|
+
| undefined;
|
|
53
|
+
if (timing) {
|
|
54
|
+
event.load_time = Math.round(timing.loadEventEnd - timing.startTime);
|
|
55
|
+
event.dom_ready = Math.round(timing.domContentLoadedEventEnd - timing.startTime);
|
|
56
|
+
event.ttfb = Math.round(timing.responseStart - timing.requestStart);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
queueEvent(event);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Initialize pageview tracking
|
|
65
|
+
* Tracks initial pageview when called
|
|
66
|
+
*/
|
|
67
|
+
export function initPageviewTracking(): void {
|
|
68
|
+
// Track initial pageview after DOM is ready
|
|
69
|
+
if (document.readyState === 'complete') {
|
|
70
|
+
trackPageview();
|
|
71
|
+
} else {
|
|
72
|
+
window.addEventListener('load', () => {
|
|
73
|
+
trackPageview();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|