From 0c1c3d8ed62a035a2947f00664a5afab20626822 Mon Sep 17 00:00:00 2001 From: vklimontovich Date: Wed, 13 May 2026 17:13:51 -0400 Subject: [PATCH 1/2] fix(core): make callbacks config optional Crash on `Nextlytics({ backends: [...] })` without `callbacks`: `TypeError: Cannot read properties of undefined (reading 'getUser')`. README and quickstart treat callbacks as optional, but the type required it and `withDefaults` did not provide a default, so `server.tsx` and `api-handler.ts` dereferenced `undefined`. - Mark `callbacks` optional on `NextlyticsConfig`. - Default it to `{}` in `withDefaults` so internal access stays simple. --- packages/core/src/config-helpers.test.ts | 15 +++++++++++++++ packages/core/src/config-helpers.ts | 2 ++ packages/core/src/types.ts | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/config-helpers.test.ts diff --git a/packages/core/src/config-helpers.test.ts b/packages/core/src/config-helpers.test.ts new file mode 100644 index 0000000..aaf03a9 --- /dev/null +++ b/packages/core/src/config-helpers.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from "vitest"; +import { withDefaults } from "./config-helpers"; + +describe("withDefaults", () => { + it("defaults callbacks to an empty object when omitted", () => { + const result = withDefaults({}); + expect(result.callbacks).toEqual({}); + }); + + it("preserves user-provided callbacks", () => { + const getUser = async () => undefined; + const result = withDefaults({ callbacks: { getUser } }); + expect(result.callbacks.getUser).toBe(getUser); + }); +}); diff --git a/packages/core/src/config-helpers.ts b/packages/core/src/config-helpers.ts index 9fcf505..9c56b44 100644 --- a/packages/core/src/config-helpers.ts +++ b/packages/core/src/config-helpers.ts @@ -5,6 +5,7 @@ export type NextlyticsConfigWithDefaults = Required< > & NextlyticsConfig & { anonymousUsers: Required>; + callbacks: NonNullable; }; export function withDefaults(config: NextlyticsConfig): NextlyticsConfigWithDefaults { @@ -14,6 +15,7 @@ export function withDefaults(config: NextlyticsConfig): NextlyticsConfigWithDefa eventEndpoint: config.eventEndpoint ?? "/api/event", isApiPath: config.isApiPath ?? ((str: string) => str.startsWith("/api")), backends: config.backends ?? [], + callbacks: config.callbacks ?? {}, anonymousUsers: { gdprMode: config.anonymousUsers?.gdprMode ?? true, useCookies: config.anonymousUsers?.useCookies ?? false, diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 0632fa3..7732fc8 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -164,7 +164,7 @@ export type NextlyticsConfig = { isApiPath?: (path: string) => boolean; /** Endpoint for client events. Default: "/api/event" */ eventEndpoint?: string; - callbacks: { + callbacks?: { /** Resolve authenticated user from request context */ getUser?: (ctx: RequestContext) => Promise; /** Override anonymous user ID generation */ From 1d39c6fb5e403e975db48ff15efe3ca4eb90bf1c Mon Sep 17 00:00:00 2001 From: vklimontovich Date: Wed, 13 May 2026 17:21:14 -0400 Subject: [PATCH 2/2] chore: format server.tsx (prettier) --- packages/core/src/server.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/src/server.tsx b/packages/core/src/server.tsx index f6a2e33..a00c99f 100644 --- a/packages/core/src/server.tsx +++ b/packages/core/src/server.tsx @@ -245,7 +245,9 @@ export function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult { if (!ctx) { // x-nl-page-render-id absent → check if middleware is at least active if (!headersList.get(headerNames.active)) { - console.warn("[Nextlytics] nextlyticsMiddleware should be added in order for Server to work"); + console.warn( + "[Nextlytics] nextlyticsMiddleware should be added in order for Server to work" + ); } return <>{children}; }