@nextlytics/core 0.1.0-canary-1

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.
Files changed (93) hide show
  1. package/dist/anonymous-user.cjs +118 -0
  2. package/dist/anonymous-user.d.mts +22 -0
  3. package/dist/anonymous-user.d.ts +22 -0
  4. package/dist/anonymous-user.js +94 -0
  5. package/dist/backends/clickhouse.cjs +110 -0
  6. package/dist/backends/clickhouse.d.mts +58 -0
  7. package/dist/backends/clickhouse.d.ts +58 -0
  8. package/dist/backends/clickhouse.js +92 -0
  9. package/dist/backends/ga.cjs +207 -0
  10. package/dist/backends/ga.d.mts +21 -0
  11. package/dist/backends/ga.d.ts +21 -0
  12. package/dist/backends/ga.js +183 -0
  13. package/dist/backends/gtm.cjs +155 -0
  14. package/dist/backends/gtm.d.mts +11 -0
  15. package/dist/backends/gtm.d.ts +11 -0
  16. package/dist/backends/gtm.js +131 -0
  17. package/dist/backends/lib/db.cjs +150 -0
  18. package/dist/backends/lib/db.d.mts +121 -0
  19. package/dist/backends/lib/db.d.ts +121 -0
  20. package/dist/backends/lib/db.js +119 -0
  21. package/dist/backends/logging.cjs +45 -0
  22. package/dist/backends/logging.d.mts +7 -0
  23. package/dist/backends/logging.d.ts +7 -0
  24. package/dist/backends/logging.js +21 -0
  25. package/dist/backends/neon.cjs +84 -0
  26. package/dist/backends/neon.d.mts +11 -0
  27. package/dist/backends/neon.d.ts +11 -0
  28. package/dist/backends/neon.js +66 -0
  29. package/dist/backends/postgrest.cjs +98 -0
  30. package/dist/backends/postgrest.d.mts +46 -0
  31. package/dist/backends/postgrest.d.ts +46 -0
  32. package/dist/backends/postgrest.js +73 -0
  33. package/dist/backends/posthog.cjs +120 -0
  34. package/dist/backends/posthog.d.mts +13 -0
  35. package/dist/backends/posthog.d.ts +13 -0
  36. package/dist/backends/posthog.js +96 -0
  37. package/dist/backends/segment.cjs +112 -0
  38. package/dist/backends/segment.d.mts +43 -0
  39. package/dist/backends/segment.d.ts +43 -0
  40. package/dist/backends/segment.js +88 -0
  41. package/dist/client.cjs +171 -0
  42. package/dist/client.d.mts +29 -0
  43. package/dist/client.d.ts +29 -0
  44. package/dist/client.js +146 -0
  45. package/dist/config-helpers.cjs +71 -0
  46. package/dist/config-helpers.d.mts +16 -0
  47. package/dist/config-helpers.d.ts +16 -0
  48. package/dist/config-helpers.js +45 -0
  49. package/dist/handlers.cjs +123 -0
  50. package/dist/handlers.d.mts +9 -0
  51. package/dist/handlers.d.ts +9 -0
  52. package/dist/handlers.js +99 -0
  53. package/dist/headers.cjs +41 -0
  54. package/dist/headers.d.mts +3 -0
  55. package/dist/headers.d.ts +3 -0
  56. package/dist/headers.js +17 -0
  57. package/dist/index.cjs +41 -0
  58. package/dist/index.d.mts +9 -0
  59. package/dist/index.d.ts +9 -0
  60. package/dist/index.js +12 -0
  61. package/dist/middleware.cjs +204 -0
  62. package/dist/middleware.d.mts +10 -0
  63. package/dist/middleware.d.ts +10 -0
  64. package/dist/middleware.js +183 -0
  65. package/dist/pages-router.cjs +45 -0
  66. package/dist/pages-router.d.mts +45 -0
  67. package/dist/pages-router.d.ts +45 -0
  68. package/dist/pages-router.js +21 -0
  69. package/dist/plugins/vercel-geo.cjs +60 -0
  70. package/dist/plugins/vercel-geo.d.mts +25 -0
  71. package/dist/plugins/vercel-geo.d.ts +25 -0
  72. package/dist/plugins/vercel-geo.js +36 -0
  73. package/dist/server-component-context.cjs +95 -0
  74. package/dist/server-component-context.d.mts +30 -0
  75. package/dist/server-component-context.d.ts +30 -0
  76. package/dist/server-component-context.js +69 -0
  77. package/dist/server.cjs +236 -0
  78. package/dist/server.d.mts +13 -0
  79. package/dist/server.d.ts +13 -0
  80. package/dist/server.js +213 -0
  81. package/dist/template.cjs +108 -0
  82. package/dist/template.d.mts +27 -0
  83. package/dist/template.d.ts +27 -0
  84. package/dist/template.js +83 -0
  85. package/dist/types.cjs +16 -0
  86. package/dist/types.d.mts +216 -0
  87. package/dist/types.d.ts +216 -0
  88. package/dist/types.js +0 -0
  89. package/dist/uitils.cjs +94 -0
  90. package/dist/uitils.d.mts +22 -0
  91. package/dist/uitils.d.ts +22 -0
  92. package/dist/uitils.js +68 -0
  93. package/package.json +162 -0
