diff --git a/libs/jitsu-js/src/analytics-plugin.ts b/libs/jitsu-js/src/analytics-plugin.ts index 42b1be653..6c3a637eb 100644 --- a/libs/jitsu-js/src/analytics-plugin.ts +++ b/libs/jitsu-js/src/analytics-plugin.ts @@ -10,6 +10,7 @@ import { ID, JSONObject, Options, + ErrorHandler, } from "@jitsu/protocols/analytics"; import parse from "./index"; @@ -35,6 +36,7 @@ const defaultConfig: Required = { fetchTimeoutMs: undefined, s2s: undefined, idEndpoint: undefined, + errorPolicy: "log", privacy: { dontSend: false, disableUserIds: false, @@ -628,6 +630,22 @@ function maskWriteKey(writeKey?: string): string | undefined { return writeKey; } +function getErrorHandler(opts: JitsuOptions): ErrorHandler { + const configuredHandler = opts.errorPolicy || "log"; + if (typeof configuredHandler === "function") { + return configuredHandler; + } else if (configuredHandler === "rethrow") { + return e => { + throw e; + }; + } else { + //"log" and unsupported value + return e => { + console.error(`[JITSU ERROR] ${e?.message || e?.toString() || "unknown error"}`, e); + }; + } +} + async function send( method, payload, @@ -643,6 +661,7 @@ async function send( const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`; const fetch = jitsuConfig.fetch || globalThis.fetch; if (!fetch) { + //don't run it through error handler since error is critical and should be addressed throw new Error( "Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope" ); @@ -682,7 +701,8 @@ async function send( clearTimeout(abortTimeout); } } catch (e: any) { - throw new Error(`Calling ${url} failed: ${e.message}`); + getErrorHandler(jitsuConfig)(new Error(`Calling ${url} failed: ${e.message}`)); + return Promise.resolve(); } let responseText; try { @@ -709,7 +729,8 @@ async function send( try { responseJson = JSON.parse(responseText); } catch (e) { - return Promise.reject(`Can't parse JSON: ${responseText}: ${e?.message}`); + getErrorHandler(jitsuConfig)(new Error(`Can't parse JSON: ${responseText}: ${e?.message}`)); + return Promise.resolve(); } if (responseJson.destinations && responseJson.destinations.length > 0) { diff --git a/package.json b/package.json index 8557f9574..bf9ff08f9 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "console:dev": "dotenv -e .env.local -- turbo run console:dev", "console:storybook": "dotenv -e .env.local -- turbo run console:storybook", "rotor:dev": "dotenv -e .env.local -- turbo run rotor:dev", - "console:start": "dotenv -e .env.local -- pnpm run --filter=console console:start", + "console:start": "dotenv -e .env.local -- turbo run console:start", "console:db-prepare": "dotenv -e .env.local -- pnpm run --filter=console db:update-schema", "console:db-prepare-force": "dotenv -e .env.local -- pnpm run --filter=console db:update-schema-force", "dev": "dotenv -e .env.local -- turbo run dev", diff --git a/types/protocols/analytics.d.ts b/types/protocols/analytics.d.ts index 5247e41db..98c6d88ed 100644 --- a/types/protocols/analytics.d.ts +++ b/types/protocols/analytics.d.ts @@ -316,6 +316,8 @@ export type RuntimeFacade = { pageTitle(): string | undefined; }; +export type ErrorHandler = (error: any) => void; + export type JitsuOptions = { /** * API Key. Optional. If not set, Jitsu will send event to the server without auth, and server @@ -372,6 +374,11 @@ export type JitsuOptions = { */ idEndpoint?: string; + /** + * What to do with errors. It can log it, rethrow or run a custom handler. Default value: "log" + */ + errorPolicy?: ErrorHandler | "rethrow" | "log"; + privacy?: { dontSend?: boolean; disableUserIds?: boolean; diff --git a/webapps/console/package.json b/webapps/console/package.json index 6ee276da5..1fbdfbf88 100644 --- a/webapps/console/package.json +++ b/webapps/console/package.json @@ -12,8 +12,8 @@ "prisma": "prisma", "lint": "next lint", "console:dev": "next dev", - "dev:rotor": "ts-node service/rotor.ts", "console:start": "next start", + "dev:rotor": "ts-node service/rotor.ts", "build": "prisma generate && next build", "clean": "rm -rf ./.next ./.turbo", "compile": "tsc -p .",