@codaco/analytics 3.1.0 → 4.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/.eslintrc.js +4 -4
- package/.turbo/turbo-build.log +17 -16
- package/.turbo/turbo-test.log +31 -0
- package/README.md +9 -9
- package/dist/index.d.mts +137 -37
- package/dist/index.mjs +99 -67
- package/dist/index.mjs.map +1 -1
- package/jest.config.js +198 -198
- package/package.json +1 -1
- package/src/index.ts +226 -185
- package/src/utils.ts +36 -36
- package/tsconfig.json +10 -10
package/.eslintrc.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
extends: ["custom/next"],
|
|
4
|
-
};
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
extends: ["custom/next"],
|
|
4
|
+
};
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[34mCLI[39m
|
|
7
|
-
[34mCLI[39m
|
|
8
|
-
[34mCLI[39m
|
|
9
|
-
[34mCLI[39m
|
|
10
|
-
[
|
|
11
|
-
[
|
|
12
|
-
[32mESM[39m [1mdist
|
|
13
|
-
[32mESM[39m
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[32mDTS[39m
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @codaco/analytics@4.0.0 build /Users/jmh629/Projects/error-analytics-microservice/packages/analytics
|
|
4
|
+
> tsup src/index.ts --format esm --dts --clean --sourcemap
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v7.2.0
|
|
9
|
+
[34mCLI[39m Target: es2022
|
|
10
|
+
[34mCLI[39m Cleaning output folder
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m5.69 KB[39m
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m11.29 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 31ms
|
|
15
|
+
[34mDTS[39m Build start
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 980ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m5.97 KB[39m
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
> @codaco/analytics@0.6.0-alpha test /Users/jmh629/Projects/error-analytics-microservice/packages/analytics
|
|
3
|
+
> NODE_OPTIONS=--experimental-vm-modules jest "--watch"
|
|
4
|
+
|
|
5
|
+
(node:55883) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
|
|
6
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
7
|
+
FAIL src/index.test.mjs
|
|
8
|
+
Analytics client package
|
|
9
|
+
✕ should be able to create a new client (1 ms)
|
|
10
|
+
|
|
11
|
+
● Analytics client package › should be able to create a new client
|
|
12
|
+
|
|
13
|
+
TypeError: Cannot read properties of undefined (reading 'platformUrl')
|
|
14
|
+
|
|
15
|
+
50 | private platformUrl?: string = "https://analytics.networkcanvas.dev";
|
|
16
|
+
51 | private installationId: string | null = null;
|
|
17
|
+
> 52 |
|
|
18
|
+
| ^
|
|
19
|
+
53 | private dispatchQueue: QueueObject<AnalyticsEventOrError>;
|
|
20
|
+
54 |
|
|
21
|
+
55 | private enabled: boolean = true;
|
|
22
|
+
|
|
23
|
+
at new s (src/index.ts:52:11)
|
|
24
|
+
at Object.<anonymous> (src/index.test.mjs:6:20)
|
|
25
|
+
|
|
26
|
+
Test Suites: 1 failed, 1 total
|
|
27
|
+
Tests: 1 failed, 1 total
|
|
28
|
+
Snapshots: 0 total
|
|
29
|
+
Time: 0.215 s, estimated 1 s
|
|
30
|
+
Ran all test suites related to changed files.
|
|
31
|
+
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# @codaco/analytics
|
|
2
|
-
|
|
3
|
-
This npm package implements methods and types for sending analytics and errors from Fresco instances to a custom error and analytics microservice.
|
|
4
|
-
|
|
5
|
-
It exports two functions:
|
|
6
|
-
|
|
7
|
-
**createRouteHandler** - A function that creates a NextJs route handler which geolocates requests, and forwards the event payload to the microservice.
|
|
8
|
-
|
|
9
|
-
**makeEventTracker** - A function that returns a `trackEvent` function, which attaches timestamp data to an event, and then calls the route handler.
|
|
1
|
+
# @codaco/analytics
|
|
2
|
+
|
|
3
|
+
This npm package implements methods and types for sending analytics and errors from Fresco instances to a custom error and analytics microservice.
|
|
4
|
+
|
|
5
|
+
It exports two functions:
|
|
6
|
+
|
|
7
|
+
**createRouteHandler** - A function that creates a NextJs route handler which geolocates requests, and forwards the event payload to the microservice.
|
|
8
|
+
|
|
9
|
+
**makeEventTracker** - A function that returns a `trackEvent` function, which attaches timestamp data to an event, and then calls the route handler.
|
package/dist/index.d.mts
CHANGED
|
@@ -2,19 +2,24 @@ import { NextRequest } from 'next/server';
|
|
|
2
2
|
import { WebServiceClient } from '@maxmind/geoip2-node';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
|
-
declare const eventTypes: readonly ["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
declare const eventTypes: readonly ["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"];
|
|
6
|
+
declare const RawEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
7
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8
|
+
type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
11
|
+
metadata?: Record<string, unknown> | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
14
|
+
metadata?: Record<string, unknown> | undefined;
|
|
15
|
+
}>, z.ZodObject<{
|
|
16
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
17
|
+
type: z.ZodLiteral<"Error">;
|
|
18
|
+
error: z.ZodObject<{
|
|
14
19
|
message: z.ZodString;
|
|
15
20
|
name: z.ZodString;
|
|
16
21
|
stack: z.ZodOptional<z.ZodString>;
|
|
17
|
-
}, "
|
|
22
|
+
}, "strict", z.ZodTypeAny, {
|
|
18
23
|
message: string;
|
|
19
24
|
name: string;
|
|
20
25
|
stack?: string | undefined;
|
|
@@ -22,51 +27,146 @@ declare const EventsSchema: z.ZodObject<{
|
|
|
22
27
|
message: string;
|
|
23
28
|
name: string;
|
|
24
29
|
stack?: string | undefined;
|
|
25
|
-
}
|
|
30
|
+
}>;
|
|
31
|
+
}, "strip", z.ZodTypeAny, {
|
|
32
|
+
type: "Error";
|
|
33
|
+
error: {
|
|
34
|
+
message: string;
|
|
35
|
+
name: string;
|
|
36
|
+
stack?: string | undefined;
|
|
37
|
+
};
|
|
38
|
+
metadata?: Record<string, unknown> | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
type: "Error";
|
|
41
|
+
error: {
|
|
42
|
+
message: string;
|
|
43
|
+
name: string;
|
|
44
|
+
stack?: string | undefined;
|
|
45
|
+
};
|
|
46
|
+
metadata?: Record<string, unknown> | undefined;
|
|
47
|
+
}>]>;
|
|
48
|
+
type RawEvent = z.infer<typeof RawEventSchema>;
|
|
49
|
+
declare const TrackableEventSchema: z.ZodIntersection<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
26
50
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
51
|
+
type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
|
|
27
52
|
}, "strip", z.ZodTypeAny, {
|
|
28
|
-
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
53
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
54
|
+
metadata?: Record<string, unknown> | undefined;
|
|
55
|
+
}, {
|
|
56
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
57
|
+
metadata?: Record<string, unknown> | undefined;
|
|
58
|
+
}>, z.ZodObject<{
|
|
59
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
60
|
+
type: z.ZodLiteral<"Error">;
|
|
61
|
+
error: z.ZodObject<{
|
|
62
|
+
message: z.ZodString;
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
stack: z.ZodOptional<z.ZodString>;
|
|
65
|
+
}, "strict", z.ZodTypeAny, {
|
|
66
|
+
message: string;
|
|
67
|
+
name: string;
|
|
68
|
+
stack?: string | undefined;
|
|
69
|
+
}, {
|
|
33
70
|
message: string;
|
|
34
71
|
name: string;
|
|
35
72
|
stack?: string | undefined;
|
|
36
|
-
}
|
|
73
|
+
}>;
|
|
74
|
+
}, "strip", z.ZodTypeAny, {
|
|
75
|
+
type: "Error";
|
|
76
|
+
error: {
|
|
77
|
+
message: string;
|
|
78
|
+
name: string;
|
|
79
|
+
stack?: string | undefined;
|
|
80
|
+
};
|
|
37
81
|
metadata?: Record<string, unknown> | undefined;
|
|
38
82
|
}, {
|
|
39
|
-
type: "
|
|
40
|
-
|
|
83
|
+
type: "Error";
|
|
84
|
+
error: {
|
|
85
|
+
message: string;
|
|
86
|
+
name: string;
|
|
87
|
+
stack?: string | undefined;
|
|
88
|
+
};
|
|
89
|
+
metadata?: Record<string, unknown> | undefined;
|
|
90
|
+
}>]>, z.ZodObject<{
|
|
91
|
+
timestamp: z.ZodString;
|
|
92
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
93
|
timestamp: string;
|
|
42
|
-
|
|
43
|
-
|
|
94
|
+
}, {
|
|
95
|
+
timestamp: string;
|
|
96
|
+
}>>;
|
|
97
|
+
type TrackableEvent = z.infer<typeof TrackableEventSchema>;
|
|
98
|
+
declare const DispatchableEventSchema: z.ZodIntersection<z.ZodIntersection<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
99
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
100
|
+
type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
|
|
101
|
+
}, "strip", z.ZodTypeAny, {
|
|
102
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
103
|
+
metadata?: Record<string, unknown> | undefined;
|
|
104
|
+
}, {
|
|
105
|
+
type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
|
|
106
|
+
metadata?: Record<string, unknown> | undefined;
|
|
107
|
+
}>, z.ZodObject<{
|
|
108
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
109
|
+
type: z.ZodLiteral<"Error">;
|
|
110
|
+
error: z.ZodObject<{
|
|
111
|
+
message: z.ZodString;
|
|
112
|
+
name: z.ZodString;
|
|
113
|
+
stack: z.ZodOptional<z.ZodString>;
|
|
114
|
+
}, "strict", z.ZodTypeAny, {
|
|
115
|
+
message: string;
|
|
116
|
+
name: string;
|
|
117
|
+
stack?: string | undefined;
|
|
118
|
+
}, {
|
|
119
|
+
message: string;
|
|
120
|
+
name: string;
|
|
121
|
+
stack?: string | undefined;
|
|
122
|
+
}>;
|
|
123
|
+
}, "strip", z.ZodTypeAny, {
|
|
124
|
+
type: "Error";
|
|
125
|
+
error: {
|
|
44
126
|
message: string;
|
|
45
127
|
name: string;
|
|
46
128
|
stack?: string | undefined;
|
|
47
|
-
}
|
|
129
|
+
};
|
|
48
130
|
metadata?: Record<string, unknown> | undefined;
|
|
49
|
-
}
|
|
50
|
-
type Event = z.infer<typeof EventsSchema>;
|
|
51
|
-
type AnalyticsEvent = {
|
|
52
|
-
type: EventTypeWithoutError;
|
|
53
|
-
metadata?: Record<string, unknown>;
|
|
54
|
-
};
|
|
55
|
-
type AnalyticsError = {
|
|
131
|
+
}, {
|
|
56
132
|
type: "Error";
|
|
57
|
-
error:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
133
|
+
error: {
|
|
134
|
+
message: string;
|
|
135
|
+
name: string;
|
|
136
|
+
stack?: string | undefined;
|
|
137
|
+
};
|
|
138
|
+
metadata?: Record<string, unknown> | undefined;
|
|
139
|
+
}>]>, z.ZodObject<{
|
|
140
|
+
timestamp: z.ZodString;
|
|
141
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
142
|
timestamp: string;
|
|
63
|
-
}
|
|
143
|
+
}, {
|
|
144
|
+
timestamp: string;
|
|
145
|
+
}>>, z.ZodObject<{
|
|
146
|
+
installationId: z.ZodString;
|
|
147
|
+
countryISOCode: z.ZodString;
|
|
148
|
+
}, "strip", z.ZodTypeAny, {
|
|
149
|
+
installationId: string;
|
|
150
|
+
countryISOCode: string;
|
|
151
|
+
}, {
|
|
152
|
+
installationId: string;
|
|
153
|
+
countryISOCode: string;
|
|
154
|
+
}>>;
|
|
155
|
+
type DispatchableEvent = z.infer<typeof DispatchableEventSchema>;
|
|
64
156
|
type RouteHandlerConfiguration = {
|
|
65
157
|
platformUrl?: string;
|
|
66
158
|
installationId: string;
|
|
67
159
|
maxMindClient: WebServiceClient;
|
|
68
160
|
};
|
|
69
161
|
declare const createRouteHandler: ({ platformUrl, installationId, maxMindClient, }: RouteHandlerConfiguration) => (request: NextRequest) => Promise<Response>;
|
|
70
|
-
|
|
162
|
+
type ConsumerConfiguration = {
|
|
163
|
+
enabled?: boolean;
|
|
164
|
+
endpoint?: string;
|
|
165
|
+
};
|
|
166
|
+
type EventTrackerReturn = {
|
|
167
|
+
error: string | null;
|
|
168
|
+
success: boolean;
|
|
169
|
+
};
|
|
170
|
+
declare const makeEventTracker: ({ enabled, endpoint }: ConsumerConfiguration) => (event: RawEvent) => Promise<EventTrackerReturn>;
|
|
71
171
|
|
|
72
|
-
export {
|
|
172
|
+
export { DispatchableEvent, DispatchableEventSchema, EventTrackerReturn, RawEvent, RawEventSchema, TrackableEvent, TrackableEventSchema, createRouteHandler, eventTypes, makeEventTracker };
|
package/dist/index.mjs
CHANGED
|
@@ -33,21 +33,41 @@ var eventTypes = [
|
|
|
33
33
|
"ProtocolInstalled",
|
|
34
34
|
"InterviewStarted",
|
|
35
35
|
"InterviewCompleted",
|
|
36
|
-
"DataExported"
|
|
37
|
-
"Error"
|
|
36
|
+
"DataExported"
|
|
38
37
|
];
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
var SharedEventAndErrorSchema = z.object({
|
|
39
|
+
metadata: z.record(z.unknown()).optional()
|
|
40
|
+
});
|
|
41
|
+
var EventSchema = z.object({
|
|
42
|
+
type: z.enum(eventTypes)
|
|
43
|
+
});
|
|
44
|
+
var ErrorSchema = z.object({
|
|
45
|
+
type: z.literal("Error"),
|
|
44
46
|
error: z.object({
|
|
45
47
|
message: z.string(),
|
|
46
48
|
name: z.string(),
|
|
47
49
|
stack: z.string().optional()
|
|
48
|
-
}).
|
|
49
|
-
metadata: z.record(z.unknown()).optional()
|
|
50
|
+
}).strict()
|
|
50
51
|
});
|
|
52
|
+
var RawEventSchema = z.discriminatedUnion("type", [
|
|
53
|
+
SharedEventAndErrorSchema.merge(EventSchema),
|
|
54
|
+
SharedEventAndErrorSchema.merge(ErrorSchema)
|
|
55
|
+
]);
|
|
56
|
+
var TrackablePropertiesSchema = z.object({
|
|
57
|
+
timestamp: z.string()
|
|
58
|
+
});
|
|
59
|
+
var TrackableEventSchema = z.intersection(
|
|
60
|
+
RawEventSchema,
|
|
61
|
+
TrackablePropertiesSchema
|
|
62
|
+
);
|
|
63
|
+
var DispatchablePropertiesSchema = z.object({
|
|
64
|
+
installationId: z.string(),
|
|
65
|
+
countryISOCode: z.string()
|
|
66
|
+
});
|
|
67
|
+
var DispatchableEventSchema = z.intersection(
|
|
68
|
+
TrackableEventSchema,
|
|
69
|
+
DispatchablePropertiesSchema
|
|
70
|
+
);
|
|
51
71
|
var createRouteHandler = ({
|
|
52
72
|
platformUrl = "https://analytics.networkcanvas.com",
|
|
53
73
|
installationId,
|
|
@@ -55,16 +75,31 @@ var createRouteHandler = ({
|
|
|
55
75
|
}) => {
|
|
56
76
|
return async (request) => {
|
|
57
77
|
try {
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
const incomingEvent = await request.json();
|
|
79
|
+
const trackableEvent = TrackableEventSchema.safeParse(incomingEvent);
|
|
80
|
+
if (!trackableEvent.success) {
|
|
81
|
+
console.error("Invalid event:", trackableEvent.error);
|
|
82
|
+
return new Response(JSON.stringify({ error: "Invalid event" }), {
|
|
83
|
+
status: 400,
|
|
84
|
+
headers: {
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
let countryISOCode = "Unknown";
|
|
90
|
+
try {
|
|
91
|
+
const ip = await fetch("https://api64.ipify.org").then(
|
|
92
|
+
(res) => res.text()
|
|
93
|
+
);
|
|
94
|
+
const { country } = await maxMindClient.country(ip);
|
|
95
|
+
countryISOCode = country?.isoCode ?? "Unknown";
|
|
96
|
+
} catch (e) {
|
|
97
|
+
console.error("Geolocation failed:", e);
|
|
98
|
+
}
|
|
64
99
|
const dispatchableEvent = {
|
|
65
|
-
...
|
|
100
|
+
...trackableEvent.data,
|
|
66
101
|
installationId,
|
|
67
|
-
|
|
102
|
+
countryISOCode
|
|
68
103
|
};
|
|
69
104
|
const response = await fetch(`${platformUrl}/api/event`, {
|
|
70
105
|
keepalive: true,
|
|
@@ -75,55 +110,45 @@ var createRouteHandler = ({
|
|
|
75
110
|
body: JSON.stringify(dispatchableEvent)
|
|
76
111
|
});
|
|
77
112
|
if (!response.ok) {
|
|
113
|
+
let error = `Analytics platform returned an unexpected error: ${response.statusText}`;
|
|
114
|
+
if (response.status === 400) {
|
|
115
|
+
error = `Analytics platform rejected the event as invalid. Please check the event schema`;
|
|
116
|
+
}
|
|
78
117
|
if (response.status === 404) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
console.error(
|
|
84
|
-
`Internal server error on analytics platform when forwarding event: ${response.statusText}.`
|
|
85
|
-
);
|
|
86
|
-
} else {
|
|
87
|
-
console.error(
|
|
88
|
-
`General error when forwarding event: ${response.statusText}`
|
|
89
|
-
);
|
|
118
|
+
error = `Analytics platform could not be reached. Please specify a valid platform URL, or check that the platform is online.`;
|
|
119
|
+
}
|
|
120
|
+
if (response.status === 500) {
|
|
121
|
+
error = `Analytics platform returned an internal server error. Please check the platform logs.`;
|
|
90
122
|
}
|
|
91
|
-
|
|
92
|
-
|
|
123
|
+
console.info("\u26A0\uFE0F Analytics platform rejected event.");
|
|
124
|
+
return Response.json(
|
|
93
125
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
}
|
|
126
|
+
error
|
|
127
|
+
},
|
|
128
|
+
{ status: 500 }
|
|
99
129
|
);
|
|
100
130
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
status: 200,
|
|
105
|
-
headers: {
|
|
106
|
-
"Content-Type": "application/json"
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
);
|
|
131
|
+
console.info("\u{1F680} Analytics event sent to platform!");
|
|
132
|
+
return Response.json({ message: "Event forwarded successfully" });
|
|
110
133
|
} catch (e) {
|
|
111
134
|
const error = ensureError(e);
|
|
112
|
-
console.
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
});
|
|
135
|
+
console.info("\u{1F6AB} Internal error with sending analytics event.");
|
|
136
|
+
return Response.json(
|
|
137
|
+
{ error: `Error in analytics route handler: ${error.message}` },
|
|
138
|
+
{ status: 500 }
|
|
139
|
+
);
|
|
119
140
|
}
|
|
120
141
|
};
|
|
121
142
|
};
|
|
122
|
-
var makeEventTracker = (endpoint = "/api/analytics") => async (event) => {
|
|
143
|
+
var makeEventTracker = ({ enabled = false, endpoint = "/api/analytics" }) => async (event) => {
|
|
144
|
+
if (!enabled) {
|
|
145
|
+
console.log("Analytics disabled, not sending event");
|
|
146
|
+
return { error: null, success: true };
|
|
147
|
+
}
|
|
123
148
|
const endpointWithHost = getBaseUrl() + endpoint;
|
|
124
149
|
const eventWithTimeStamp = {
|
|
125
150
|
...event,
|
|
126
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
151
|
+
timestamp: (/* @__PURE__ */ new Date()).toJSON()
|
|
127
152
|
};
|
|
128
153
|
try {
|
|
129
154
|
const response = await fetch(endpointWithHost, {
|
|
@@ -136,28 +161,35 @@ var makeEventTracker = (endpoint = "/api/analytics") => async (event) => {
|
|
|
136
161
|
});
|
|
137
162
|
if (!response.ok) {
|
|
138
163
|
if (response.status === 404) {
|
|
139
|
-
|
|
140
|
-
`Analytics endpoint not found, did you forget to add the route
|
|
141
|
-
|
|
142
|
-
|
|
164
|
+
return {
|
|
165
|
+
error: `Analytics endpoint not found, did you forget to add the route?`,
|
|
166
|
+
success: false
|
|
167
|
+
};
|
|
143
168
|
}
|
|
144
|
-
if (response.status ===
|
|
145
|
-
|
|
146
|
-
`
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
if (response.status === 400) {
|
|
170
|
+
return {
|
|
171
|
+
error: `Invalid event sent to analytics endpoint: ${response.statusText}`,
|
|
172
|
+
success: false
|
|
173
|
+
};
|
|
149
174
|
}
|
|
150
|
-
|
|
151
|
-
`
|
|
152
|
-
|
|
175
|
+
return {
|
|
176
|
+
error: `Internal server error when sending analytics event: ${response.statusText}. Check the route handler implementation.`,
|
|
177
|
+
success: false
|
|
178
|
+
};
|
|
153
179
|
}
|
|
180
|
+
return { error: null, success: true };
|
|
154
181
|
} catch (e) {
|
|
155
182
|
const error = ensureError(e);
|
|
156
|
-
|
|
183
|
+
return {
|
|
184
|
+
error: `Internal error when sending analytics event: ${error.message}`,
|
|
185
|
+
success: false
|
|
186
|
+
};
|
|
157
187
|
}
|
|
158
188
|
};
|
|
159
189
|
export {
|
|
160
|
-
|
|
190
|
+
DispatchableEventSchema,
|
|
191
|
+
RawEventSchema,
|
|
192
|
+
TrackableEventSchema,
|
|
161
193
|
createRouteHandler,
|
|
162
194
|
eventTypes,
|
|
163
195
|
makeEventTracker
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["// Helper function that ensures that a value is an Error\r\nexport function ensureError(value: unknown): Error {\r\n if (!value) return new Error(\"No value was thrown\");\r\n\r\n if (value instanceof Error) return value;\r\n\r\n // Test if value inherits from Error\r\n if (value.isPrototypeOf(Error)) return value as Error & typeof value;\r\n\r\n let stringified = \"[Unable to stringify the thrown value]\";\r\n try {\r\n stringified = JSON.stringify(value);\r\n } catch {}\r\n\r\n const error = new Error(\r\n `This value was thrown as is, not through an Error: ${stringified}`\r\n );\r\n return error;\r\n}\r\n\r\nexport function getBaseUrl() {\r\n if (typeof window !== \"undefined\")\r\n // browser should use relative path\r\n return \"\";\r\n\r\n if (process.env.VERCEL_URL)\r\n // reference for vercel.com\r\n return `https://${process.env.VERCEL_URL}`;\r\n\r\n if (process.env.NEXT_PUBLIC_URL)\r\n // Manually set deployment URL from env\r\n return process.env.NEXT_PUBLIC_URL;\r\n\r\n // assume localhost\r\n return `http://127.0.0.1:3000`;\r\n}\r\n","import type { NextRequest } from \"next/server\";\r\nimport { WebServiceClient } from \"@maxmind/geoip2-node\";\r\nimport { ensureError, getBaseUrl } from \"./utils\";\r\nimport z from \"zod\";\r\n\r\nexport const eventTypes = [\r\n \"AppSetup\",\r\n \"ProtocolInstalled\",\r\n \"InterviewStarted\",\r\n \"InterviewCompleted\",\r\n \"DataExported\",\r\n \"Error\",\r\n] as const;\r\n\r\nexport type EventType = (typeof eventTypes)[number];\r\ntype EventTypeWithoutError = Exclude<EventType, \"Error\">;\r\n\r\nexport const EventsSchema = z.object({\r\n type: z.enum(eventTypes),\r\n installationId: z.string(),\r\n timestamp: z.string(),\r\n isocode: z.string().optional(),\r\n error: z\r\n .object({\r\n message: z.string(),\r\n name: z.string(),\r\n stack: z.string().optional(),\r\n })\r\n .optional(),\r\n metadata: z.record(z.unknown()).optional(),\r\n});\r\n\r\nexport type Event = z.infer<typeof EventsSchema>;\r\n\r\nexport type AnalyticsEvent = {\r\n type: EventTypeWithoutError;\r\n metadata?: Record<string, unknown>;\r\n};\r\n\r\nexport type AnalyticsError = {\r\n type: \"Error\";\r\n error: Error;\r\n metadata?: Record<string, unknown>;\r\n};\r\n\r\nexport type AnalyticsEventOrError = AnalyticsEvent | AnalyticsError;\r\n\r\nexport type AnalyticsEventOrErrorWithTimestamp = AnalyticsEventOrError & {\r\n timestamp: string;\r\n};\r\n\r\ntype RouteHandlerConfiguration = {\r\n platformUrl?: string;\r\n installationId: string;\r\n maxMindClient: WebServiceClient;\r\n};\r\n\r\nexport const createRouteHandler = ({\r\n platformUrl = \"https://analytics.networkcanvas.com\",\r\n installationId,\r\n maxMindClient,\r\n}: RouteHandlerConfiguration) => {\r\n return async (request: NextRequest) => {\r\n try {\r\n const event =\r\n (await request.json()) as AnalyticsEventOrErrorWithTimestamp;\r\n\r\n const ip = await fetch(\"https://api64.ipify.org\").then((res) =>\r\n res.text()\r\n );\r\n\r\n const { country } = await maxMindClient.country(ip);\r\n const countryCode = country?.isoCode ?? \"Unknown\";\r\n\r\n const dispatchableEvent: Event = {\r\n ...event,\r\n installationId,\r\n isocode: countryCode,\r\n };\r\n\r\n // Forward to microservice\r\n const response = await fetch(`${platformUrl}/api/event`, {\r\n keepalive: true,\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(dispatchableEvent),\r\n });\r\n\r\n if (!response.ok) {\r\n if (response.status === 404) {\r\n console.error(\r\n `Analytics platform not found. Please specify a valid platform URL.`\r\n );\r\n } else if (response.status === 500) {\r\n console.error(\r\n `Internal server error on analytics platform when forwarding event: ${response.statusText}.`\r\n );\r\n } else {\r\n console.error(\r\n `General error when forwarding event: ${response.statusText}`\r\n );\r\n }\r\n\r\n return new Response(\r\n JSON.stringify({ error: \"Internal Server Error\" }),\r\n {\r\n status: 500,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n }\r\n );\r\n }\r\n\r\n return new Response(\r\n JSON.stringify({ message: \"Event forwarded successfully\" }),\r\n {\r\n status: 200,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n }\r\n );\r\n } catch (e) {\r\n const error = ensureError(e);\r\n console.error(\"Error in route handler:\", error);\r\n\r\n // Return an appropriate error response\r\n return new Response(JSON.stringify({ error: \"Internal Server Error\" }), {\r\n status: 500,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n });\r\n }\r\n };\r\n};\r\n\r\nexport const makeEventTracker =\r\n (endpoint: string = \"/api/analytics\") =>\r\n async (event: AnalyticsEventOrError) => {\r\n const endpointWithHost = getBaseUrl() + endpoint;\r\n\r\n const eventWithTimeStamp = {\r\n ...event,\r\n timestamp: new Date(),\r\n };\r\n\r\n try {\r\n const response = await fetch(endpointWithHost, {\r\n method: \"POST\",\r\n keepalive: true,\r\n body: JSON.stringify(eventWithTimeStamp),\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n if (response.status === 404) {\r\n console.error(\r\n `Analytics endpoint not found, did you forget to add the route?`\r\n );\r\n return;\r\n }\r\n\r\n if (response.status === 500) {\r\n console.error(\r\n `Internal server error when sending analytics event: ${response.statusText}. Check the route handler implementation.`\r\n );\r\n return;\r\n }\r\n\r\n console.error(\r\n `General error sending analytics event: ${response.statusText}`\r\n );\r\n }\r\n } catch (e) {\r\n const error = ensureError(e);\r\n\r\n console.error(\"Internal error with analytics:\", error.message);\r\n }\r\n };\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["// Helper function that ensures that a value is an Error\nexport function ensureError(value: unknown): Error {\n if (!value) return new Error(\"No value was thrown\");\n\n if (value instanceof Error) return value;\n\n // Test if value inherits from Error\n if (value.isPrototypeOf(Error)) return value as Error & typeof value;\n\n let stringified = \"[Unable to stringify the thrown value]\";\n try {\n stringified = JSON.stringify(value);\n } catch {}\n\n const error = new Error(\n `This value was thrown as is, not through an Error: ${stringified}`\n );\n return error;\n}\n\nexport function getBaseUrl() {\n if (typeof window !== \"undefined\")\n // browser should use relative path\n return \"\";\n\n if (process.env.VERCEL_URL)\n // reference for vercel.com\n return `https://${process.env.VERCEL_URL}`;\n\n if (process.env.NEXT_PUBLIC_URL)\n // Manually set deployment URL from env\n return process.env.NEXT_PUBLIC_URL;\n\n // assume localhost\n return `http://127.0.0.1:3000`;\n}\n","import { type NextRequest } from \"next/server\";\nimport { WebServiceClient } from \"@maxmind/geoip2-node\";\nimport { ensureError, getBaseUrl } from \"./utils\";\nimport z from \"zod\";\n\n// Todo: it would be great to work out a way to support arbitrary types here.\nexport const eventTypes = [\n \"AppSetup\",\n \"ProtocolInstalled\",\n \"InterviewStarted\",\n \"InterviewCompleted\",\n \"DataExported\",\n] as const;\n\n// Properties that everything has in common.\nconst SharedEventAndErrorSchema = z.object({\n metadata: z.record(z.unknown()).optional(),\n});\n\nconst EventSchema = z.object({\n type: z.enum(eventTypes),\n});\n\nconst ErrorSchema = z.object({\n type: z.literal(\"Error\"),\n error: z\n .object({\n message: z.string(),\n name: z.string(),\n stack: z.string().optional(),\n })\n .strict(),\n});\n\n// Raw events are the events that are sent trackEvent.\nexport const RawEventSchema = z.discriminatedUnion(\"type\", [\n SharedEventAndErrorSchema.merge(EventSchema),\n SharedEventAndErrorSchema.merge(ErrorSchema),\n]);\nexport type RawEvent = z.infer<typeof RawEventSchema>;\n\n// Trackable events are the events that are sent to the route handler.\nconst TrackablePropertiesSchema = z.object({\n timestamp: z.string(),\n});\n\nexport const TrackableEventSchema = z.intersection(\n RawEventSchema,\n TrackablePropertiesSchema\n);\nexport type TrackableEvent = z.infer<typeof TrackableEventSchema>;\n\n// Dispatchable events are the events that are sent to the platform.\nconst DispatchablePropertiesSchema = z.object({\n installationId: z.string(),\n countryISOCode: z.string(),\n});\n\nexport const DispatchableEventSchema = z.intersection(\n TrackableEventSchema,\n DispatchablePropertiesSchema\n);\nexport type DispatchableEvent = z.infer<typeof DispatchableEventSchema>;\n\ntype RouteHandlerConfiguration = {\n platformUrl?: string;\n installationId: string;\n maxMindClient: WebServiceClient;\n};\n\nexport const createRouteHandler = ({\n platformUrl = \"https://analytics.networkcanvas.com\",\n installationId,\n maxMindClient,\n}: RouteHandlerConfiguration) => {\n return async (request: NextRequest) => {\n try {\n const incomingEvent = (await request.json()) as unknown;\n\n // Validate the event\n const trackableEvent = TrackableEventSchema.safeParse(incomingEvent);\n\n if (!trackableEvent.success) {\n console.error(\"Invalid event:\", trackableEvent.error);\n return new Response(JSON.stringify({ error: \"Invalid event\" }), {\n status: 400,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n }\n\n // We don't want failures in third party services to prevent us from\n // tracking analytics events.\n let countryISOCode = \"Unknown\";\n try {\n const ip = await fetch(\"https://api64.ipify.org\").then((res) =>\n res.text()\n );\n const { country } = await maxMindClient.country(ip);\n countryISOCode = country?.isoCode ?? \"Unknown\";\n } catch (e) {\n console.error(\"Geolocation failed:\", e);\n }\n\n const dispatchableEvent: DispatchableEvent = {\n ...trackableEvent.data,\n installationId,\n countryISOCode,\n };\n\n // Forward to microservice\n const response = await fetch(`${platformUrl}/api/event`, {\n keepalive: true,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(dispatchableEvent),\n });\n\n if (!response.ok) {\n let error = `Analytics platform returned an unexpected error: ${response.statusText}`;\n\n if (response.status === 400) {\n error = `Analytics platform rejected the event as invalid. Please check the event schema`;\n }\n\n if (response.status === 404) {\n error = `Analytics platform could not be reached. Please specify a valid platform URL, or check that the platform is online.`;\n }\n\n if (response.status === 500) {\n error = `Analytics platform returned an internal server error. Please check the platform logs.`;\n }\n\n console.info(\"⚠️ Analytics platform rejected event.\");\n return Response.json(\n {\n error,\n },\n { status: 500 }\n );\n }\n console.info(\"🚀 Analytics event sent to platform!\");\n return Response.json({ message: \"Event forwarded successfully\" });\n } catch (e) {\n const error = ensureError(e);\n console.info(\"🚫 Internal error with sending analytics event.\");\n\n return Response.json(\n { error: `Error in analytics route handler: ${error.message}` },\n { status: 500 }\n );\n }\n };\n};\n\ntype ConsumerConfiguration = {\n enabled?: boolean;\n endpoint?: string;\n};\n\nexport type EventTrackerReturn = {\n error: string | null;\n success: boolean;\n};\n\nexport const makeEventTracker =\n ({ enabled = false, endpoint = \"/api/analytics\" }: ConsumerConfiguration) =>\n async (event: RawEvent): Promise<EventTrackerReturn> => {\n // If analytics is disabled don't send analytics events.\n if (!enabled) {\n console.log(\"Analytics disabled, not sending event\");\n return { error: null, success: true };\n }\n\n const endpointWithHost = getBaseUrl() + endpoint;\n\n const eventWithTimeStamp: TrackableEvent = {\n ...event,\n timestamp: new Date().toJSON(),\n };\n\n try {\n const response = await fetch(endpointWithHost, {\n method: \"POST\",\n keepalive: true,\n body: JSON.stringify(eventWithTimeStamp),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return {\n error: `Analytics endpoint not found, did you forget to add the route?`,\n success: false,\n };\n }\n\n // createRouteHandler will return a 400 if the event failed schema validation.\n if (response.status === 400) {\n return {\n error: `Invalid event sent to analytics endpoint: ${response.statusText}`,\n success: false,\n };\n }\n\n // createRouteHandler will return a 500 for all error states\n return {\n error: `Internal server error when sending analytics event: ${response.statusText}. Check the route handler implementation.`,\n success: false,\n };\n }\n\n return { error: null, success: true };\n } catch (e) {\n const error = ensureError(e);\n return {\n error: `Internal error when sending analytics event: ${error.message}`,\n success: false,\n };\n }\n };\n"],"mappings":"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","names":[]}
|