@codaco/analytics 3.1.0 → 5.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 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
+ };
@@ -1,16 +1,17 @@
1
-
2
- > @codaco/analytics@2.0.0 build D:\Projects\Network Canvas\error-analytics-microservice\packages\analytics
3
- > tsup src/index.ts --format esm --dts --clean --sourcemap
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v7.2.0
8
- CLI Target: es2022
9
- CLI Cleaning output folder
10
- ESM Build start
11
- ESM dist\index.mjs 4.06 KB
12
- ESM dist\index.mjs.map 8.81 KB
13
- ESM ⚡️ Build success in 17ms
14
- DTS Build start
15
- DTS ⚡️ Build success in 1007ms
16
- DTS dist\index.d.mts 1.38 KB
1
+
2
+ 
3
+ > @codaco/analytics@5.0.0 build /Users/jmh629/Projects/error-analytics-microservice/packages/analytics
4
+ > tsup src/index.ts --format esm --dts --clean --sourcemap
5
+
6
+ CLI Building entry: src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v7.3.0
9
+ CLI Target: es2022
10
+ CLI Cleaning output folder
11
+ ESM Build start
12
+ ESM dist/index.js 5.77 KB
13
+ ESM dist/index.js.map 11.87 KB
14
+ ESM ⚡️ Build success in 18ms
15
+ DTS Build start
16
+ DTS ⚡️ Build success in 907ms
17
+ DTS dist/index.d.ts 5.64 KB
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.
@@ -0,0 +1,146 @@
1
+ import { NextRequest } from 'next/server';
2
+ import { WebServiceClient } from '@maxmind/geoip2-node';
3
+ import z from 'zod';
4
+
5
+ declare const eventTypes: readonly ["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"];
6
+ /**
7
+ * Raw events are the events that are sent trackEvent. They are either general
8
+ * events or errors. We discriminate on the `type` property to determine which
9
+ * schema to use, and then merge the shared properties.
10
+ */
11
+ declare const RawEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
12
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
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<{
21
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
22
+ type: z.ZodLiteral<"Error">;
23
+ message: z.ZodString;
24
+ name: z.ZodString;
25
+ stack: z.ZodOptional<z.ZodString>;
26
+ cause: z.ZodOptional<z.ZodString>;
27
+ }, "strip", z.ZodTypeAny, {
28
+ type: "Error";
29
+ message: string;
30
+ name: string;
31
+ metadata?: Record<string, unknown> | undefined;
32
+ stack?: string | undefined;
33
+ cause?: string | undefined;
34
+ }, {
35
+ type: "Error";
36
+ message: string;
37
+ name: string;
38
+ metadata?: Record<string, unknown> | undefined;
39
+ stack?: string | undefined;
40
+ cause?: string | undefined;
41
+ }>]>;
42
+ type RawEvent = z.infer<typeof RawEventSchema>;
43
+ declare const TrackableEventSchema: z.ZodIntersection<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
44
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
45
+ type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
48
+ metadata?: Record<string, unknown> | undefined;
49
+ }, {
50
+ type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
51
+ metadata?: Record<string, unknown> | undefined;
52
+ }>, z.ZodObject<{
53
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
54
+ type: z.ZodLiteral<"Error">;
55
+ message: z.ZodString;
56
+ name: z.ZodString;
57
+ stack: z.ZodOptional<z.ZodString>;
58
+ cause: z.ZodOptional<z.ZodString>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ type: "Error";
61
+ message: string;
62
+ name: string;
63
+ metadata?: Record<string, unknown> | undefined;
64
+ stack?: string | undefined;
65
+ cause?: string | undefined;
66
+ }, {
67
+ type: "Error";
68
+ message: string;
69
+ name: string;
70
+ metadata?: Record<string, unknown> | undefined;
71
+ stack?: string | undefined;
72
+ cause?: string | undefined;
73
+ }>]>, z.ZodObject<{
74
+ timestamp: z.ZodString;
75
+ }, "strip", z.ZodTypeAny, {
76
+ timestamp: string;
77
+ }, {
78
+ timestamp: string;
79
+ }>>;
80
+ type TrackableEvent = z.infer<typeof TrackableEventSchema>;
81
+ /**
82
+ * The final schema for an analytics event. This is the schema that is used to
83
+ * validate the event before it is inserted into the database. It is the
84
+ * intersection of the trackable event and the dispatchable properties.
85
+ */
86
+ declare const AnalyticsEventSchema: z.ZodIntersection<z.ZodIntersection<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
87
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
88
+ type: z.ZodEnum<["AppSetup", "ProtocolInstalled", "InterviewStarted", "InterviewCompleted", "DataExported"]>;
89
+ }, "strip", z.ZodTypeAny, {
90
+ type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
91
+ metadata?: Record<string, unknown> | undefined;
92
+ }, {
93
+ type: "AppSetup" | "ProtocolInstalled" | "InterviewStarted" | "InterviewCompleted" | "DataExported";
94
+ metadata?: Record<string, unknown> | undefined;
95
+ }>, z.ZodObject<{
96
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
97
+ type: z.ZodLiteral<"Error">;
98
+ message: z.ZodString;
99
+ name: z.ZodString;
100
+ stack: z.ZodOptional<z.ZodString>;
101
+ cause: z.ZodOptional<z.ZodString>;
102
+ }, "strip", z.ZodTypeAny, {
103
+ type: "Error";
104
+ message: string;
105
+ name: string;
106
+ metadata?: Record<string, unknown> | undefined;
107
+ stack?: string | undefined;
108
+ cause?: string | undefined;
109
+ }, {
110
+ type: "Error";
111
+ message: string;
112
+ name: string;
113
+ metadata?: Record<string, unknown> | undefined;
114
+ stack?: string | undefined;
115
+ cause?: string | undefined;
116
+ }>]>, z.ZodObject<{
117
+ timestamp: z.ZodString;
118
+ }, "strip", z.ZodTypeAny, {
119
+ timestamp: string;
120
+ }, {
121
+ timestamp: string;
122
+ }>>, z.ZodObject<{
123
+ installationId: z.ZodString;
124
+ countryISOCode: z.ZodString;
125
+ }, "strip", z.ZodTypeAny, {
126
+ installationId: string;
127
+ countryISOCode: string;
128
+ }, {
129
+ installationId: string;
130
+ countryISOCode: string;
131
+ }>>;
132
+ type analyticsEvent = z.infer<typeof AnalyticsEventSchema>;
133
+ declare const createRouteHandler: ({ platformUrl, installationId, maxMindClient, }: {
134
+ platformUrl?: string | undefined;
135
+ installationId: string;
136
+ maxMindClient: WebServiceClient;
137
+ }) => (request: NextRequest) => Promise<Response>;
138
+ declare const makeEventTracker: ({ enabled, endpoint, }: {
139
+ enabled?: boolean | undefined;
140
+ endpoint?: string | undefined;
141
+ }) => (event: RawEvent) => Promise<{
142
+ error: string | null;
143
+ success: boolean;
144
+ }>;
145
+
146
+ export { AnalyticsEventSchema, type RawEvent, RawEventSchema, type TrackableEvent, TrackableEventSchema, type analyticsEvent, createRouteHandler, eventTypes, makeEventTracker };
package/dist/index.js ADDED
@@ -0,0 +1,202 @@
1
+ // src/utils.ts
2
+ function ensureError(value) {
3
+ if (!value)
4
+ return new Error("No value was thrown");
5
+ if (value instanceof Error)
6
+ return value;
7
+ if (value.isPrototypeOf(Error))
8
+ return value;
9
+ let stringified = "[Unable to stringify the thrown value]";
10
+ try {
11
+ stringified = JSON.stringify(value);
12
+ } catch {
13
+ }
14
+ const error = new Error(
15
+ `This value was thrown as is, not through an Error: ${stringified}`
16
+ );
17
+ return error;
18
+ }
19
+ function getBaseUrl() {
20
+ if (typeof window !== "undefined")
21
+ return "";
22
+ if (process.env.VERCEL_URL)
23
+ return `https://${process.env.VERCEL_URL}`;
24
+ if (process.env.NEXT_PUBLIC_URL)
25
+ return process.env.NEXT_PUBLIC_URL;
26
+ return `http://127.0.0.1:3000`;
27
+ }
28
+
29
+ // src/index.ts
30
+ import z from "zod";
31
+ var eventTypes = [
32
+ "AppSetup",
33
+ "ProtocolInstalled",
34
+ "InterviewStarted",
35
+ "InterviewCompleted",
36
+ "DataExported"
37
+ ];
38
+ var EventSchema = z.object({
39
+ type: z.enum(eventTypes)
40
+ });
41
+ var ErrorSchema = z.object({
42
+ type: z.literal("Error"),
43
+ message: z.string(),
44
+ name: z.string(),
45
+ stack: z.string().optional(),
46
+ cause: z.string().optional()
47
+ });
48
+ var SharedEventAndErrorSchema = z.object({
49
+ metadata: z.record(z.unknown()).optional()
50
+ });
51
+ var RawEventSchema = z.discriminatedUnion("type", [
52
+ SharedEventAndErrorSchema.merge(EventSchema),
53
+ SharedEventAndErrorSchema.merge(ErrorSchema)
54
+ ]);
55
+ var TrackablePropertiesSchema = z.object({
56
+ timestamp: z.string()
57
+ });
58
+ var TrackableEventSchema = z.intersection(
59
+ RawEventSchema,
60
+ TrackablePropertiesSchema
61
+ );
62
+ var DispatchablePropertiesSchema = z.object({
63
+ installationId: z.string(),
64
+ countryISOCode: z.string()
65
+ });
66
+ var AnalyticsEventSchema = z.intersection(
67
+ TrackableEventSchema,
68
+ DispatchablePropertiesSchema
69
+ );
70
+ var createRouteHandler = ({
71
+ platformUrl = "https://analytics.networkcanvas.com",
72
+ installationId,
73
+ maxMindClient
74
+ }) => {
75
+ return async (request) => {
76
+ try {
77
+ const incomingEvent = await request.json();
78
+ const trackableEvent = TrackableEventSchema.safeParse(incomingEvent);
79
+ if (!trackableEvent.success) {
80
+ console.error("Invalid event:", trackableEvent.error);
81
+ return new Response(JSON.stringify({ error: "Invalid event" }), {
82
+ status: 400,
83
+ headers: {
84
+ "Content-Type": "application/json"
85
+ }
86
+ });
87
+ }
88
+ let countryISOCode = "Unknown";
89
+ try {
90
+ const ip = await fetch("https://api64.ipify.org").then(
91
+ (res) => res.text()
92
+ );
93
+ if (!ip) {
94
+ throw new Error("Could not fetch IP address");
95
+ }
96
+ const { country } = await maxMindClient.country(ip);
97
+ countryISOCode = country?.isoCode ?? "Unknown";
98
+ } catch (e) {
99
+ console.error("Geolocation failed:", e);
100
+ }
101
+ const analyticsEvent = {
102
+ ...trackableEvent.data,
103
+ installationId,
104
+ countryISOCode
105
+ };
106
+ const response = await fetch(`${platformUrl}/api/event`, {
107
+ keepalive: true,
108
+ method: "POST",
109
+ headers: {
110
+ "Content-Type": "application/json"
111
+ },
112
+ body: JSON.stringify(analyticsEvent)
113
+ });
114
+ if (!response.ok) {
115
+ let error = `Analytics platform returned an unexpected error: ${response.statusText}`;
116
+ if (response.status === 400) {
117
+ error = `Analytics platform rejected the event as invalid. Please check the event schema`;
118
+ }
119
+ if (response.status === 404) {
120
+ error = `Analytics platform could not be reached. Please specify a valid platform URL, or check that the platform is online.`;
121
+ }
122
+ if (response.status === 500) {
123
+ error = `Analytics platform returned an internal server error. Please check the platform logs.`;
124
+ }
125
+ console.info(`\u26A0\uFE0F Analytics platform rejected event: ${error}`);
126
+ return Response.json(
127
+ {
128
+ error
129
+ },
130
+ { status: 500 }
131
+ );
132
+ }
133
+ console.info("\u{1F680} Analytics event sent to platform!");
134
+ return Response.json({ message: "Event forwarded successfully" });
135
+ } catch (e) {
136
+ const error = ensureError(e);
137
+ console.info("\u{1F6AB} Internal error with sending analytics event.");
138
+ return Response.json(
139
+ { error: `Error in analytics route handler: ${error.message}` },
140
+ { status: 500 }
141
+ );
142
+ }
143
+ };
144
+ };
145
+ var makeEventTracker = ({
146
+ enabled = false,
147
+ endpoint = "/api/analytics"
148
+ }) => async (event) => {
149
+ if (!enabled) {
150
+ console.log("Analytics disabled - event not sent.");
151
+ return { error: null, success: true };
152
+ }
153
+ const endpointWithHost = getBaseUrl() + endpoint;
154
+ const eventWithTimeStamp = {
155
+ ...event,
156
+ timestamp: (/* @__PURE__ */ new Date()).toJSON()
157
+ };
158
+ try {
159
+ const response = await fetch(endpointWithHost, {
160
+ method: "POST",
161
+ keepalive: true,
162
+ body: JSON.stringify(eventWithTimeStamp),
163
+ headers: {
164
+ "Content-Type": "application/json"
165
+ }
166
+ });
167
+ if (!response.ok) {
168
+ if (response.status === 404) {
169
+ return {
170
+ error: `Analytics endpoint not found, did you forget to add the route?`,
171
+ success: false
172
+ };
173
+ }
174
+ if (response.status === 400) {
175
+ return {
176
+ error: `Invalid event sent to analytics endpoint: ${response.statusText}`,
177
+ success: false
178
+ };
179
+ }
180
+ return {
181
+ error: `Internal server error when sending analytics event: ${response.statusText}. Check the route handler implementation.`,
182
+ success: false
183
+ };
184
+ }
185
+ return { error: null, success: true };
186
+ } catch (e) {
187
+ const error = ensureError(e);
188
+ return {
189
+ error: `Internal error when sending analytics event: ${error.message}`,
190
+ success: false
191
+ };
192
+ }
193
+ };
194
+ export {
195
+ AnalyticsEventSchema,
196
+ RawEventSchema,
197
+ TrackableEventSchema,
198
+ createRouteHandler,
199
+ eventTypes,
200
+ makeEventTracker
201
+ };
202
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
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\nconst EventSchema = z.object({\n type: z.enum(eventTypes),\n});\n\nconst ErrorSchema = z.object({\n type: z.literal(\"Error\"),\n message: z.string(),\n name: z.string(),\n stack: z.string().optional(),\n cause: z.string().optional(),\n});\n\nconst SharedEventAndErrorSchema = z.object({\n metadata: z.record(z.unknown()).optional(),\n});\n\n/**\n * Raw events are the events that are sent trackEvent. They are either general\n * events or errors. We discriminate on the `type` property to determine which\n * schema to use, and then merge the shared properties.\n */\nexport const RawEventSchema = z.discriminatedUnion(\"type\", [\n SharedEventAndErrorSchema.merge(EventSchema),\n SharedEventAndErrorSchema.merge(ErrorSchema),\n]);\nexport type RawEvent = z.infer<typeof RawEventSchema>;\n\n/**\n * Trackable events are the events that are sent to the route handler. The\n * `trackEvent` function adds the timestamp to ensure it is not inaccurate\n * due to network latency or processing time.\n */\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/**\n * Dispatchable events are the events that are sent to the platform. The route\n * handler injects the installationId and countryISOCode properties.\n */\nconst DispatchablePropertiesSchema = z.object({\n installationId: z.string(),\n countryISOCode: z.string(),\n});\n\n/**\n * The final schema for an analytics event. This is the schema that is used to\n * validate the event before it is inserted into the database. It is the\n * intersection of the trackable event and the dispatchable properties.\n */\nexport const AnalyticsEventSchema = z.intersection(\n TrackableEventSchema,\n DispatchablePropertiesSchema\n);\nexport type analyticsEvent = z.infer<typeof AnalyticsEventSchema>;\n\nexport const createRouteHandler = ({\n platformUrl = \"https://analytics.networkcanvas.com\",\n installationId,\n maxMindClient,\n}: {\n platformUrl?: string;\n installationId: string;\n maxMindClient: WebServiceClient;\n}) => {\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, so we'll catch any errors and log them\n // and continue with an 'Unknown' country code.\n let countryISOCode = \"Unknown\";\n try {\n const ip = await fetch(\"https://api64.ipify.org\").then((res) =>\n res.text()\n );\n\n if (!ip) {\n throw new Error(\"Could not fetch IP address\");\n }\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 analyticsEvent: analyticsEvent = {\n ...trackableEvent.data,\n installationId,\n countryISOCode,\n };\n\n // Forward to backend\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(analyticsEvent),\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: ${error}`);\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\nexport const makeEventTracker =\n ({\n enabled = false,\n endpoint = \"/api/analytics\",\n }: {\n enabled?: boolean;\n endpoint?: string;\n }) =>\n async (\n event: RawEvent\n ): Promise<{\n error: string | null;\n success: boolean;\n }> => {\n if (!enabled) {\n console.log(\"Analytics disabled - event not sent.\");\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":[]}
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@codaco/analytics",
3
- "version": "3.1.0",
4
- "module": "./dist/index.mjs",
5
- "types": "./dist/index.d.mts",
3
+ "version": "5.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
6
7
  "author": "Complex Data Collective <developers@coda.co>",
7
8
  "description": "Utilities for tracking analytics and error reporting in Fresco",
8
9
  "scripts": {