@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 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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"}
@@ -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"}
@@ -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"}
@@ -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,7 @@
1
+ /**
2
+ * Type definitions for the app analytics module.
3
+ *
4
+ * @module
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -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
+ }