@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/server.js ADDED
@@ -0,0 +1,213 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+ import { headers, cookies } from "next/headers";
3
+ import { removeSensitiveHeaders } from "./headers";
4
+ import {
5
+ headers as analyticsHeaders,
6
+ restoreServerComponentContext
7
+ } from "./server-component-context";
8
+ import { resolveAnonymousUser } from "./anonymous-user";
9
+ import { NextlyticsClient } from "./client";
10
+ import { createHandlers } from "./handlers";
11
+ import { logConfigWarnings, validateConfig, withDefaults } from "./config-helpers";
12
+ import { createNextlyticsMiddleware } from "./middleware";
13
+ import { generateId } from "./uitils";
14
+ function resolveBackends(config, ctx) {
15
+ const backends = config.backends || [];
16
+ return backends.map((backend) => {
17
+ if (typeof backend === "function") {
18
+ return backend(ctx);
19
+ }
20
+ return backend;
21
+ }).filter((b) => b !== null);
22
+ }
23
+ function resolvePlugins(config, ctx) {
24
+ const plugins = config.plugins || [];
25
+ return plugins.map((plugin) => {
26
+ if (typeof plugin === "function") {
27
+ if (!ctx) {
28
+ return null;
29
+ }
30
+ return plugin(ctx);
31
+ }
32
+ return plugin;
33
+ }).filter((p) => p !== null);
34
+ }
35
+ function mergeClientActions(actions) {
36
+ const items = [];
37
+ for (const action of actions) {
38
+ if (action?.items) {
39
+ items.push(...action.items);
40
+ }
41
+ }
42
+ return { items };
43
+ }
44
+ async function createRequestContext() {
45
+ const [_cookies, _headers] = await Promise.all([cookies(), headers()]);
46
+ return {
47
+ cookies: _cookies,
48
+ headers: _headers
49
+ };
50
+ }
51
+ async function NextlyticsServer({ children }) {
52
+ const headersList = await headers();
53
+ const ctx = restoreServerComponentContext(headersList);
54
+ if (!ctx) {
55
+ console.warn(
56
+ "[Nextlytics] nextlyticsMiddleware should be added in order for NextlyticsServer to work"
57
+ );
58
+ return /* @__PURE__ */ jsx(Fragment, { children });
59
+ }
60
+ return /* @__PURE__ */ jsx(NextlyticsClient, { requestId: ctx.pageRenderId, scripts: ctx.scripts, templates: ctx.templates, children });
61
+ }
62
+ function Nextlytics(userConfig) {
63
+ const config = withDefaults(userConfig);
64
+ const validationResult = validateConfig(config);
65
+ logConfigWarnings(validationResult);
66
+ const dispatchEventInternal = (event, ctx) => {
67
+ const plugins = resolvePlugins(config, ctx);
68
+ const backends = resolveBackends(config, ctx);
69
+ const pluginsDone = (async () => {
70
+ for (const plugin of plugins) {
71
+ try {
72
+ await plugin.onDispatch(event);
73
+ } catch (err) {
74
+ console.warn("[Nextlytics] Plugin failed on onDispatch:", err);
75
+ }
76
+ }
77
+ })();
78
+ const backendResults = pluginsDone.then(() => {
79
+ return backends.map((backend) => {
80
+ const start = Date.now();
81
+ const promise = backend.onEvent(event).then((result) => ({ ok: true, ms: Date.now() - start, result })).catch((err) => {
82
+ console.warn(`[Nextlytics] Backend "${backend.name}" failed on onEvent:`, err);
83
+ return { ok: false, ms: Date.now() - start, result: void 0 };
84
+ });
85
+ return { backend, promise };
86
+ });
87
+ });
88
+ const clientActions = backendResults.then(async (results) => {
89
+ const actionResults = results.filter((r) => r.backend.returnsClientActions);
90
+ const actions = await Promise.all(actionResults.map((r) => r.promise));
91
+ return mergeClientActions(actions.map((a) => a.result));
92
+ });
93
+ const completion = backendResults.then(async (results) => {
94
+ const settled = await Promise.all(results.map((r) => r.promise));
95
+ if (config.debug) {
96
+ const nameWidth = Math.max(...results.map((r) => r.backend.name.length));
97
+ console.log(
98
+ `[Nextlytics] dispatchEvent ${event.type} ${event.eventId} (${results.length} backends)`
99
+ );
100
+ results.forEach((r, i) => {
101
+ const s = settled[i];
102
+ const status = s.ok ? "ok" : "fail";
103
+ console.log(` ${r.backend.name.padEnd(nameWidth)} ${status.padEnd(4)} ${s.ms}ms`);
104
+ });
105
+ }
106
+ }).then(() => {
107
+ });
108
+ return { clientActions, completion };
109
+ };
110
+ const updateEventInternal = async (eventId, patch, ctx) => {
111
+ const backends = resolveBackends(config, ctx).filter((backend) => backend.supportsUpdates);
112
+ const results = await Promise.all(
113
+ backends.map(async (backend) => {
114
+ const start = Date.now();
115
+ try {
116
+ await backend.updateEvent(eventId, patch);
117
+ return { backend, ok: true, ms: Date.now() - start };
118
+ } catch (err) {
119
+ console.warn(`[Nextlytics] Backend "${backend.name}" failed on updateEvent:`, err);
120
+ return { backend, ok: false, ms: Date.now() - start };
121
+ }
122
+ })
123
+ );
124
+ if (config.debug && backends.length > 0) {
125
+ const nameWidth = Math.max(...backends.map((b) => b.name.length));
126
+ console.log(`[Nextlytics] updateEvent ${eventId} (${backends.length} backends)`);
127
+ results.forEach((r) => {
128
+ const status = r.ok ? "ok" : "fail";
129
+ console.log(` ${r.backend.name.padEnd(nameWidth)} ${status.padEnd(4)} ${r.ms}ms`);
130
+ });
131
+ }
132
+ };
133
+ const dispatchEvent = async (event) => {
134
+ const ctx = await createRequestContext();
135
+ return dispatchEventInternal(event, ctx);
136
+ };
137
+ const updateEvent = async (eventId, patch) => {
138
+ const ctx = await createRequestContext();
139
+ return updateEventInternal(eventId, patch, ctx);
140
+ };
141
+ const middleware = createNextlyticsMiddleware(config, dispatchEventInternal, updateEventInternal);
142
+ const handlers = createHandlers(config, dispatchEventInternal, updateEventInternal);
143
+ const analytics = async () => {
144
+ const headersList = await headers();
145
+ const cookieStore = await cookies();
146
+ const pageRenderId = headersList.get(analyticsHeaders.pageRenderId);
147
+ const serverContext = createServerContextFromHeaders(headersList);
148
+ const ctx = { headers: headersList, cookies: cookieStore };
149
+ const { anonId: anonymousUserId } = await resolveAnonymousUser({ ctx, serverContext, config });
150
+ let userContext;
151
+ if (config.callbacks.getUser) {
152
+ try {
153
+ userContext = await config.callbacks.getUser(ctx) || void 0;
154
+ } catch {
155
+ }
156
+ }
157
+ return {
158
+ sendEvent: async (eventName, opts) => {
159
+ if (!pageRenderId) {
160
+ console.error("[Nextlytics] analytics() requires nextlyticsMiddleware");
161
+ return { ok: false };
162
+ }
163
+ const event = {
164
+ eventId: generateId(),
165
+ parentEventId: pageRenderId,
166
+ type: eventName,
167
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
168
+ anonymousUserId,
169
+ serverContext,
170
+ userContext,
171
+ properties: opts?.props || {}
172
+ };
173
+ await dispatchEventInternal(event, ctx);
174
+ return { ok: true };
175
+ }
176
+ };
177
+ };
178
+ return { middleware, handlers, analytics, dispatchEvent, updateEvent };
179
+ }
180
+ function createServerContextFromHeaders(headersList) {
181
+ const rawHeaders = {};
182
+ headersList.forEach((value, key) => {
183
+ rawHeaders[key] = value;
184
+ });
185
+ const requestHeaders = removeSensitiveHeaders(rawHeaders);
186
+ const pathname = headersList.get(analyticsHeaders.pathname) || "";
187
+ const search = headersList.get(analyticsHeaders.search) || "";
188
+ const searchParams = {};
189
+ if (search) {
190
+ const params = new URLSearchParams(search);
191
+ params.forEach((value, key) => {
192
+ if (!searchParams[key]) {
193
+ searchParams[key] = [];
194
+ }
195
+ searchParams[key].push(value);
196
+ });
197
+ }
198
+ return {
199
+ collectedAt: /* @__PURE__ */ new Date(),
200
+ host: headersList.get("host") || "",
201
+ method: "GET",
202
+ path: pathname,
203
+ search: searchParams,
204
+ ip: headersList.get("x-forwarded-for")?.split(",")[0]?.trim() || "",
205
+ requestHeaders,
206
+ responseHeaders: {}
207
+ };
208
+ }
209
+ export {
210
+ Nextlytics,
211
+ NextlyticsServer,
212
+ createRequestContext
213
+ };
@@ -0,0 +1,108 @@
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 template_exports = {};
20
+ __export(template_exports, {
21
+ apply: () => apply,
22
+ compile: () => compile
23
+ });
24
+ module.exports = __toCommonJS(template_exports);
25
+ function compile(template) {
26
+ const result = [];
27
+ let i = 0, text = "";
28
+ while (i < template.length) {
29
+ if (template[i] === "\\" && "{}".includes(template[i + 1]) && template[i + 1] === template[i + 2]) {
30
+ text += template.slice(i + 1, i + 3);
31
+ i += 3;
32
+ } else if (template.slice(i, i + 2) === "{{") {
33
+ if (text) {
34
+ result.push({ type: "text", value: text });
35
+ text = "";
36
+ }
37
+ const end = template.indexOf("}}", i + 2);
38
+ if (end === -1) throw new Error(`Unclosed {{ at position ${i}`);
39
+ result.push({ type: "expr", expr: parseExpr(template.slice(i + 2, end).trim()) });
40
+ i = end + 2;
41
+ } else {
42
+ text += template[i++];
43
+ }
44
+ }
45
+ if (text) result.push({ type: "text", value: text });
46
+ return result;
47
+ }
48
+ function apply(tpl, params, fns) {
49
+ return tpl.map((p) => p.type === "text" ? p.value : evalExpr(p.expr, params, fns)).join("");
50
+ }
51
+ function parseExpr(s) {
52
+ if ((s[0] === '"' || s[0] === "'") && s[0] === s[s.length - 1]) {
53
+ const esc = { n: "\n", t: " ", r: "\r" };
54
+ return {
55
+ type: "string",
56
+ value: s.slice(1, -1).replace(/\\(.)/g, (_, c) => esc[c] ?? c)
57
+ };
58
+ }
59
+ if (/^-?\d+(\.\d+)?$/.test(s)) return { type: "number", value: +s };
60
+ const m = s.match(/^(\w+)\(/);
61
+ if (m && s.endsWith(")"))
62
+ return { type: "call", func: m[1], args: splitArgs(s.slice(m[0].length, -1)).map(parseExpr) };
63
+ return { type: "path", parts: s.split(".") };
64
+ }
65
+ function splitArgs(s) {
66
+ const args = [];
67
+ let cur = "", depth = 0, quote = null;
68
+ for (let i = 0; i < s.length; i++) {
69
+ const c = s[i];
70
+ if ((c === '"' || c === "'") && s[i - 1] !== "\\") quote = quote === c ? null : quote ?? c;
71
+ if (!quote) {
72
+ if (c === "(") depth++;
73
+ if (c === ")") depth--;
74
+ if (c === "," && depth === 0) {
75
+ args.push(cur.trim());
76
+ cur = "";
77
+ continue;
78
+ }
79
+ }
80
+ cur += c;
81
+ }
82
+ if (cur.trim()) args.push(cur.trim());
83
+ return args;
84
+ }
85
+ function resolve(parts, obj) {
86
+ for (const p of parts) {
87
+ if (obj == null || typeof obj !== "object") return void 0;
88
+ obj = obj[p];
89
+ }
90
+ return obj;
91
+ }
92
+ function evalExpr(e, params, fns) {
93
+ if (e.type === "string") return e.value;
94
+ if (e.type === "number") return String(e.value);
95
+ if (e.type === "path") return String(resolve(e.parts, params) ?? "");
96
+ const fn = fns[e.func];
97
+ if (!fn) throw new Error(`Unknown function: ${e.func}`);
98
+ return fn(
99
+ ...e.args.map(
100
+ (a) => a.type === "path" ? resolve(a.parts, params) : a.type === "call" ? evalExpr(a, params, fns) : a.value
101
+ )
102
+ );
103
+ }
104
+ // Annotate the CommonJS export names for ESM import in node:
105
+ 0 && (module.exports = {
106
+ apply,
107
+ compile
108
+ });
@@ -0,0 +1,27 @@
1
+ type Expr = {
2
+ type: "path";
3
+ parts: string[];
4
+ } | {
5
+ type: "call";
6
+ func: string;
7
+ args: Expr[];
8
+ } | {
9
+ type: "string";
10
+ value: string;
11
+ } | {
12
+ type: "number";
13
+ value: number;
14
+ };
15
+ type CompiledTemplate = Array<{
16
+ type: "text";
17
+ value: string;
18
+ } | {
19
+ type: "expr";
20
+ expr: Expr;
21
+ }>;
22
+ type TemplateFunction = (...values: unknown[]) => string;
23
+ type TemplateFunctions = Record<string, TemplateFunction>;
24
+ declare function compile(template: string): CompiledTemplate;
25
+ declare function apply(tpl: CompiledTemplate, params: Record<string, unknown>, fns: TemplateFunctions): string;
26
+
27
+ export { type CompiledTemplate, type TemplateFunction, type TemplateFunctions, apply, compile };
@@ -0,0 +1,27 @@
1
+ type Expr = {
2
+ type: "path";
3
+ parts: string[];
4
+ } | {
5
+ type: "call";
6
+ func: string;
7
+ args: Expr[];
8
+ } | {
9
+ type: "string";
10
+ value: string;
11
+ } | {
12
+ type: "number";
13
+ value: number;
14
+ };
15
+ type CompiledTemplate = Array<{
16
+ type: "text";
17
+ value: string;
18
+ } | {
19
+ type: "expr";
20
+ expr: Expr;
21
+ }>;
22
+ type TemplateFunction = (...values: unknown[]) => string;
23
+ type TemplateFunctions = Record<string, TemplateFunction>;
24
+ declare function compile(template: string): CompiledTemplate;
25
+ declare function apply(tpl: CompiledTemplate, params: Record<string, unknown>, fns: TemplateFunctions): string;
26
+
27
+ export { type CompiledTemplate, type TemplateFunction, type TemplateFunctions, apply, compile };
@@ -0,0 +1,83 @@
1
+ function compile(template) {
2
+ const result = [];
3
+ let i = 0, text = "";
4
+ while (i < template.length) {
5
+ if (template[i] === "\\" && "{}".includes(template[i + 1]) && template[i + 1] === template[i + 2]) {
6
+ text += template.slice(i + 1, i + 3);
7
+ i += 3;
8
+ } else if (template.slice(i, i + 2) === "{{") {
9
+ if (text) {
10
+ result.push({ type: "text", value: text });
11
+ text = "";
12
+ }
13
+ const end = template.indexOf("}}", i + 2);
14
+ if (end === -1) throw new Error(`Unclosed {{ at position ${i}`);
15
+ result.push({ type: "expr", expr: parseExpr(template.slice(i + 2, end).trim()) });
16
+ i = end + 2;
17
+ } else {
18
+ text += template[i++];
19
+ }
20
+ }
21
+ if (text) result.push({ type: "text", value: text });
22
+ return result;
23
+ }
24
+ function apply(tpl, params, fns) {
25
+ return tpl.map((p) => p.type === "text" ? p.value : evalExpr(p.expr, params, fns)).join("");
26
+ }
27
+ function parseExpr(s) {
28
+ if ((s[0] === '"' || s[0] === "'") && s[0] === s[s.length - 1]) {
29
+ const esc = { n: "\n", t: " ", r: "\r" };
30
+ return {
31
+ type: "string",
32
+ value: s.slice(1, -1).replace(/\\(.)/g, (_, c) => esc[c] ?? c)
33
+ };
34
+ }
35
+ if (/^-?\d+(\.\d+)?$/.test(s)) return { type: "number", value: +s };
36
+ const m = s.match(/^(\w+)\(/);
37
+ if (m && s.endsWith(")"))
38
+ return { type: "call", func: m[1], args: splitArgs(s.slice(m[0].length, -1)).map(parseExpr) };
39
+ return { type: "path", parts: s.split(".") };
40
+ }
41
+ function splitArgs(s) {
42
+ const args = [];
43
+ let cur = "", depth = 0, quote = null;
44
+ for (let i = 0; i < s.length; i++) {
45
+ const c = s[i];
46
+ if ((c === '"' || c === "'") && s[i - 1] !== "\\") quote = quote === c ? null : quote ?? c;
47
+ if (!quote) {
48
+ if (c === "(") depth++;
49
+ if (c === ")") depth--;
50
+ if (c === "," && depth === 0) {
51
+ args.push(cur.trim());
52
+ cur = "";
53
+ continue;
54
+ }
55
+ }
56
+ cur += c;
57
+ }
58
+ if (cur.trim()) args.push(cur.trim());
59
+ return args;
60
+ }
61
+ function resolve(parts, obj) {
62
+ for (const p of parts) {
63
+ if (obj == null || typeof obj !== "object") return void 0;
64
+ obj = obj[p];
65
+ }
66
+ return obj;
67
+ }
68
+ function evalExpr(e, params, fns) {
69
+ if (e.type === "string") return e.value;
70
+ if (e.type === "number") return String(e.value);
71
+ if (e.type === "path") return String(resolve(e.parts, params) ?? "");
72
+ const fn = fns[e.func];
73
+ if (!fn) throw new Error(`Unknown function: ${e.func}`);
74
+ return fn(
75
+ ...e.args.map(
76
+ (a) => a.type === "path" ? resolve(a.parts, params) : a.type === "call" ? evalExpr(a, params, fns) : a.value
77
+ )
78
+ );
79
+ }
80
+ export {
81
+ apply,
82
+ compile
83
+ };
package/dist/types.cjs ADDED
@@ -0,0 +1,16 @@
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 __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
@@ -0,0 +1,216 @@
1
+ import { RequestCookies } from 'next/dist/server/web/spec-extension/cookies';
2
+ import { NextRequest, NextMiddleware } from 'next/server';
3
+
4
+ /** Server-side request context collected in middleware */
5
+ interface ServerEventContext {
6
+ /** When the event was collected on server */
7
+ collectedAt: Date;
8
+ /** Request host (e.g. "example.com") */
9
+ host: string;
10
+ /** HTTP method (GET, POST, etc.) */
11
+ method: string;
12
+ /** URL pathname (e.g. "/products/123") */
13
+ path: string;
14
+ /** Query parameters as key -> values[] */
15
+ search: Record<string, string[]>;
16
+ /** Client IP from x-forwarded-for or direct connection */
17
+ ip: string;
18
+ /** Request headers (sensitive ones removed) */
19
+ requestHeaders: Record<string, string>;
20
+ /** Response headers */
21
+ responseHeaders: Record<string, string>;
22
+ }
23
+ /** Client-side context collected in browser */
24
+ interface ClientContext {
25
+ /** When the event was collected on client */
26
+ collectedAt: Date;
27
+ /** document.referrer */
28
+ referer?: string;
29
+ /** window.location.pathname - may differ from server path in SPAs */
30
+ path?: string;
31
+ /** Screen and viewport dimensions */
32
+ screen: {
33
+ /** screen.width */
34
+ width?: number;
35
+ /** screen.height */
36
+ height?: number;
37
+ /** window.innerWidth (viewport) */
38
+ innerWidth?: number;
39
+ /** window.innerHeight (viewport) */
40
+ innerHeight?: number;
41
+ /** window.devicePixelRatio */
42
+ density?: number;
43
+ };
44
+ /** navigator.userAgent */
45
+ userAgent?: string;
46
+ /** navigator.language */
47
+ locale?: string;
48
+ }
49
+ /** Identified user context */
50
+ interface UserContext {
51
+ /** Unique user identifier */
52
+ userId: string;
53
+ /** User traits for identification */
54
+ traits: {
55
+ email?: string;
56
+ name?: string;
57
+ phone?: string;
58
+ } & Record<string, unknown>;
59
+ }
60
+ /** Analytics event sent to backends */
61
+ interface NextlyticsEvent {
62
+ /** ISO timestamp when event was collected */
63
+ collectedAt: string;
64
+ /** Unique event ID */
65
+ eventId: string;
66
+ /** Parent event ID (e.g. pageView for client events) */
67
+ parentEventId?: string;
68
+ /** Event type (e.g. "pageView", "apiCall", custom events) */
69
+ type: "pageView" | "apiCall" | string;
70
+ /** Anonymous user identifier (GDPR-compliant hash or cookie-based) */
71
+ anonymousUserId?: string;
72
+ /** Server-side request context */
73
+ serverContext: ServerEventContext;
74
+ /** Identified user context */
75
+ userContext?: UserContext;
76
+ /** Client-side browser context */
77
+ clientContext?: ClientContext;
78
+ /** Custom event properties */
79
+ properties: Record<string, unknown>;
80
+ }
81
+
82
+ type AnonymousUserResult = {
83
+ /** Anonymous user identifier */
84
+ anonId: string;
85
+ };
86
+ /** Headers and cookies context for backend/plugin factories. Uses Pick for compatibility with both
87
+ * middleware (RequestCookies) and server components (ReadonlyRequestCookies) */
88
+ type RequestContext = {
89
+ headers: Headers;
90
+ cookies: Pick<RequestCookies, "get" | "getAll" | "has">;
91
+ };
92
+ type NextlyticsPlugin = {
93
+ /**
94
+ * Called right after event is created but before it's sent to backends.
95
+ * Plugin can mutate the event to add/modify properties.
96
+ * @param event - The event to process (can be mutated)
97
+ */
98
+ onDispatch(event: NextlyticsEvent): Promise<void>;
99
+ };
100
+ /** Factory to create plugin per-request (for request-scoped plugins) */
101
+ type NextlyticsPluginFactory = (ctx: RequestContext) => NextlyticsPlugin;
102
+ type NextlyticsConfig = {
103
+ /** Enable debug logging (shows backend stats for each event) */
104
+ debug?: boolean;
105
+ anonymousUsers?: {
106
+ /** Store anonymous ID in cookies */
107
+ useCookies?: boolean;
108
+ /** Use hash-based IDs for GDPR compliance (default: true) */
109
+ gdprMode?: boolean;
110
+ /** Rotate hash salt daily for shorter-lived IDs (default: true) */
111
+ dailySalt?: boolean;
112
+ /** Cookie name when useCookies=true (default: "__nextlytics_anon") */
113
+ cookieName?: string;
114
+ /** Cookie max age in seconds (default: 2 years) */
115
+ cookieMaxAge?: number;
116
+ };
117
+ /**
118
+ * When to record pageView:
119
+ * - "server": in middleware (default, more reliable)
120
+ * - "client-init": when JS loads (has client context) - NOT SUPPORTED CURRENTLU
121
+ */
122
+ pageViewMode?: "server" | "client-init";
123
+ /** Skip tracking for API routes */
124
+ excludeApiCalls?: boolean;
125
+ /** Skip tracking for specific paths */
126
+ excludePaths?: (path: string) => boolean;
127
+ /** Determine if path is API route. Default: () => false */
128
+ isApiPath?: (path: string) => boolean;
129
+ /** Endpoint for client events. Default: "/api/event" */
130
+ eventEndpoint?: string;
131
+ callbacks: {
132
+ /** Resolve authenticated user from request context */
133
+ getUser?: (ctx: RequestContext) => Promise<UserContext | undefined>;
134
+ /** Override anonymous user ID generation */
135
+ getAnonymousUserId?: (opts: {
136
+ ctx: RequestContext;
137
+ originalAnonymousUserId?: string;
138
+ }) => Promise<AnonymousUserResult>;
139
+ };
140
+ /** Analytics backends to send events to */
141
+ backends?: (NextlyticsBackend | NextlyticsBackendFactory)[];
142
+ plugins?: (NextlyticsPlugin | NextlyticsPluginFactory)[];
143
+ };
144
+ type ClientAction = {
145
+ items: ClientActionItem[];
146
+ };
147
+ type ClientActionItem = TemplatizedScriptInsertion<unknown>;
148
+ /**
149
+ * Inserts scripts to a page as
150
+ * `<script scr={src}></script>` or <script>{body}</script>
151
+ */
152
+ type TemplatizedScriptInsertion<T> = {
153
+ type: "script-template";
154
+ params: T;
155
+ templateId: string;
156
+ };
157
+ /** Result of dispatching an event (two-phase) */
158
+ type DispatchResult = {
159
+ /** Resolves quickly with actions from backends with returnsClientActions=true */
160
+ clientActions: Promise<ClientAction>;
161
+ /** Resolves when ALL backends complete processing */
162
+ completion: Promise<void>;
163
+ };
164
+ type JavascriptTemplate = {
165
+ items: ScriptElement[];
166
+ };
167
+ type ScriptElement = {
168
+ async?: string;
169
+ body?: string;
170
+ src?: string;
171
+ /** If true, skip insertion if script with same src already exists */
172
+ singleton?: boolean;
173
+ };
174
+ /** Backend that receives analytics events */
175
+ type NextlyticsBackend = {
176
+ /** Backend name for logging */
177
+ name: string;
178
+ /** Whether backend supports updating existing events */
179
+ supportsUpdates?: boolean;
180
+ /**
181
+ * If onEvent can return client actions
182
+ */
183
+ returnsClientActions?: boolean;
184
+ getClientSideTemplates?: () => Record<string, JavascriptTemplate>;
185
+ /** Handle new event */
186
+ onEvent(event: NextlyticsEvent): Promise<void | ClientAction>;
187
+ /** Update existing event (e.g. add client context to server pageView) */
188
+ updateEvent(eventId: string, patch: Partial<NextlyticsEvent>): Promise<void> | void;
189
+ };
190
+ /** Factory to create backend per-request (for request-scoped backends) */
191
+ type NextlyticsBackendFactory = (ctx: RequestContext) => NextlyticsBackend;
192
+ /** Server-side analytics API */
193
+ type NextlyticsServerSide = {
194
+ /** Send custom event from server component/action */
195
+ sendEvent: (eventName: string, opts?: {
196
+ props?: Record<string, unknown>;
197
+ }) => Promise<{
198
+ ok: boolean;
199
+ }>;
200
+ };
201
+ type AppRouteHandlers = Record<"GET" | "POST", (req: NextRequest) => Promise<Response>>;
202
+ /** Return value from Nextlytics() */
203
+ type NextlyticsResult = {
204
+ /** Route handlers for /api/event */
205
+ handlers: AppRouteHandlers;
206
+ /** Get server-side analytics API */
207
+ analytics: () => Promise<NextlyticsServerSide>;
208
+ /** Middleware to intercept requests */
209
+ middleware: NextMiddleware;
210
+ /** Manually dispatch event (returns two-phase result) */
211
+ dispatchEvent: (event: NextlyticsEvent) => Promise<DispatchResult>;
212
+ /** Manually update existing event */
213
+ updateEvent: (eventId: string, patch: Partial<NextlyticsEvent>) => Promise<void>;
214
+ };
215
+
216
+ export type { AnonymousUserResult, ClientAction, ClientActionItem, ClientContext, DispatchResult, JavascriptTemplate, NextlyticsBackend, NextlyticsBackendFactory, NextlyticsConfig, NextlyticsEvent, NextlyticsPlugin, NextlyticsPluginFactory, NextlyticsResult, NextlyticsServerSide, RequestContext, ScriptElement, ServerEventContext, TemplatizedScriptInsertion, UserContext };