package/dist/client.js ADDED
@@ -0,0 +1,146 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useEffect, useCallback, createContext, useContext } from "react";
4
+ import { headers } from "./server-component-context";
5
+ import { compile, apply } from "./template";
6
+ const templateFunctions = {
7
+ q: (v) => JSON.stringify(v ?? null),
8
+ json: (v) => JSON.stringify(v ?? null)
9
+ };
10
+ const compiledCache = {};
11
+ const NextlyticsContext = createContext(null);
12
+ function createClientContext() {
13
+ const isBrowser = typeof window !== "undefined";
14
+ return {
15
+ collectedAt: /* @__PURE__ */ new Date(),
16
+ referer: isBrowser ? document.referrer || void 0 : void 0,
17
+ path: isBrowser ? window.location.pathname : void 0,
18
+ screen: {
19
+ width: isBrowser ? window.screen.width : void 0,
20
+ height: isBrowser ? window.screen.height : void 0,
21
+ innerWidth: isBrowser ? window.innerWidth : void 0,
22
+ innerHeight: isBrowser ? window.innerHeight : void 0,
23
+ density: isBrowser ? window.devicePixelRatio : void 0
24
+ },
25
+ userAgent: isBrowser ? navigator.userAgent : void 0,
26
+ locale: isBrowser ? navigator.language : void 0
27
+ };
28
+ }
29
+ function getCompiledTemplate(templateId, itemIndex, item) {
30
+ const cacheKey = `${templateId}:${itemIndex}`;
31
+ if (!compiledCache[cacheKey]) {
32
+ compiledCache[cacheKey] = {
33
+ src: item.src ? compile(item.src) : void 0,
34
+ body: item.body ? compile(item.body) : void 0
35
+ };
36
+ }
37
+ return compiledCache[cacheKey];
38
+ }
39
+ function executeTemplatedScripts(scripts, templates) {
40
+ if (!scripts || typeof window === "undefined") return;
41
+ for (const script of scripts) {
42
+ if (script.type !== "script-template") {
43
+ console.warn(`[Nextlytics] unsupported script type ${script.type} `);
44
+ continue;
45
+ }
46
+ const template = templates[script.templateId];
47
+ if (!template) {
48
+ console.warn(`[Nextlytics] Missing template: ${script.templateId}`);
49
+ continue;
50
+ }
51
+ const params = script.params;
52
+ for (let i = 0; i < template.items.length; i++) {
53
+ const item = template.items[i];
54
+ const compiled = getCompiledTemplate(script.templateId, i, item);
55
+ const src = compiled.src ? apply(compiled.src, params, templateFunctions) : void 0;
56
+ if (item.singleton && src && document.querySelector(`script[src="${src}"]`)) {
57
+ continue;
58
+ }
59
+ const el = document.createElement("script");
60
+ if (src) {
61
+ el.src = src;
62
+ }
63
+ if (compiled.body) {
64
+ el.textContent = apply(compiled.body, params, templateFunctions);
65
+ }
66
+ if (item.async) {
67
+ el.async = true;
68
+ }
69
+ document.head.appendChild(el);
70
+ }
71
+ }
72
+ }
73
+ async function sendEvent(requestId, type, payload) {
74
+ try {
75
+ const response = await fetch("/api/event", {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ [headers.pageRenderId]: requestId
80
+ },
81
+ body: JSON.stringify({ type, payload })
82
+ });
83
+ if (response.status === 404) {
84
+ console.error(
85
+ "[Nextlytics] In order for NextlyticsClient to work, you must mount nextlyticsRouteHandler to /api/event"
86
+ );
87
+ return { ok: false };
88
+ }
89
+ const data = await response.json().catch(() => ({ ok: response.ok }));
90
+ return { ok: data.ok ?? response.ok, scripts: data.scripts };
91
+ } catch (error) {
92
+ console.error("[Nextlytics] Failed to send event:", error);
93
+ return { ok: false };
94
+ }
95
+ }
96
+ const initializedRequestIds = /* @__PURE__ */ new Set();
97
+ function NextlyticsClient(props) {
98
+ const requestId = props.ctx?.requestId ?? props.requestId ?? "";
99
+ const scripts = props.ctx?.scripts ?? props.scripts;
100
+ const templates = props.ctx?.templates ?? props.templates ?? {};
101
+ useEffect(() => {
102
+ if (initializedRequestIds.has(requestId)) return;
103
+ initializedRequestIds.add(requestId);
104
+ if (scripts && Object.keys(templates).length > 0) {
105
+ executeTemplatedScripts(scripts, templates);
106
+ }
107
+ const clientContext = createClientContext();
108
+ sendEvent(requestId, "client-init", clientContext).then(
109
+ ({ scripts: responseScripts }) => {
110
+ if (responseScripts) {
111
+ executeTemplatedScripts(responseScripts, templates);
112
+ }
113
+ }
114
+ );
115
+ }, [requestId, scripts, templates]);
116
+ return /* @__PURE__ */ jsx(NextlyticsContext.Provider, { value: { requestId, templates }, children: props.children });
117
+ }
118
+ function useNextlytics() {
119
+ const context = useContext(NextlyticsContext);
120
+ if (!context) {
121
+ throw new Error(
122
+ "[Nextlytics] useNextlytics() must be used within a component wrapped by <NextlyticsServer>. Add <NextlyticsServer> at the top of your layout.tsx file."
123
+ );
124
+ }
125
+ const { requestId, templates } = context;
126
+ const send = useCallback(
127
+ async (eventName, opts) => {
128
+ const result = await sendEvent(requestId, "client-event", {
129
+ name: eventName,
130
+ props: opts?.props,
131
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
132
+ clientContext: createClientContext()
133
+ });
134
+ if (result.scripts) {
135
+ executeTemplatedScripts(result.scripts, templates);
136
+ }
137
+ return { ok: result.ok };
138
+ },
139
+ [requestId, templates]
140
+ );
141
+ return { sendEvent: send };
142
+ }
143
+ export {
144
+ NextlyticsClient,
145
+ useNextlytics
146
+ };
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var config_helpers_exports = {};
20
+ __export(config_helpers_exports, {
21
+ logConfigWarnings: () => logConfigWarnings,
22
+ validateConfig: () => validateConfig,
23
+ withDefaults: () => withDefaults
24
+ });
25
+ module.exports = __toCommonJS(config_helpers_exports);
26
+ function withDefaults(config) {
27
+ return {
28
+ ...config,
29
+ pageViewMode: config.pageViewMode ?? "server",
30
+ excludeApiCalls: config.excludeApiCalls ?? false,
31
+ eventEndpoint: config.eventEndpoint ?? "/api/event",
32
+ isApiPath: config.isApiPath ?? (() => false),
33
+ backends: config.backends ?? [],
34
+ anonymousUsers: {
35
+ gdprMode: config.anonymousUsers?.gdprMode ?? true,
36
+ useCookies: config.anonymousUsers?.useCookies ?? false,
37
+ dailySalt: config.anonymousUsers?.dailySalt ?? true,
38
+ cookieName: config.anonymousUsers?.cookieName ?? "__nextlytics_anon",
39
+ cookieMaxAge: config.anonymousUsers?.cookieMaxAge ?? 60 * 60 * 24 * 365 * 2
40
+ // 2 years
41
+ }
42
+ };
43
+ }
44
+ function validateConfig(config) {
45
+ const warnings = [];
46
+ if (config.pageViewMode === "client-init" && config.backends?.length) {
47
+ const staticBackends = config.backends.filter((b) => typeof b !== "function");
48
+ const backendsWithoutUpdates = staticBackends.filter((b) => !b.supportsUpdates);
49
+ if (backendsWithoutUpdates.length > 0) {
50
+ const backendNames = backendsWithoutUpdates.map((b) => `"${b.name}"`).join(", ");
51
+ warnings.push(
52
+ `[Nextlytics] pageViewMode="client-init" requires backends that support updates. These don't: ${backendNames}`
53
+ );
54
+ }
55
+ }
56
+ return {
57
+ valid: warnings.length === 0,
58
+ warnings
59
+ };
60
+ }
61
+ function logConfigWarnings(result) {
62
+ for (const warning of result.warnings) {
63
+ console.warn(warning);
64
+ }
65
+ }
66
+ // Annotate the CommonJS export names for ESM import in node:
67
+ 0 && (module.exports = {
68
+ logConfigWarnings,
69
+ validateConfig,
70
+ withDefaults
71
+ });
@@ -0,0 +1,16 @@
1
+ import { NextlyticsConfig } from './types.mjs';
2
+ import 'next/dist/server/web/spec-extension/cookies';
3
+ import 'next/server';
4
+
5
+ type NextlyticsConfigWithDefaults = Required<Pick<NextlyticsConfig, "pageViewMode" | "excludeApiCalls" | "eventEndpoint" | "isApiPath" | "backends">> & NextlyticsConfig & {
6
+ anonymousUsers: Required<NonNullable<NextlyticsConfig["anonymousUsers"]>>;
7
+ };
8
+ declare function withDefaults(config: NextlyticsConfig): NextlyticsConfigWithDefaults;
9
+ interface ConfigValidationResult {
10
+ valid: boolean;
11
+ warnings: string[];
12
+ }
13
+ declare function validateConfig(config: NextlyticsConfig): ConfigValidationResult;
14
+ declare function logConfigWarnings(result: ConfigValidationResult): void;
15
+
16
+ export { type ConfigValidationResult, type NextlyticsConfigWithDefaults, logConfigWarnings, validateConfig, withDefaults };
@@ -0,0 +1,16 @@
1
+ import { NextlyticsConfig } from './types.js';
2
+ import 'next/dist/server/web/spec-extension/cookies';
3
+ import 'next/server';
4
+
5
+ type NextlyticsConfigWithDefaults = Required<Pick<NextlyticsConfig, "pageViewMode" | "excludeApiCalls" | "eventEndpoint" | "isApiPath" | "backends">> & NextlyticsConfig & {
6
+ anonymousUsers: Required<NonNullable<NextlyticsConfig["anonymousUsers"]>>;
7
+ };
8
+ declare function withDefaults(config: NextlyticsConfig): NextlyticsConfigWithDefaults;
9
+ interface ConfigValidationResult {
10
+ valid: boolean;
11
+ warnings: string[];
12
+ }
13
+ declare function validateConfig(config: NextlyticsConfig): ConfigValidationResult;
14
+ declare function logConfigWarnings(result: ConfigValidationResult): void;
15
+
16
+ export { type ConfigValidationResult, type NextlyticsConfigWithDefaults, logConfigWarnings, validateConfig, withDefaults };
@@ -0,0 +1,45 @@
1
+ function withDefaults(config) {
2
+ return {
3
+ ...config,
4
+ pageViewMode: config.pageViewMode ?? "server",
5
+ excludeApiCalls: config.excludeApiCalls ?? false,
6
+ eventEndpoint: config.eventEndpoint ?? "/api/event",
7
+ isApiPath: config.isApiPath ?? (() => false),
8
+ backends: config.backends ?? [],
9
+ anonymousUsers: {
10
+ gdprMode: config.anonymousUsers?.gdprMode ?? true,
11
+ useCookies: config.anonymousUsers?.useCookies ?? false,
12
+ dailySalt: config.anonymousUsers?.dailySalt ?? true,
13
+ cookieName: config.anonymousUsers?.cookieName ?? "__nextlytics_anon",
14
+ cookieMaxAge: config.anonymousUsers?.cookieMaxAge ?? 60 * 60 * 24 * 365 * 2
15
+ // 2 years
16
+ }
17
+ };
18
+ }
19
+ function validateConfig(config) {
20
+ const warnings = [];
21
+ if (config.pageViewMode === "client-init" && config.backends?.length) {
22
+ const staticBackends = config.backends.filter((b) => typeof b !== "function");
23
+ const backendsWithoutUpdates = staticBackends.filter((b) => !b.supportsUpdates);
24
+ if (backendsWithoutUpdates.length > 0) {
25
+ const backendNames = backendsWithoutUpdates.map((b) => `"${b.name}"`).join(", ");
26
+ warnings.push(
27
+ `[Nextlytics] pageViewMode="client-init" requires backends that support updates. These don't: ${backendNames}`
28
+ );
29
+ }
30
+ }
31
+ return {
32
+ valid: warnings.length === 0,
33
+ warnings
34
+ };
35
+ }
36
+ function logConfigWarnings(result) {
37
+ for (const warning of result.warnings) {
38
+ console.warn(warning);
39
+ }
40
+ }
41
+ export {
42
+ logConfigWarnings,
43
+ validateConfig,
44
+ withDefaults
45
+ };
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var handlers_exports = {};
20
+ __export(handlers_exports, {
21
+ createHandlers: () => createHandlers
22
+ });
23
+ module.exports = __toCommonJS(handlers_exports);
24
+ var import_server_component_context = require("./server-component-context");
25
+ var import_uitils = require("./uitils");
26
+ var import_anonymous_user = require("./anonymous-user");
27
+ function createRequestContext(request) {
28
+ return {
29
+ headers: request.headers,
30
+ cookies: request.cookies
31
+ };
32
+ }
33
+ async function getUserContext(config, ctx) {
34
+ if (!config.callbacks.getUser) return void 0;
35
+ return await config.callbacks.getUser(ctx) || void 0;
36
+ }
37
+ function createHandlers(config, dispatchEvent, updateEvent) {
38
+ return {
39
+ GET: async () => {
40
+ return Response.json({ status: "ok" });
41
+ },
42
+ POST: async (req) => {
43
+ const pageRenderId = req.headers.get(import_server_component_context.headers.pageRenderId);
44
+ if (!pageRenderId) {
45
+ return Response.json({ error: "Missing page render ID" }, { status: 400 });
46
+ }
47
+ let body;
48
+ try {
49
+ body = await req.json();
50
+ } catch {
51
+ return Response.json({ error: "Invalid JSON" }, { status: 400 });
52
+ }
53
+ const { type, payload } = body;
54
+ const ctx = createRequestContext(req);
55
+ if (type === "client-init") {
56
+ const clientContext = payload;
57
+ const serverContext = (0, import_uitils.createServerContext)(req);
58
+ if (clientContext?.path) {
59
+ serverContext.path = clientContext.path;
60
+ }
61
+ const userContext = await getUserContext(config, ctx);
62
+ const { anonId: anonymousUserId } = await (0, import_anonymous_user.resolveAnonymousUser)({
63
+ ctx,
64
+ serverContext,
65
+ config
66
+ });
67
+ if (config.pageViewMode === "client-init") {
68
+ const event = {
69
+ eventId: pageRenderId,
70
+ type: "pageView",
71
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
72
+ anonymousUserId,
73
+ serverContext,
74
+ clientContext,
75
+ userContext,
76
+ properties: {}
77
+ };
78
+ const { clientActions, completion } = dispatchEvent(event, ctx);
79
+ const actions = await clientActions;
80
+ completion.catch((err) => console.warn("[Nextlytics] Dispatch completion error:", err));
81
+ const scripts = actions.items.filter((i) => i.type === "script-template");
82
+ return Response.json({ ok: true, scripts: scripts.length > 0 ? scripts : void 0 });
83
+ } else {
84
+ await updateEvent(pageRenderId, { clientContext, userContext, anonymousUserId }, ctx);
85
+ return Response.json({ ok: true });
86
+ }
87
+ } else if (type === "client-event") {
88
+ const clientContext = payload.clientContext || void 0;
89
+ const serverContext = (0, import_uitils.createServerContext)(req);
90
+ if (clientContext?.path) {
91
+ serverContext.path = clientContext.path;
92
+ }
93
+ const userContext = await getUserContext(config, ctx);
94
+ const { anonId: anonymousUserId } = await (0, import_anonymous_user.resolveAnonymousUser)({
95
+ ctx,
96
+ serverContext,
97
+ config
98
+ });
99
+ const event = {
100
+ eventId: (0, import_uitils.generateId)(),
101
+ parentEventId: pageRenderId,
102
+ type: payload.name || type,
103
+ collectedAt: payload.collectedAt || (/* @__PURE__ */ new Date()).toISOString(),
104
+ anonymousUserId,
105
+ serverContext,
106
+ clientContext,
107
+ userContext,
108
+ properties: payload.props || {}
109
+ };
110
+ const { clientActions, completion } = dispatchEvent(event, ctx);
111
+ const actions = await clientActions;
112
+ completion.catch((err) => console.warn("[Nextlytics] Dispatch completion error:", err));
113
+ const scripts = actions.items.filter((i) => i.type === "script-template");
114
+ return Response.json({ ok: true, scripts: scripts.length > 0 ? scripts : void 0 });
115
+ }
116
+ return Response.json({ ok: true });
117
+ }
118
+ };
119
+ }
120
+ // Annotate the CommonJS export names for ESM import in node:
121
+ 0 && (module.exports = {
122
+ createHandlers
123
+ });
@@ -0,0 +1,9 @@
1
+ import { NextRequest } from 'next/server';
2
+ import { NextlyticsEvent, RequestContext, DispatchResult } from './types.mjs';
3
+ import { NextlyticsConfigWithDefaults } from './config-helpers.mjs';
4
+ import 'next/dist/server/web/spec-extension/cookies';
5
+
6
+ type AppRouteHandlers = Record<"GET" | "POST", (req: NextRequest) => Promise<Response>>;
7
+ declare function createHandlers(config: NextlyticsConfigWithDefaults, dispatchEvent: (event: NextlyticsEvent, ctx: RequestContext) => DispatchResult, updateEvent: (eventId: string, patch: Partial<NextlyticsEvent>, ctx: RequestContext) => Promise<void>): AppRouteHandlers;
8
+
9
+ export { createHandlers };
@@ -0,0 +1,9 @@
1
+ import { NextRequest } from 'next/server';
2
+ import { NextlyticsEvent, RequestContext, DispatchResult } from './types.js';
3
+ import { NextlyticsConfigWithDefaults } from './config-helpers.js';
4
+ import 'next/dist/server/web/spec-extension/cookies';
5
+
6
+ type AppRouteHandlers = Record<"GET" | "POST", (req: NextRequest) => Promise<Response>>;
7
+ declare function createHandlers(config: NextlyticsConfigWithDefaults, dispatchEvent: (event: NextlyticsEvent, ctx: RequestContext) => DispatchResult, updateEvent: (eventId: string, patch: Partial<NextlyticsEvent>, ctx: RequestContext) => Promise<void>): AppRouteHandlers;
8
+
9
+ export { createHandlers };
@@ -0,0 +1,99 @@
1
+ import { headers as analyticsHeaders } from "./server-component-context";
2
+ import { createServerContext, generateId } from "./uitils";
3
+ import { resolveAnonymousUser } from "./anonymous-user";
4
+ function createRequestContext(request) {
5
+ return {
6
+ headers: request.headers,
7
+ cookies: request.cookies
8
+ };
9
+ }
10
+ async function getUserContext(config, ctx) {
11
+ if (!config.callbacks.getUser) return void 0;
12
+ return await config.callbacks.getUser(ctx) || void 0;
13
+ }
14
+ function createHandlers(config, dispatchEvent, updateEvent) {
15
+ return {
16
+ GET: async () => {
17
+ return Response.json({ status: "ok" });
18
+ },
19
+ POST: async (req) => {
20
+ const pageRenderId = req.headers.get(analyticsHeaders.pageRenderId);
21
+ if (!pageRenderId) {
22
+ return Response.json({ error: "Missing page render ID" }, { status: 400 });
23
+ }
24
+ let body;
25
+ try {
26
+ body = await req.json();
27
+ } catch {
28
+ return Response.json({ error: "Invalid JSON" }, { status: 400 });
29
+ }
30
+ const { type, payload } = body;
31
+ const ctx = createRequestContext(req);
32
+ if (type === "client-init") {
33
+ const clientContext = payload;
34
+ const serverContext = createServerContext(req);
35
+ if (clientContext?.path) {
36
+ serverContext.path = clientContext.path;
37
+ }
38
+ const userContext = await getUserContext(config, ctx);
39
+ const { anonId: anonymousUserId } = await resolveAnonymousUser({
40
+ ctx,
41
+ serverContext,
42
+ config
43
+ });
44
+ if (config.pageViewMode === "client-init") {
45
+ const event = {
46
+ eventId: pageRenderId,
47
+ type: "pageView",
48
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
49
+ anonymousUserId,
50
+ serverContext,
51
+ clientContext,
52
+ userContext,
53
+ properties: {}
54
+ };
55
+ const { clientActions, completion } = dispatchEvent(event, ctx);
56
+ const actions = await clientActions;
57
+ completion.catch((err) => console.warn("[Nextlytics] Dispatch completion error:", err));
58
+ const scripts = actions.items.filter((i) => i.type === "script-template");
59
+ return Response.json({ ok: true, scripts: scripts.length > 0 ? scripts : void 0 });
60
+ } else {
61
+ await updateEvent(pageRenderId, { clientContext, userContext, anonymousUserId }, ctx);
62
+ return Response.json({ ok: true });
63
+ }
64
+ } else if (type === "client-event") {
65
+ const clientContext = payload.clientContext || void 0;
66
+ const serverContext = createServerContext(req);
67
+ if (clientContext?.path) {
68
+ serverContext.path = clientContext.path;
69
+ }
70
+ const userContext = await getUserContext(config, ctx);
71
+ const { anonId: anonymousUserId } = await resolveAnonymousUser({
72
+ ctx,
73
+ serverContext,
74
+ config
75
+ });
76
+ const event = {
77
+ eventId: generateId(),
78
+ parentEventId: pageRenderId,
79
+ type: payload.name || type,
80
+ collectedAt: payload.collectedAt || (/* @__PURE__ */ new Date()).toISOString(),
81
+ anonymousUserId,
82
+ serverContext,
83
+ clientContext,
84
+ userContext,
85
+ properties: payload.props || {}
86
+ };
87
+ const { clientActions, completion } = dispatchEvent(event, ctx);
88
+ const actions = await clientActions;
89
+ completion.catch((err) => console.warn("[Nextlytics] Dispatch completion error:", err));
90
+ const scripts = actions.items.filter((i) => i.type === "script-template");
91
+ return Response.json({ ok: true, scripts: scripts.length > 0 ? scripts : void 0 });
92
+ }
93
+ return Response.json({ ok: true });
94
+ }
95
+ };
96
+ }
97
+ export {
98
+ createHandlers
99
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var headers_exports = {};
20
+ __export(headers_exports, {
21
+ removeSensitiveHeaders: () => removeSensitiveHeaders
22
+ });
23
+ module.exports = __toCommonJS(headers_exports);
24
+ const SENSITIVE_HEADERS = /* @__PURE__ */ new Set(["cookie", "set-cookie", "authorization", "proxy-authorization"]);
25
+ const SENSITIVE_PATTERNS = /auth|token|key|secret|password|credential|session/i;
26
+ function removeSensitiveHeaders(requestHeaders) {
27
+ const result = {};
28
+ for (const [key, value] of Object.entries(requestHeaders)) {
29
+ const lowerKey = key.toLowerCase();
30
+ if (SENSITIVE_HEADERS.has(lowerKey) || SENSITIVE_PATTERNS.test(lowerKey)) {
31
+ result[key] = `[redacted, len ${value.length}]`;
32
+ } else {
33
+ result[key] = value;
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ // Annotate the CommonJS export names for ESM import in node:
39
+ 0 && (module.exports = {
40
+ removeSensitiveHeaders
41
+ });
@@ -0,0 +1,3 @@
1
+ declare function removeSensitiveHeaders(requestHeaders: Record<string, string>): Record<string, string>;
2
+
3
+ export { removeSensitiveHeaders };
@@ -0,0 +1,3 @@
1
+ declare function removeSensitiveHeaders(requestHeaders: Record<string, string>): Record<string, string>;
2
+
3
+ export { removeSensitiveHeaders };
@@ -0,0 +1,17 @@
1
+ const SENSITIVE_HEADERS = /* @__PURE__ */ new Set(["cookie", "set-cookie", "authorization", "proxy-authorization"]);
2
+ const SENSITIVE_PATTERNS = /auth|token|key|secret|password|credential|session/i;
3
+ function removeSensitiveHeaders(requestHeaders) {
4
+ const result = {};
5
+ for (const [key, value] of Object.entries(requestHeaders)) {
6
+ const lowerKey = key.toLowerCase();
7
+ if (SENSITIVE_HEADERS.has(lowerKey) || SENSITIVE_PATTERNS.test(lowerKey)) {
8
+ result[key] = `[redacted, len ${value.length}]`;
9
+ } else {
10
+ result[key] = value;
11
+ }
12
+ }
13
+ return result;
14
+ }
15
+ export {
16
+ removeSensitiveHeaders
17
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
+ Nextlytics: () => import_server.Nextlytics,
22
+ NextlyticsClient: () => import_client.NextlyticsClient,
23
+ NextlyticsServer: () => import_server.NextlyticsServer,
24
+ getNextlyticsProps: () => import_pages_router.getNextlyticsProps,
25
+ loggingBackend: () => import_logging.loggingBackend,
26
+ useNextlytics: () => import_client.useNextlytics
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var import_server = require("./server");
30
+ var import_client = require("./client");
31
+ var import_pages_router = require("./pages-router");
32
+ var import_logging = require("./backends/logging");
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ Nextlytics,
36
+ NextlyticsClient,
37
+ NextlyticsServer,
38
+ getNextlyticsProps,
39
+ loggingBackend,
40
+ useNextlytics
41
+ });
@@ -0,0 +1,9 @@
1
+ export { Nextlytics, NextlyticsServer } from './server.mjs';
2
+ export { NextlyticsClient, NextlyticsContext, useNextlytics } from './client.mjs';
3
+ export { getNextlyticsProps } from './pages-router.mjs';
4
+ export { loggingBackend } from './backends/logging.mjs';
5
+ export { AnonymousUserResult, ClientContext, NextlyticsBackend, NextlyticsBackendFactory, NextlyticsConfig, NextlyticsEvent, NextlyticsPlugin, NextlyticsPluginFactory, NextlyticsResult, NextlyticsServerSide, RequestContext, ServerEventContext, UserContext } from './types.mjs';
6
+ import 'react/jsx-runtime';
7
+ import 'react';
8
+ import 'next/dist/server/web/spec-extension/cookies';
9
+ import 'next/server';
@@ -0,0 +1,9 @@
1
+ export { Nextlytics, NextlyticsServer } from './server.js';
2
+ export { NextlyticsClient, NextlyticsContext, useNextlytics } from './client.js';
3
+ export { getNextlyticsProps } from './pages-router.js';
4
+ export { loggingBackend } from './backends/logging.js';
5
+ export { AnonymousUserResult, ClientContext, NextlyticsBackend, NextlyticsBackendFactory, NextlyticsConfig, NextlyticsEvent, NextlyticsPlugin, NextlyticsPluginFactory, NextlyticsResult, NextlyticsServerSide, RequestContext, ServerEventContext, UserContext } from './types.js';
6
+ import 'react/jsx-runtime';
7
+ import 'react';
8
+ import 'next/dist/server/web/spec-extension/cookies';
9
+ import 'next/server';