@codaco/analytics 7.0.0 → 9.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/CHANGELOG.md +19 -0
- package/MIGRATION.md +404 -0
- package/README.md +486 -4
- package/dist/chunk-3NEQVIC4.js +72 -0
- package/dist/chunk-3NEQVIC4.js.map +1 -0
- package/dist/index.d.ts +113 -144
- package/dist/index.js +188 -183
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +44 -0
- package/dist/server.js +153 -0
- package/dist/server.js.map +1 -0
- package/dist/types-Ymgjicqi.d.ts +145 -0
- package/package.json +31 -24
- package/src/__tests__/client.test.ts +276 -0
- package/src/__tests__/index.test.ts +207 -0
- package/src/__tests__/utils.test.ts +105 -0
- package/src/client.ts +151 -0
- package/src/config.ts +92 -0
- package/src/hooks.ts +79 -0
- package/src/index.ts +69 -264
- package/src/provider.tsx +60 -0
- package/src/server.ts +213 -0
- package/src/types.ts +183 -0
- package/src/utils.ts +13 -16
- package/tsconfig.json +7 -7
- package/vitest.config.ts +18 -0
- package/.turbo/turbo-build.log +0 -16
- package/.turbo/turbo-lint.log +0 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,150 +1,119 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { A as AnalyticsConfig, a as Analytics } from './types-Ymgjicqi.js';
|
|
2
|
+
export { E as ErrorProperties, b as EventProperties, c as EventType, e as eventTypes, l as legacyEventTypeMap } from './types-Ymgjicqi.js';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import 'zod';
|
|
3
6
|
|
|
4
|
-
declare const eventTypes: readonly ["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"];
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
* general events or errors. We discriminate on the `type` property to determine
|
|
8
|
-
* which schema to use, and then merge the shared properties.
|
|
8
|
+
* Check if analytics is disabled via environment variables
|
|
9
9
|
*/
|
|
10
|
-
declare
|
|
11
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
12
|
-
}, {
|
|
13
|
-
type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
|
|
14
|
-
}>, "strip", z.ZodTypeAny, {
|
|
15
|
-
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
16
|
-
metadata?: Record<string, unknown> | undefined;
|
|
17
|
-
}, {
|
|
18
|
-
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
19
|
-
metadata?: Record<string, unknown> | undefined;
|
|
20
|
-
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
21
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
22
|
-
}, {
|
|
23
|
-
type: z.ZodLiteral<"Error">;
|
|
24
|
-
message: z.ZodString;
|
|
25
|
-
name: z.ZodString;
|
|
26
|
-
stack: z.ZodOptional<z.ZodString>;
|
|
27
|
-
cause: z.ZodOptional<z.ZodString>;
|
|
28
|
-
}>, "strip", z.ZodTypeAny, {
|
|
29
|
-
type: "Error";
|
|
30
|
-
message: string;
|
|
31
|
-
name: string;
|
|
32
|
-
stack?: string | undefined;
|
|
33
|
-
cause?: string | undefined;
|
|
34
|
-
metadata?: Record<string, unknown> | undefined;
|
|
35
|
-
}, {
|
|
36
|
-
type: "Error";
|
|
37
|
-
message: string;
|
|
38
|
-
name: string;
|
|
39
|
-
stack?: string | undefined;
|
|
40
|
-
cause?: string | undefined;
|
|
41
|
-
metadata?: Record<string, unknown> | undefined;
|
|
42
|
-
}>]>;
|
|
43
|
-
type RawEvent = z.infer<typeof RawEventSchema>;
|
|
44
|
-
declare const TrackableEventSchema: z.ZodIntersection<z.ZodDiscriminatedUnion<"type", [z.ZodObject<z.objectUtil.extendShape<{
|
|
45
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
46
|
-
}, {
|
|
47
|
-
type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
|
|
48
|
-
}>, "strip", z.ZodTypeAny, {
|
|
49
|
-
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
50
|
-
metadata?: Record<string, unknown> | undefined;
|
|
51
|
-
}, {
|
|
52
|
-
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
53
|
-
metadata?: Record<string, unknown> | undefined;
|
|
54
|
-
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
55
|
-
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
56
|
-
}, {
|
|
57
|
-
type: z.ZodLiteral<"Error">;
|
|
58
|
-
message: z.ZodString;
|
|
59
|
-
name: z.ZodString;
|
|
60
|
-
stack: z.ZodOptional<z.ZodString>;
|
|
61
|
-
cause: z.ZodOptional<z.ZodString>;
|
|
62
|
-
}>, "strip", z.ZodTypeAny, {
|
|
63
|
-
type: "Error";
|
|
64
|
-
message: string;
|
|
65
|
-
name: string;
|
|
66
|
-
stack?: string | undefined;
|
|
67
|
-
cause?: string | undefined;
|
|
68
|
-
metadata?: Record<string, unknown> | undefined;
|
|
69
|
-
}, {
|
|
70
|
-
type: "Error";
|
|
71
|
-
message: string;
|
|
72
|
-
name: string;
|
|
73
|
-
stack?: string | undefined;
|
|
74
|
-
cause?: string | undefined;
|
|
75
|
-
metadata?: Record<string, unknown> | undefined;
|
|
76
|
-
}>]>, z.ZodObject<{
|
|
77
|
-
timestamp: z.ZodString;
|
|
78
|
-
}, "strip", z.ZodTypeAny, {
|
|
79
|
-
timestamp: string;
|
|
80
|
-
}, {
|
|
81
|
-
timestamp: string;
|
|
82
|
-
}>>;
|
|
83
|
-
type TrackableEvent = z.infer<typeof TrackableEventSchema>;
|
|
10
|
+
declare function isDisabledByEnv(): boolean;
|
|
84
11
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* intersection of the trackable event and the dispatchable properties.
|
|
12
|
+
* Default configuration for analytics
|
|
13
|
+
* API host and key are hardcoded, but disabled flag can be set via environment variables
|
|
88
14
|
*/
|
|
89
|
-
declare const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
15
|
+
declare const defaultConfig: Partial<AnalyticsConfig>;
|
|
16
|
+
/**
|
|
17
|
+
* Merge user config with defaults
|
|
18
|
+
*
|
|
19
|
+
* Note: This package is designed to work exclusively with the Cloudflare Worker
|
|
20
|
+
* reverse proxy (ph-relay.networkcanvas.com). Authentication is handled by the
|
|
21
|
+
* worker, so the API key is optional and defaults to a placeholder value.
|
|
22
|
+
*
|
|
23
|
+
* The only environment variable checked is DISABLE_ANALYTICS / NEXT_PUBLIC_DISABLE_ANALYTICS
|
|
24
|
+
* for disabling tracking. All other configuration is hardcoded or passed explicitly.
|
|
25
|
+
*/
|
|
26
|
+
declare function mergeConfig(userConfig: AnalyticsConfig): Required<AnalyticsConfig>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Hook to access analytics functionality in React components
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* import { useAnalytics } from '@codaco/analytics';
|
|
34
|
+
*
|
|
35
|
+
* function MyComponent() {
|
|
36
|
+
* const { trackEvent, trackError } = useAnalytics();
|
|
37
|
+
*
|
|
38
|
+
* const handleAction = () => {
|
|
39
|
+
* trackEvent('protocol_installed', {
|
|
40
|
+
* metadata: { protocolName: 'My Protocol' }
|
|
41
|
+
* });
|
|
42
|
+
* };
|
|
43
|
+
*
|
|
44
|
+
* return <button onClick={handleAction}>Install Protocol</button>;
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function useAnalytics(): Analytics;
|
|
49
|
+
/**
|
|
50
|
+
* Hook to access feature flags
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* import { useFeatureFlag } from '@codaco/analytics';
|
|
55
|
+
*
|
|
56
|
+
* function MyComponent() {
|
|
57
|
+
* const isNewFeatureEnabled = useFeatureFlag('new-feature');
|
|
58
|
+
*
|
|
59
|
+
* if (isNewFeatureEnabled) {
|
|
60
|
+
* return <NewFeature />;
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* return <OldFeature />;
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function useFeatureFlag(flagKey: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Hook to access feature flag values (for multivariate flags)
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* import { useFeatureFlagValue } from '@codaco/analytics';
|
|
74
|
+
*
|
|
75
|
+
* function MyComponent() {
|
|
76
|
+
* const theme = useFeatureFlagValue('theme-variant');
|
|
77
|
+
*
|
|
78
|
+
* return <div className={theme === 'dark' ? 'dark-theme' : 'light-theme'}>
|
|
79
|
+
* Content
|
|
80
|
+
* </div>;
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function useFeatureFlagValue(flagKey: string): string | boolean | undefined;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Props for the AnalyticsProvider
|
|
88
|
+
*/
|
|
89
|
+
interface AnalyticsProviderProps {
|
|
90
|
+
children: ReactNode;
|
|
91
|
+
config: AnalyticsConfig;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Provider component that initializes PostHog and provides analytics context
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* import { AnalyticsProvider } from '@codaco/analytics';
|
|
99
|
+
*
|
|
100
|
+
* function App({ children }) {
|
|
101
|
+
* return (
|
|
102
|
+
* <AnalyticsProvider
|
|
103
|
+
* config={{
|
|
104
|
+
* installationId: 'your-installation-id',
|
|
105
|
+
* apiKey: 'phc_your_api_key', // optional if set via env
|
|
106
|
+
* apiHost: 'https://ph-relay.networkcanvas.com', // optional
|
|
107
|
+
* }}
|
|
108
|
+
* >
|
|
109
|
+
* {children}
|
|
110
|
+
* </AnalyticsProvider>
|
|
111
|
+
* );
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
declare function AnalyticsProvider({ children, config }: AnalyticsProviderProps): react.JSX.Element | null;
|
|
116
|
+
|
|
117
|
+
declare function ensureError(value: unknown): Error;
|
|
149
118
|
|
|
150
|
-
export {
|
|
119
|
+
export { Analytics, AnalyticsConfig, AnalyticsProvider, type AnalyticsProviderProps, defaultConfig, ensureError, isDisabledByEnv, mergeConfig, useAnalytics, useFeatureFlag, useFeatureFlagValue };
|
package/dist/index.js
CHANGED
|
@@ -1,205 +1,210 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
defaultConfig,
|
|
3
|
+
ensureError,
|
|
4
|
+
isDisabledByEnv,
|
|
5
|
+
mergeConfig
|
|
6
|
+
} from "./chunk-3NEQVIC4.js";
|
|
3
7
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
6
|
-
if (!value) return new Error("No value was thrown");
|
|
7
|
-
if (value instanceof Error) return value;
|
|
8
|
-
if (Object.prototype.isPrototypeOf.call(value, Error))
|
|
9
|
-
return value;
|
|
10
|
-
let stringified = "[Unable to stringify the thrown value]";
|
|
11
|
-
try {
|
|
12
|
-
stringified = JSON.stringify(value);
|
|
13
|
-
} catch (e) {
|
|
14
|
-
console.error(e);
|
|
15
|
-
}
|
|
16
|
-
const error = new Error(
|
|
17
|
-
`This value was thrown as is, not through an Error: ${stringified}`
|
|
18
|
-
);
|
|
19
|
-
return error;
|
|
20
|
-
}
|
|
8
|
+
// src/hooks.ts
|
|
9
|
+
import { useContext } from "react";
|
|
21
10
|
|
|
22
|
-
// src/
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
var DispatchablePropertiesSchema = z.object({
|
|
56
|
-
installationId: z.string(),
|
|
57
|
-
countryISOCode: z.string()
|
|
58
|
-
});
|
|
59
|
-
var AnalyticsEventSchema = z.intersection(
|
|
60
|
-
TrackableEventSchema,
|
|
61
|
-
DispatchablePropertiesSchema
|
|
62
|
-
);
|
|
63
|
-
var createRouteHandler = ({
|
|
64
|
-
platformUrl = "https://analytics.networkcanvas.com",
|
|
65
|
-
installationId,
|
|
66
|
-
disableAnalytics
|
|
67
|
-
}) => {
|
|
68
|
-
return async (request) => {
|
|
69
|
-
try {
|
|
70
|
-
const incomingEvent = await request.json();
|
|
71
|
-
if (disableAnalytics) {
|
|
72
|
-
console.info("\u{1F6D1} Analytics disabled. Payload not sent.");
|
|
73
|
-
try {
|
|
74
|
-
console.info(
|
|
75
|
-
"Payload:",
|
|
76
|
-
"\n",
|
|
77
|
-
JSON.stringify(incomingEvent, null, 2)
|
|
78
|
-
);
|
|
79
|
-
} catch (e) {
|
|
80
|
-
console.error("Error stringifying payload:", e);
|
|
11
|
+
// src/provider.tsx
|
|
12
|
+
import { createContext, useEffect, useRef } from "react";
|
|
13
|
+
|
|
14
|
+
// src/client.ts
|
|
15
|
+
import posthog from "posthog-js";
|
|
16
|
+
function createAnalytics(config) {
|
|
17
|
+
const { apiHost, apiKey, installationId, disabled, debug, posthogOptions } = config;
|
|
18
|
+
if (disabled) {
|
|
19
|
+
return createNoOpAnalytics(installationId);
|
|
20
|
+
}
|
|
21
|
+
posthog.init(apiKey, {
|
|
22
|
+
api_host: apiHost,
|
|
23
|
+
loaded: (posthogInstance) => {
|
|
24
|
+
posthogInstance.register({
|
|
25
|
+
installation_id: installationId
|
|
26
|
+
});
|
|
27
|
+
if (debug) {
|
|
28
|
+
posthogInstance.debug();
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
...posthogOptions
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
trackEvent: (eventType, properties) => {
|
|
35
|
+
if (disabled) return;
|
|
36
|
+
try {
|
|
37
|
+
posthog.capture(eventType, {
|
|
38
|
+
...properties,
|
|
39
|
+
// Flatten metadata into properties for better PostHog integration
|
|
40
|
+
...properties?.metadata ?? {}
|
|
41
|
+
});
|
|
42
|
+
} catch (_e) {
|
|
43
|
+
if (debug) {
|
|
81
44
|
}
|
|
82
|
-
return NextResponse.json(
|
|
83
|
-
{ message: "Analytics disabled" },
|
|
84
|
-
{ status: 200 }
|
|
85
|
-
);
|
|
86
45
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
46
|
+
},
|
|
47
|
+
trackError: (error, additionalProperties) => {
|
|
48
|
+
if (disabled) return;
|
|
49
|
+
try {
|
|
50
|
+
const errorObj = ensureError(error);
|
|
51
|
+
const errorProperties = {
|
|
52
|
+
message: errorObj.message,
|
|
53
|
+
name: errorObj.name,
|
|
54
|
+
stack: errorObj.stack,
|
|
55
|
+
cause: errorObj.cause ? String(errorObj.cause) : void 0,
|
|
56
|
+
...additionalProperties
|
|
57
|
+
};
|
|
58
|
+
posthog.capture("error", {
|
|
59
|
+
...errorProperties,
|
|
60
|
+
// Flatten metadata
|
|
61
|
+
...additionalProperties?.metadata ?? {}
|
|
62
|
+
});
|
|
63
|
+
} catch (_e) {
|
|
64
|
+
if (debug) {
|
|
65
|
+
}
|
|
91
66
|
}
|
|
92
|
-
|
|
67
|
+
},
|
|
68
|
+
isFeatureEnabled: (flagKey) => {
|
|
69
|
+
if (disabled) return false;
|
|
93
70
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
97
|
-
if (!ip) {
|
|
98
|
-
throw new Error("Could not fetch IP address");
|
|
71
|
+
return posthog.isFeatureEnabled(flagKey);
|
|
72
|
+
} catch (_e) {
|
|
73
|
+
if (debug) {
|
|
99
74
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
getFeatureFlag: (flagKey) => {
|
|
79
|
+
if (disabled) return void 0;
|
|
80
|
+
try {
|
|
81
|
+
return posthog.getFeatureFlag(flagKey);
|
|
82
|
+
} catch (_e) {
|
|
83
|
+
if (debug) {
|
|
107
84
|
}
|
|
108
|
-
|
|
109
|
-
console.error("Geolocation failed:", e);
|
|
85
|
+
return void 0;
|
|
110
86
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
method: "POST",
|
|
119
|
-
headers: {
|
|
120
|
-
"Content-Type": "application/json"
|
|
121
|
-
},
|
|
122
|
-
body: JSON.stringify(analyticsEvent)
|
|
123
|
-
});
|
|
124
|
-
if (!response.ok) {
|
|
125
|
-
let error = `Analytics platform returned an unexpected error: ${response.statusText}`;
|
|
126
|
-
if (response.status === 400) {
|
|
127
|
-
error = `Analytics platform rejected the event as invalid. Please check the event schema`;
|
|
87
|
+
},
|
|
88
|
+
reloadFeatureFlags: () => {
|
|
89
|
+
if (disabled) return;
|
|
90
|
+
try {
|
|
91
|
+
posthog.reloadFeatureFlags();
|
|
92
|
+
} catch (_e) {
|
|
93
|
+
if (debug) {
|
|
128
94
|
}
|
|
129
|
-
|
|
130
|
-
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
identify: (distinctId, properties) => {
|
|
98
|
+
if (disabled) return;
|
|
99
|
+
try {
|
|
100
|
+
posthog.identify(distinctId, properties);
|
|
101
|
+
} catch (_e) {
|
|
102
|
+
if (debug) {
|
|
131
103
|
}
|
|
132
|
-
|
|
133
|
-
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
reset: () => {
|
|
107
|
+
if (disabled) return;
|
|
108
|
+
try {
|
|
109
|
+
posthog.reset();
|
|
110
|
+
} catch (_e) {
|
|
111
|
+
if (debug) {
|
|
134
112
|
}
|
|
135
|
-
console.info(`\u26A0\uFE0F Analytics platform rejected event: ${error}`);
|
|
136
|
-
return Response.json(
|
|
137
|
-
{
|
|
138
|
-
error
|
|
139
|
-
},
|
|
140
|
-
{ status: 500 }
|
|
141
|
-
);
|
|
142
113
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const error = ensureError(e);
|
|
147
|
-
console.info("\u{1F6AB} Internal error with sending analytics event.");
|
|
148
|
-
return Response.json(
|
|
149
|
-
{ error: `Error in analytics route handler: ${error.message}` },
|
|
150
|
-
{ status: 500 }
|
|
151
|
-
);
|
|
152
|
-
}
|
|
114
|
+
},
|
|
115
|
+
isEnabled: () => !disabled,
|
|
116
|
+
getInstallationId: () => installationId
|
|
153
117
|
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
118
|
+
}
|
|
119
|
+
function createNoOpAnalytics(installationId) {
|
|
120
|
+
return {
|
|
121
|
+
trackEvent: () => {
|
|
122
|
+
},
|
|
123
|
+
trackError: () => {
|
|
124
|
+
},
|
|
125
|
+
isFeatureEnabled: () => false,
|
|
126
|
+
getFeatureFlag: () => void 0,
|
|
127
|
+
reloadFeatureFlags: () => {
|
|
128
|
+
},
|
|
129
|
+
identify: () => {
|
|
130
|
+
},
|
|
131
|
+
reset: () => {
|
|
132
|
+
},
|
|
133
|
+
isEnabled: () => false,
|
|
134
|
+
getInstallationId: () => installationId
|
|
160
135
|
};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (response.status === 404) {
|
|
172
|
-
return {
|
|
173
|
-
error: `Analytics endpoint not found, did you forget to add the route?`,
|
|
174
|
-
success: false
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
if (response.status === 400) {
|
|
178
|
-
return {
|
|
179
|
-
error: `Invalid event sent to analytics endpoint: ${response.statusText}`,
|
|
180
|
-
success: false
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
error: `Internal server error when sending analytics event: ${response.statusText}. Check the route handler implementation.`,
|
|
185
|
-
success: false
|
|
186
|
-
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/provider.tsx
|
|
139
|
+
var AnalyticsContext = createContext(null);
|
|
140
|
+
function AnalyticsProvider({ children, config }) {
|
|
141
|
+
const analyticsRef = useRef(null);
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!analyticsRef.current) {
|
|
144
|
+
const mergedConfig = mergeConfig(config);
|
|
145
|
+
analyticsRef.current = createAnalytics(mergedConfig);
|
|
187
146
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
147
|
+
}, []);
|
|
148
|
+
if (!analyticsRef.current) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return /* @__PURE__ */ React.createElement(AnalyticsContext.Provider, { value: analyticsRef.current }, children);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/hooks.ts
|
|
155
|
+
function useAnalytics() {
|
|
156
|
+
const analytics = useContext(AnalyticsContext);
|
|
157
|
+
if (!analytics) {
|
|
158
|
+
throw new Error("useAnalytics must be used within an AnalyticsProvider");
|
|
195
159
|
}
|
|
160
|
+
return analytics;
|
|
161
|
+
}
|
|
162
|
+
function useFeatureFlag(flagKey) {
|
|
163
|
+
const analytics = useAnalytics();
|
|
164
|
+
return analytics.isFeatureEnabled(flagKey) ?? false;
|
|
165
|
+
}
|
|
166
|
+
function useFeatureFlagValue(flagKey) {
|
|
167
|
+
const analytics = useAnalytics();
|
|
168
|
+
return analytics.getFeatureFlag(flagKey);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/types.ts
|
|
172
|
+
import z from "zod";
|
|
173
|
+
var eventTypes = [
|
|
174
|
+
"app_setup",
|
|
175
|
+
"protocol_installed",
|
|
176
|
+
"interview_started",
|
|
177
|
+
"interview_completed",
|
|
178
|
+
"data_exported",
|
|
179
|
+
"error"
|
|
180
|
+
];
|
|
181
|
+
var legacyEventTypeMap = {
|
|
182
|
+
AppSetup: "app_setup",
|
|
183
|
+
ProtocolInstalled: "protocol_installed",
|
|
184
|
+
InterviewStarted: "interview_started",
|
|
185
|
+
InterviewCompleted: "interview_completed",
|
|
186
|
+
DataExported: "data_exported",
|
|
187
|
+
Error: "error"
|
|
196
188
|
};
|
|
189
|
+
var EventPropertiesSchema = z.object({
|
|
190
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
191
|
+
});
|
|
192
|
+
var ErrorPropertiesSchema = EventPropertiesSchema.extend({
|
|
193
|
+
message: z.string(),
|
|
194
|
+
name: z.string(),
|
|
195
|
+
stack: z.string().optional(),
|
|
196
|
+
cause: z.string().optional()
|
|
197
|
+
});
|
|
197
198
|
export {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
createRouteHandler,
|
|
199
|
+
AnalyticsProvider,
|
|
200
|
+
defaultConfig,
|
|
201
|
+
ensureError,
|
|
202
202
|
eventTypes,
|
|
203
|
-
|
|
203
|
+
isDisabledByEnv,
|
|
204
|
+
legacyEventTypeMap,
|
|
205
|
+
mergeConfig,
|
|
206
|
+
useAnalytics,
|
|
207
|
+
useFeatureFlag,
|
|
208
|
+
useFeatureFlagValue
|
|
204
209
|
};
|
|
205
210
|
//# sourceMappingURL=index.js.map
|