@molecule/app-analytics 1.0.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/LICENSE +115 -0
- package/dist/auto-tracking.d.ts +156 -0
- package/dist/auto-tracking.d.ts.map +1 -0
- package/dist/auto-tracking.js +196 -0
- package/dist/auto-tracking.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +69 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +92 -0
- package/dist/provider.js.map +1 -0
- package/dist/types.d.ts +103 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work.
|
|
38
|
+
|
|
39
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
|
+
form, that is based on (or derived from) the Work and for which the
|
|
41
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
42
|
+
represent, as a whole, an original work of authorship.
|
|
43
|
+
|
|
44
|
+
"Contribution" shall mean any work of authorship, including the
|
|
45
|
+
original version of the Work and any modifications or additions
|
|
46
|
+
to that Work, that is intentionally submitted to the Licensor for
|
|
47
|
+
inclusion in the Work by the copyright owner or by an individual or
|
|
48
|
+
Legal Entity authorized to submit on behalf of the copyright owner.
|
|
49
|
+
|
|
50
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
51
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
52
|
+
subsequently incorporated within the Work.
|
|
53
|
+
|
|
54
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
55
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
56
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
57
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
58
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
59
|
+
Work and such Derivative Works in Source or Object form.
|
|
60
|
+
|
|
61
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
62
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
63
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
64
|
+
patent license to make, have made, use, offer to sell, sell, import,
|
|
65
|
+
and otherwise transfer the Work.
|
|
66
|
+
|
|
67
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
68
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
69
|
+
modifications, and in Source or Object form, provided that You
|
|
70
|
+
meet the following conditions:
|
|
71
|
+
|
|
72
|
+
(a) You must give any other recipients of the Work or
|
|
73
|
+
Derivative Works a copy of this License; and
|
|
74
|
+
|
|
75
|
+
(b) You must cause any modified files to carry prominent notices
|
|
76
|
+
stating that You changed the files; and
|
|
77
|
+
|
|
78
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
79
|
+
that You distribute, all copyright, patent, trademark, and
|
|
80
|
+
attribution notices from the Source form of the Work,
|
|
81
|
+
excluding those notices that do not pertain to any part of
|
|
82
|
+
the Derivative Works; and
|
|
83
|
+
|
|
84
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
85
|
+
distribution, then any Derivative Works that You distribute must
|
|
86
|
+
include a readable copy of the attribution notices contained
|
|
87
|
+
within such NOTICE file.
|
|
88
|
+
|
|
89
|
+
5. Submission of Contributions.
|
|
90
|
+
|
|
91
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
92
|
+
names, trademarks, service marks, or product names of the Licensor.
|
|
93
|
+
|
|
94
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
95
|
+
agreed to in writing, Licensor provides the Work on an "AS IS" BASIS,
|
|
96
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
|
|
97
|
+
|
|
98
|
+
8. Limitation of Liability. In no event and under no legal theory shall
|
|
99
|
+
any Contributor be liable to You for damages.
|
|
100
|
+
|
|
101
|
+
9. Accepting Warranty or Additional Liability.
|
|
102
|
+
|
|
103
|
+
Copyright 2026 Molecule Dev, Inc.
|
|
104
|
+
|
|
105
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
106
|
+
you may not use this file except in compliance with the License.
|
|
107
|
+
You may obtain a copy of the License at
|
|
108
|
+
|
|
109
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
110
|
+
|
|
111
|
+
Unless required by applicable law or agreed to in writing, software
|
|
112
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
113
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
114
|
+
See the License for the specific language governing permissions and
|
|
115
|
+
limitations under the License.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automatic analytics tracking for auth, routing, HTTP, and mobile events.
|
|
3
|
+
*
|
|
4
|
+
* Uses minimal interfaces so there's no hard dependency on
|
|
5
|
+
* `@molecule/app-auth`, `@molecule/app-routing`, `@molecule/app-http`,
|
|
6
|
+
* `@molecule/app-lifecycle`, or `@molecule/app-push`.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Minimal auth event shape (mirrors `@molecule/app-auth` AuthEvent).
|
|
12
|
+
*/
|
|
13
|
+
interface AuthEvent {
|
|
14
|
+
type: 'login' | 'logout' | 'register' | 'refresh' | 'error';
|
|
15
|
+
user?: {
|
|
16
|
+
id: string;
|
|
17
|
+
email?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
};
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Minimal auth client interface for auto-tracking.
|
|
24
|
+
*/
|
|
25
|
+
interface AuthClientLike {
|
|
26
|
+
addEventListener(listener: (event: AuthEvent) => void): () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Minimal route location shape (mirrors `@molecule/app-routing` RouteLocation).
|
|
30
|
+
*/
|
|
31
|
+
interface RouteLocationLike {
|
|
32
|
+
pathname: string;
|
|
33
|
+
search: string;
|
|
34
|
+
hash: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Minimal router interface for auto-tracking.
|
|
38
|
+
*/
|
|
39
|
+
interface RouterLike {
|
|
40
|
+
subscribe(listener: (location: RouteLocationLike, action: string) => void): () => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Minimal HTTP error shape.
|
|
44
|
+
*/
|
|
45
|
+
interface HttpErrorLike {
|
|
46
|
+
message: string;
|
|
47
|
+
status: number;
|
|
48
|
+
config?: {
|
|
49
|
+
method?: string;
|
|
50
|
+
url?: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Minimal HTTP client interface for auto-tracking.
|
|
55
|
+
*/
|
|
56
|
+
interface HttpClientLike {
|
|
57
|
+
addErrorInterceptor(interceptor: (error: HttpErrorLike) => HttpErrorLike): () => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Minimal app state change shape (mirrors `@molecule/app-lifecycle` AppStateChange).
|
|
61
|
+
*/
|
|
62
|
+
interface AppStateChangeLike {
|
|
63
|
+
current: string;
|
|
64
|
+
previous: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Minimal lifecycle client interface for auto-tracking app foreground/background
|
|
68
|
+
* transitions and deep link opens.
|
|
69
|
+
*/
|
|
70
|
+
interface LifecycleClientLike {
|
|
71
|
+
onAppStateChange(listener: (change: AppStateChangeLike) => void): () => void;
|
|
72
|
+
onUrlOpen(listener: (url: string) => void): () => void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Minimal push notification shape for auto-tracking.
|
|
76
|
+
*/
|
|
77
|
+
interface PushNotificationLike {
|
|
78
|
+
id: string;
|
|
79
|
+
title: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Minimal notification received event shape (mirrors `@molecule/app-push` NotificationReceivedEvent).
|
|
83
|
+
*/
|
|
84
|
+
interface NotificationReceivedEventLike {
|
|
85
|
+
notification: PushNotificationLike;
|
|
86
|
+
foreground: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Minimal notification action event shape (mirrors `@molecule/app-push` NotificationActionEvent).
|
|
90
|
+
*/
|
|
91
|
+
interface NotificationActionEventLike {
|
|
92
|
+
notification: PushNotificationLike;
|
|
93
|
+
actionId?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Minimal push client interface for auto-tracking notification events.
|
|
97
|
+
*/
|
|
98
|
+
interface PushClientLike {
|
|
99
|
+
onNotificationReceived(listener: (event: NotificationReceivedEventLike) => void): () => void;
|
|
100
|
+
onNotificationAction(listener: (event: NotificationActionEventLike) => void): () => void;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Auto-tracking options. Pass any combination of sources — only provided
|
|
104
|
+
* sources are tracked. Works for both web and mobile apps.
|
|
105
|
+
*/
|
|
106
|
+
export interface AutoTrackingOptions {
|
|
107
|
+
/** Auth client for login/logout/register/error events. */
|
|
108
|
+
authClient?: AuthClientLike;
|
|
109
|
+
/** Router for page view tracking. */
|
|
110
|
+
router?: RouterLike;
|
|
111
|
+
/** HTTP client for error tracking. */
|
|
112
|
+
httpClient?: HttpClientLike;
|
|
113
|
+
/** Lifecycle client for app foreground/background and deep link tracking. */
|
|
114
|
+
lifecycleClient?: LifecycleClientLike;
|
|
115
|
+
/** Push client for notification received/tapped tracking. */
|
|
116
|
+
pushClient?: PushClientLike;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Sets up automatic analytics tracking for auth events, route changes,
|
|
120
|
+
* HTTP errors, app lifecycle transitions, push notifications, and deep links.
|
|
121
|
+
* Returns a cleanup function that removes all subscriptions.
|
|
122
|
+
*
|
|
123
|
+
* Pass any combination of sources — only provided sources are tracked.
|
|
124
|
+
*
|
|
125
|
+
* The analytics provider is resolved at EVENT time, not at setup time — so
|
|
126
|
+
* `setupAutoTracking()` may safely run before the analytics bond is set
|
|
127
|
+
* (events fired before bonding no-op; events fired after are tracked).
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* // Web app
|
|
132
|
+
* const cleanup = setupAutoTracking({
|
|
133
|
+
* authClient: getClient(),
|
|
134
|
+
* router: getRouter(),
|
|
135
|
+
* httpClient: getHttp(),
|
|
136
|
+
* })
|
|
137
|
+
*
|
|
138
|
+
* // Mobile app (React Native) — add lifecycle and push
|
|
139
|
+
* const cleanup = setupAutoTracking({
|
|
140
|
+
* authClient: getClient(),
|
|
141
|
+
* router: getRouter(),
|
|
142
|
+
* httpClient: getHttp(),
|
|
143
|
+
* lifecycleClient: getLifecycleProvider(),
|
|
144
|
+
* pushClient: getPushProvider(),
|
|
145
|
+
* })
|
|
146
|
+
*
|
|
147
|
+
* // Later, to remove all listeners:
|
|
148
|
+
* cleanup()
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @param options - Sources to auto-track.
|
|
152
|
+
* @returns A cleanup function that removes all event subscriptions.
|
|
153
|
+
*/
|
|
154
|
+
export declare const setupAutoTracking: (options: AutoTrackingOptions) => (() => void);
|
|
155
|
+
export {};
|
|
156
|
+
//# sourceMappingURL=auto-tracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-tracking.d.ts","sourceRoot":"","sources":["../src/auto-tracking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automatic analytics tracking for auth, routing, HTTP, and mobile events.
|
|
3
|
+
*
|
|
4
|
+
* Uses minimal interfaces so there's no hard dependency on
|
|
5
|
+
* `@molecule/app-auth`, `@molecule/app-routing`, `@molecule/app-http`,
|
|
6
|
+
* `@molecule/app-lifecycle`, or `@molecule/app-push`.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { getProvider } from './provider.js';
|
|
11
|
+
/**
|
|
12
|
+
* Sets up automatic analytics tracking for auth events, route changes,
|
|
13
|
+
* HTTP errors, app lifecycle transitions, push notifications, and deep links.
|
|
14
|
+
* Returns a cleanup function that removes all subscriptions.
|
|
15
|
+
*
|
|
16
|
+
* Pass any combination of sources — only provided sources are tracked.
|
|
17
|
+
*
|
|
18
|
+
* The analytics provider is resolved at EVENT time, not at setup time — so
|
|
19
|
+
* `setupAutoTracking()` may safely run before the analytics bond is set
|
|
20
|
+
* (events fired before bonding no-op; events fired after are tracked).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Web app
|
|
25
|
+
* const cleanup = setupAutoTracking({
|
|
26
|
+
* authClient: getClient(),
|
|
27
|
+
* router: getRouter(),
|
|
28
|
+
* httpClient: getHttp(),
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // Mobile app (React Native) — add lifecycle and push
|
|
32
|
+
* const cleanup = setupAutoTracking({
|
|
33
|
+
* authClient: getClient(),
|
|
34
|
+
* router: getRouter(),
|
|
35
|
+
* httpClient: getHttp(),
|
|
36
|
+
* lifecycleClient: getLifecycleProvider(),
|
|
37
|
+
* pushClient: getPushProvider(),
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* // Later, to remove all listeners:
|
|
41
|
+
* cleanup()
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @param options - Sources to auto-track.
|
|
45
|
+
* @returns A cleanup function that removes all event subscriptions.
|
|
46
|
+
*/
|
|
47
|
+
export const setupAutoTracking = (options) => {
|
|
48
|
+
const cleanups = [];
|
|
49
|
+
// Resolve the provider per event — capturing getProvider() once at setup
|
|
50
|
+
// permanently baked in the no-op provider whenever setupAutoTracking() ran
|
|
51
|
+
// before the analytics bond was set, silently dropping every event forever.
|
|
52
|
+
const analytics = () => getProvider();
|
|
53
|
+
// Auth events
|
|
54
|
+
if (options.authClient) {
|
|
55
|
+
const removeListener = options.authClient.addEventListener((event) => {
|
|
56
|
+
switch (event.type) {
|
|
57
|
+
case 'login':
|
|
58
|
+
if (event.user) {
|
|
59
|
+
analytics()
|
|
60
|
+
.identify({
|
|
61
|
+
userId: event.user.id,
|
|
62
|
+
email: event.user.email,
|
|
63
|
+
name: event.user.name,
|
|
64
|
+
})
|
|
65
|
+
.catch(() => { });
|
|
66
|
+
analytics()
|
|
67
|
+
.track({ name: 'auth.login', properties: { userId: event.user.id } })
|
|
68
|
+
.catch(() => { });
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'register':
|
|
72
|
+
if (event.user) {
|
|
73
|
+
analytics()
|
|
74
|
+
.identify({
|
|
75
|
+
userId: event.user.id,
|
|
76
|
+
email: event.user.email,
|
|
77
|
+
name: event.user.name,
|
|
78
|
+
})
|
|
79
|
+
.catch(() => { });
|
|
80
|
+
analytics()
|
|
81
|
+
.track({ name: 'auth.register', properties: { userId: event.user.id } })
|
|
82
|
+
.catch(() => { });
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
case 'logout':
|
|
86
|
+
analytics()
|
|
87
|
+
.track({ name: 'auth.logout' })
|
|
88
|
+
.catch(() => { });
|
|
89
|
+
analytics()
|
|
90
|
+
.reset?.()
|
|
91
|
+
.catch(() => { });
|
|
92
|
+
break;
|
|
93
|
+
case 'error':
|
|
94
|
+
analytics()
|
|
95
|
+
.track({ name: 'auth.error', properties: { error: event.error } })
|
|
96
|
+
.catch(() => { });
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
cleanups.push(removeListener);
|
|
101
|
+
}
|
|
102
|
+
// Route changes
|
|
103
|
+
if (options.router) {
|
|
104
|
+
const removeListener = options.router.subscribe((location) => {
|
|
105
|
+
analytics()
|
|
106
|
+
.page({
|
|
107
|
+
path: location.pathname,
|
|
108
|
+
url: `${location.pathname}${location.search}${location.hash}`,
|
|
109
|
+
})
|
|
110
|
+
.catch(() => { });
|
|
111
|
+
});
|
|
112
|
+
cleanups.push(removeListener);
|
|
113
|
+
}
|
|
114
|
+
// HTTP errors
|
|
115
|
+
if (options.httpClient) {
|
|
116
|
+
const removeInterceptor = options.httpClient.addErrorInterceptor((error) => {
|
|
117
|
+
analytics()
|
|
118
|
+
.track({
|
|
119
|
+
name: 'http.error',
|
|
120
|
+
properties: {
|
|
121
|
+
status: error.status,
|
|
122
|
+
method: error.config?.method,
|
|
123
|
+
url: error.config?.url,
|
|
124
|
+
message: error.message,
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
.catch(() => { });
|
|
128
|
+
return error;
|
|
129
|
+
});
|
|
130
|
+
cleanups.push(removeInterceptor);
|
|
131
|
+
}
|
|
132
|
+
// App lifecycle (foreground/background transitions + deep links)
|
|
133
|
+
if (options.lifecycleClient) {
|
|
134
|
+
const removeStateListener = options.lifecycleClient.onAppStateChange((change) => {
|
|
135
|
+
if (change.current === 'active' && change.previous !== 'active') {
|
|
136
|
+
analytics()
|
|
137
|
+
.track({
|
|
138
|
+
name: 'app.foreground',
|
|
139
|
+
properties: { previous: change.previous },
|
|
140
|
+
})
|
|
141
|
+
.catch(() => { });
|
|
142
|
+
}
|
|
143
|
+
else if (change.current === 'background' && change.previous !== 'background') {
|
|
144
|
+
analytics()
|
|
145
|
+
.track({
|
|
146
|
+
name: 'app.background',
|
|
147
|
+
properties: { previous: change.previous },
|
|
148
|
+
})
|
|
149
|
+
.catch(() => { });
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
cleanups.push(removeStateListener);
|
|
153
|
+
const removeUrlListener = options.lifecycleClient.onUrlOpen((url) => {
|
|
154
|
+
analytics()
|
|
155
|
+
.track({
|
|
156
|
+
name: 'deeplink.open',
|
|
157
|
+
properties: { url },
|
|
158
|
+
})
|
|
159
|
+
.catch(() => { });
|
|
160
|
+
});
|
|
161
|
+
cleanups.push(removeUrlListener);
|
|
162
|
+
}
|
|
163
|
+
// Push notifications (received + tapped)
|
|
164
|
+
if (options.pushClient) {
|
|
165
|
+
const removeReceivedListener = options.pushClient.onNotificationReceived((event) => {
|
|
166
|
+
analytics()
|
|
167
|
+
.track({
|
|
168
|
+
name: 'push.received',
|
|
169
|
+
properties: {
|
|
170
|
+
id: event.notification.id,
|
|
171
|
+
title: event.notification.title,
|
|
172
|
+
foreground: event.foreground,
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
.catch(() => { });
|
|
176
|
+
});
|
|
177
|
+
cleanups.push(removeReceivedListener);
|
|
178
|
+
const removeActionListener = options.pushClient.onNotificationAction((event) => {
|
|
179
|
+
analytics()
|
|
180
|
+
.track({
|
|
181
|
+
name: 'push.tapped',
|
|
182
|
+
properties: {
|
|
183
|
+
id: event.notification.id,
|
|
184
|
+
title: event.notification.title,
|
|
185
|
+
actionId: event.actionId,
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
.catch(() => { });
|
|
189
|
+
});
|
|
190
|
+
cleanups.push(removeActionListener);
|
|
191
|
+
}
|
|
192
|
+
return () => {
|
|
193
|
+
cleanups.forEach((fn) => fn());
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=auto-tracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-tracking.js","sourceRoot":"","sources":["../src/auto-tracking.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontend analytics interface for molecule.dev.
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified analytics API that can be backed by different
|
|
5
|
+
* implementations (PostHog, Mixpanel, etc.).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { identify, reset, setProvider, track } from '@molecule/app-analytics'
|
|
10
|
+
* import { createProvider } from '@molecule/app-analytics-posthog'
|
|
11
|
+
*
|
|
12
|
+
* // At startup — the key comes from your build-time env (in Vite:
|
|
13
|
+
* // import.meta.env.VITE_POSTHOG_KEY); a missing key yields a warning +
|
|
14
|
+
* // no-op provider, never a crash.
|
|
15
|
+
* setProvider(createProvider({ apiKey: posthogApiKey }))
|
|
16
|
+
*
|
|
17
|
+
* identify({ userId: user.id, email: user.email }) // on login
|
|
18
|
+
* track({ name: 'order_placed', properties: { total } })
|
|
19
|
+
* reset() // on logout
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* - Every convenience function (`track`, `identify`, `page`, …) swallows
|
|
24
|
+
* provider errors and no-ops when nothing is bonded — analytics can never
|
|
25
|
+
* break the UI, so `hasProvider()` is the ONLY signal that separates
|
|
26
|
+
* "analytics disabled/unbonded" from "events are being tracked". Check it
|
|
27
|
+
* (and the bond's own console warning) before debugging tracking code.
|
|
28
|
+
* - Attribution is AMBIENT in the browser: call `identify(user)` on login and
|
|
29
|
+
* `reset()` on logout; per-event `userId`/`anonymousId` fields are not
|
|
30
|
+
* honored by browser bonds (they exist for parity with
|
|
31
|
+
* `@molecule/api-analytics`).
|
|
32
|
+
* - `group(groupId)` normalizes the group TYPE to `'company'` in every bond
|
|
33
|
+
* (Mixpanel group key, PostHog group type) — look under "company" in the
|
|
34
|
+
* provider's UI.
|
|
35
|
+
*
|
|
36
|
+
* @module
|
|
37
|
+
*/
|
|
38
|
+
export * from './auto-tracking.js';
|
|
39
|
+
export * from './provider.js';
|
|
40
|
+
export * from './types.js';
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontend analytics interface for molecule.dev.
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified analytics API that can be backed by different
|
|
5
|
+
* implementations (PostHog, Mixpanel, etc.).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { identify, reset, setProvider, track } from '@molecule/app-analytics'
|
|
10
|
+
* import { createProvider } from '@molecule/app-analytics-posthog'
|
|
11
|
+
*
|
|
12
|
+
* // At startup — the key comes from your build-time env (in Vite:
|
|
13
|
+
* // import.meta.env.VITE_POSTHOG_KEY); a missing key yields a warning +
|
|
14
|
+
* // no-op provider, never a crash.
|
|
15
|
+
* setProvider(createProvider({ apiKey: posthogApiKey }))
|
|
16
|
+
*
|
|
17
|
+
* identify({ userId: user.id, email: user.email }) // on login
|
|
18
|
+
* track({ name: 'order_placed', properties: { total } })
|
|
19
|
+
* reset() // on logout
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* - Every convenience function (`track`, `identify`, `page`, …) swallows
|
|
24
|
+
* provider errors and no-ops when nothing is bonded — analytics can never
|
|
25
|
+
* break the UI, so `hasProvider()` is the ONLY signal that separates
|
|
26
|
+
* "analytics disabled/unbonded" from "events are being tracked". Check it
|
|
27
|
+
* (and the bond's own console warning) before debugging tracking code.
|
|
28
|
+
* - Attribution is AMBIENT in the browser: call `identify(user)` on login and
|
|
29
|
+
* `reset()` on logout; per-event `userId`/`anonymousId` fields are not
|
|
30
|
+
* honored by browser bonds (they exist for parity with
|
|
31
|
+
* `@molecule/api-analytics`).
|
|
32
|
+
* - `group(groupId)` normalizes the group TYPE to `'company'` in every bond
|
|
33
|
+
* (Mixpanel group key, PostHog group type) — look under "company" in the
|
|
34
|
+
* provider's UI.
|
|
35
|
+
*
|
|
36
|
+
* @module
|
|
37
|
+
*/
|
|
38
|
+
export * from './auto-tracking.js';
|
|
39
|
+
export * from './provider.js';
|
|
40
|
+
export * from './types.js';
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-side analytics bond accessor and convenience functions.
|
|
3
|
+
*
|
|
4
|
+
* Bond packages call `setProvider()` during setup. All convenience
|
|
5
|
+
* functions silently swallow errors so analytics never breaks the UI.
|
|
6
|
+
* If no provider is bonded, a no-op provider is used.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { AnalyticsEvent, AnalyticsPageView, AnalyticsProvider, AnalyticsUserProps } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Registers an analytics provider as the active singleton.
|
|
13
|
+
*
|
|
14
|
+
* @param provider - The analytics provider implementation to bond.
|
|
15
|
+
*/
|
|
16
|
+
export declare const setProvider: (provider: AnalyticsProvider) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves the bonded analytics provider. Returns a no-op provider if
|
|
19
|
+
* none is bonded, so analytics calls never throw.
|
|
20
|
+
*
|
|
21
|
+
* @returns The bonded analytics provider, or a silent no-op fallback.
|
|
22
|
+
*/
|
|
23
|
+
export declare const getProvider: () => AnalyticsProvider;
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether an analytics provider is currently bonded.
|
|
26
|
+
*
|
|
27
|
+
* @returns `true` if an analytics provider is bonded.
|
|
28
|
+
*/
|
|
29
|
+
export declare const hasProvider: () => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Identifies the current user for analytics tracking. Errors are silently ignored.
|
|
32
|
+
*
|
|
33
|
+
* @param user - The user properties (ID, email, name, traits).
|
|
34
|
+
* @returns A promise that resolves when identification completes or fails silently.
|
|
35
|
+
*/
|
|
36
|
+
export declare const identify: (user: AnalyticsUserProps) => Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Tracks a named event with optional properties. Errors are silently ignored.
|
|
39
|
+
*
|
|
40
|
+
* @param event - The event to track (name and optional properties).
|
|
41
|
+
* @returns A promise that resolves when tracking completes or fails silently.
|
|
42
|
+
*/
|
|
43
|
+
export declare const track: (event: AnalyticsEvent) => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Tracks a page view event. Errors are silently ignored.
|
|
46
|
+
*
|
|
47
|
+
* @param pageView - The page view data (name, path, referrer, etc.).
|
|
48
|
+
* @returns A promise that resolves when page tracking completes or fails silently.
|
|
49
|
+
*/
|
|
50
|
+
export declare const page: (pageView: AnalyticsPageView) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Associates the current user with a group/organization. Errors are silently ignored.
|
|
53
|
+
*
|
|
54
|
+
* @param groupId - The group identifier.
|
|
55
|
+
* @param traits - Optional traits describing the group.
|
|
56
|
+
* @returns A promise that resolves when group association completes or fails silently.
|
|
57
|
+
*/
|
|
58
|
+
export declare const group: (groupId: string, traits?: Record<string, unknown>) => Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Resets the analytics state (e.g. on logout). Errors are silently ignored.
|
|
61
|
+
* @returns A promise that resolves when reset completes or fails silently.
|
|
62
|
+
*/
|
|
63
|
+
export declare const reset: () => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Flushes any queued analytics events to the backend. Errors are silently ignored.
|
|
66
|
+
* @returns A promise that resolves when flush completes or fails silently.
|
|
67
|
+
*/
|
|
68
|
+
export declare const flush: () => Promise<void>;
|
|
69
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAYnB;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,iBAAiB,KAAG,IAEzD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,QAAO,iBAK9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAO,OAE9B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,kBAAkB,KAAG,OAAO,CAAC,IAAI,CAG5C,CAAA;AAEpB;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,cAAc,KAAG,OAAO,CAAC,IAAI,CAGtC,CAAA;AAEpB;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,UAAU,iBAAiB,KAAG,OAAO,CAAC,IAAI,CAG3C,CAAA;AAEpB;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,GAAI,SAAS,MAAM,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAAO,CAAC,IAAI,CACP,CAAA;AAE/E;;;GAGG;AACH,eAAO,MAAM,KAAK,QAAO,OAAO,CAAC,IAAI,CAC2B,CAAA;AAEhE;;;GAGG;AACH,eAAO,MAAM,KAAK,QAAO,OAAO,CAAC,IAAI,CAC2B,CAAA"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-side analytics bond accessor and convenience functions.
|
|
3
|
+
*
|
|
4
|
+
* Bond packages call `setProvider()` during setup. All convenience
|
|
5
|
+
* functions silently swallow errors so analytics never breaks the UI.
|
|
6
|
+
* If no provider is bonded, a no-op provider is used.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { bond, get as bondGet, isBonded } from '@molecule/app-bond';
|
|
11
|
+
const BOND_TYPE = 'app-analytics';
|
|
12
|
+
const noopProvider = {
|
|
13
|
+
identify: async () => { },
|
|
14
|
+
track: async () => { },
|
|
15
|
+
page: async () => { },
|
|
16
|
+
reset: async () => { },
|
|
17
|
+
flush: async () => { },
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Registers an analytics provider as the active singleton.
|
|
21
|
+
*
|
|
22
|
+
* @param provider - The analytics provider implementation to bond.
|
|
23
|
+
*/
|
|
24
|
+
export const setProvider = (provider) => {
|
|
25
|
+
bond(BOND_TYPE, provider);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves the bonded analytics provider. Returns a no-op provider if
|
|
29
|
+
* none is bonded, so analytics calls never throw.
|
|
30
|
+
*
|
|
31
|
+
* @returns The bonded analytics provider, or a silent no-op fallback.
|
|
32
|
+
*/
|
|
33
|
+
export const getProvider = () => {
|
|
34
|
+
if (!isBonded(BOND_TYPE)) {
|
|
35
|
+
return noopProvider;
|
|
36
|
+
}
|
|
37
|
+
return bondGet(BOND_TYPE);
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Checks whether an analytics provider is currently bonded.
|
|
41
|
+
*
|
|
42
|
+
* @returns `true` if an analytics provider is bonded.
|
|
43
|
+
*/
|
|
44
|
+
export const hasProvider = () => {
|
|
45
|
+
return isBonded(BOND_TYPE);
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Identifies the current user for analytics tracking. Errors are silently ignored.
|
|
49
|
+
*
|
|
50
|
+
* @param user - The user properties (ID, email, name, traits).
|
|
51
|
+
* @returns A promise that resolves when identification completes or fails silently.
|
|
52
|
+
*/
|
|
53
|
+
export const identify = (user) => getProvider()
|
|
54
|
+
.identify(user)
|
|
55
|
+
.catch(() => { });
|
|
56
|
+
/**
|
|
57
|
+
* Tracks a named event with optional properties. Errors are silently ignored.
|
|
58
|
+
*
|
|
59
|
+
* @param event - The event to track (name and optional properties).
|
|
60
|
+
* @returns A promise that resolves when tracking completes or fails silently.
|
|
61
|
+
*/
|
|
62
|
+
export const track = (event) => getProvider()
|
|
63
|
+
.track(event)
|
|
64
|
+
.catch(() => { });
|
|
65
|
+
/**
|
|
66
|
+
* Tracks a page view event. Errors are silently ignored.
|
|
67
|
+
*
|
|
68
|
+
* @param pageView - The page view data (name, path, referrer, etc.).
|
|
69
|
+
* @returns A promise that resolves when page tracking completes or fails silently.
|
|
70
|
+
*/
|
|
71
|
+
export const page = (pageView) => getProvider()
|
|
72
|
+
.page(pageView)
|
|
73
|
+
.catch(() => { });
|
|
74
|
+
/**
|
|
75
|
+
* Associates the current user with a group/organization. Errors are silently ignored.
|
|
76
|
+
*
|
|
77
|
+
* @param groupId - The group identifier.
|
|
78
|
+
* @param traits - Optional traits describing the group.
|
|
79
|
+
* @returns A promise that resolves when group association completes or fails silently.
|
|
80
|
+
*/
|
|
81
|
+
export const group = (groupId, traits) => (getProvider().group?.(groupId, traits) ?? Promise.resolve()).catch(() => { });
|
|
82
|
+
/**
|
|
83
|
+
* Resets the analytics state (e.g. on logout). Errors are silently ignored.
|
|
84
|
+
* @returns A promise that resolves when reset completes or fails silently.
|
|
85
|
+
*/
|
|
86
|
+
export const reset = () => (getProvider().reset?.() ?? Promise.resolve()).catch(() => { });
|
|
87
|
+
/**
|
|
88
|
+
* Flushes any queued analytics events to the backend. Errors are silently ignored.
|
|
89
|
+
* @returns A promise that resolves when flush completes or fails silently.
|
|
90
|
+
*/
|
|
91
|
+
export const flush = () => (getProvider().flush?.() ?? Promise.resolve()).catch(() => { });
|
|
92
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AASnE,MAAM,SAAS,GAAG,eAAe,CAAA;AAEjC,MAAM,YAAY,GAAsB;IACtC,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;IACxB,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;IACrB,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;IACpB,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;IACrB,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;CACtB,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAA2B,EAAQ,EAAE;IAC/D,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;AAC3B,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAsB,EAAE;IACjD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzB,OAAO,YAAY,CAAA;IACrB,CAAC;IACD,OAAO,OAAO,CAAoB,SAAS,CAAE,CAAA;AAC/C,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAY,EAAE;IACvC,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAA;AAC5B,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAwB,EAAiB,EAAE,CAClE,WAAW,EAAE;KACV,QAAQ,CAAC,IAAI,CAAC;KACd,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAqB,EAAiB,EAAE,CAC5D,WAAW,EAAE;KACV,KAAK,CAAC,KAAK,CAAC;KACZ,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,QAA2B,EAAiB,EAAE,CACjE,WAAW,EAAE;KACV,IAAI,CAAC,QAAQ,CAAC;KACd,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAEpB;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,MAAgC,EAAiB,EAAE,CACxF,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,GAAkB,EAAE,CACvC,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,GAAkB,EAAE,CACvC,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the app analytics module.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* User properties for analytics identification.
|
|
8
|
+
*/
|
|
9
|
+
export interface AnalyticsUserProps {
|
|
10
|
+
/** Unique user identifier. */
|
|
11
|
+
userId: string;
|
|
12
|
+
/** User email address. */
|
|
13
|
+
email?: string;
|
|
14
|
+
/** User display name. */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Arbitrary key-value traits to associate with the user. */
|
|
17
|
+
traits?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Event properties for analytics tracking.
|
|
21
|
+
*/
|
|
22
|
+
export interface AnalyticsEvent {
|
|
23
|
+
/** Event name (e.g. `"button_clicked"`, `"purchase_completed"`). */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Arbitrary key-value properties for this event. */
|
|
26
|
+
properties?: Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Event timestamp (defaults to now). Only honored where the underlying
|
|
29
|
+
* browser SDK supports client-set timestamps (PostHog does); the Mixpanel
|
|
30
|
+
* browser SDK always stamps the time of capture. For reliable historical
|
|
31
|
+
* timestamps use the API-side `@molecule/api-analytics` bonds.
|
|
32
|
+
*/
|
|
33
|
+
timestamp?: Date;
|
|
34
|
+
/**
|
|
35
|
+
* Identified user who triggered the event. Browser analytics SDKs attribute
|
|
36
|
+
* events to the AMBIENT identified session — call `identify()` first;
|
|
37
|
+
* current browser bonds do not honor a per-event userId override. (Exists
|
|
38
|
+
* for interface parity with `@molecule/api-analytics`, where there is no
|
|
39
|
+
* ambient session and per-event IDs are required.)
|
|
40
|
+
*/
|
|
41
|
+
userId?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Anonymous identifier for unauthenticated users. Like `userId`, browser
|
|
44
|
+
* bonds use the SDK's own ambient anonymous identity instead of this field.
|
|
45
|
+
*/
|
|
46
|
+
anonymousId?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Page view event.
|
|
50
|
+
*/
|
|
51
|
+
export interface AnalyticsPageView {
|
|
52
|
+
/** Page name (e.g. `"Home"`, `"Settings"`). */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Page category (e.g. `"Dashboard"`, `"Marketing"`). */
|
|
55
|
+
category?: string;
|
|
56
|
+
/** Full page URL. */
|
|
57
|
+
url?: string;
|
|
58
|
+
/** Page path (e.g. `"/settings/profile"`). */
|
|
59
|
+
path?: string;
|
|
60
|
+
/** Referrer URL. */
|
|
61
|
+
referrer?: string;
|
|
62
|
+
/** Arbitrary key-value properties for this page view. */
|
|
63
|
+
properties?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Analytics provider interface that all analytics bond packages must implement.
|
|
67
|
+
*/
|
|
68
|
+
export interface AnalyticsProvider {
|
|
69
|
+
/**
|
|
70
|
+
* Identifies a user and associates traits with them.
|
|
71
|
+
*
|
|
72
|
+
* @param user - User properties including userId and optional traits.
|
|
73
|
+
*/
|
|
74
|
+
identify(user: AnalyticsUserProps): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Tracks a named event with optional properties.
|
|
77
|
+
*
|
|
78
|
+
* @param event - The event name and properties to track.
|
|
79
|
+
*/
|
|
80
|
+
track(event: AnalyticsEvent): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Records a page view.
|
|
83
|
+
*
|
|
84
|
+
* @param pageView - Page view details (name, path, properties).
|
|
85
|
+
*/
|
|
86
|
+
page(pageView: AnalyticsPageView): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Associates a user with a group (e.g. company, team).
|
|
89
|
+
*
|
|
90
|
+
* @param groupId - The group identifier.
|
|
91
|
+
* @param traits - Arbitrary traits to associate with the group.
|
|
92
|
+
*/
|
|
93
|
+
group?(groupId: string, traits?: Record<string, unknown>): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Resets the current user identity and generates a new anonymous ID.
|
|
96
|
+
*/
|
|
97
|
+
reset?(): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Flushes any queued events to the analytics service immediately.
|
|
100
|
+
*/
|
|
101
|
+
flush?(): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qBAAqB;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjD;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3C;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEhD;;;;;OAKG;IACH,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAExE;;OAEG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvB;;OAEG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@molecule/app-analytics",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Frontend analytics interface for molecule.dev",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:watch": "vitest"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"molecule",
|
|
24
|
+
"analytics",
|
|
25
|
+
"tracking",
|
|
26
|
+
"posthog",
|
|
27
|
+
"mixpanel"
|
|
28
|
+
],
|
|
29
|
+
"license": "Apache-2.0",
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@molecule/app-bond": "^1.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@molecule/app-bond": "1.0.0",
|
|
35
|
+
"@types/node": "26.1.2",
|
|
36
|
+
"typescript": "6.0.3",
|
|
37
|
+
"vitest": "4.1.10"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/molecule-dev/molecule.git",
|
|
42
|
+
"directory": "packages/app/core/analytics"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/molecule-dev/molecule/tree/main/packages/app/core/analytics",
|
|
45
|
+
"bugs": "https://github.com/molecule-dev/molecule/issues",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|