@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
@@ -0,0 +1,25 @@
1
+ import { NextlyticsPlugin } from '../types.js';
2
+ import 'next/dist/server/web/spec-extension/cookies';
3
+ import 'next/server';
4
+
5
+ type VercelGeoPluginOptions = {
6
+ /** Property name to store geo data under. Default: "geo" */
7
+ geoPropertyName?: string;
8
+ };
9
+ /**
10
+ * Plugin that extracts Vercel geo headers and adds them to event properties.
11
+ * Only works when deployed to Vercel.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { vercelGeoPlugin } from "@nextlytics/core/plugins/vercel-geo";
16
+ *
17
+ * export const { middleware, handlers } = Nextlytics({
18
+ * plugins: [vercelGeoPlugin()],
19
+ * // ...
20
+ * });
21
+ * ```
22
+ */
23
+ declare function vercelGeoPlugin(options?: VercelGeoPluginOptions): NextlyticsPlugin;
24
+
25
+ export { type VercelGeoPluginOptions, vercelGeoPlugin };
@@ -0,0 +1,36 @@
1
+ const VERCEL_GEO_HEADERS = {
2
+ "x-vercel-ip-country": "country",
3
+ "x-vercel-ip-country-region": "region",
4
+ "x-vercel-ip-city": "city",
5
+ "x-vercel-ip-latitude": "latitude",
6
+ "x-vercel-ip-longitude": "longitude",
7
+ "x-vercel-ip-timezone": "timezone"
8
+ };
9
+ function vercelGeoPlugin(options) {
10
+ const geoPropertyName = options?.geoPropertyName ?? "geo";
11
+ return {
12
+ async onDispatch(event) {
13
+ const headers = event.serverContext.requestHeaders;
14
+ const geo = {};
15
+ for (const [header, prop] of Object.entries(VERCEL_GEO_HEADERS)) {
16
+ const value = headers[header];
17
+ if (value) {
18
+ if (prop === "latitude" || prop === "longitude") {
19
+ const num = parseFloat(value);
20
+ if (!isNaN(num)) {
21
+ geo[prop] = num;
22
+ }
23
+ } else {
24
+ geo[prop] = value;
25
+ }
26
+ }
27
+ }
28
+ if (Object.keys(geo).length > 0) {
29
+ event.properties[geoPropertyName] = geo;
30
+ }
31
+ }
32
+ };
33
+ }
34
+ export {
35
+ vercelGeoPlugin
36
+ };
@@ -0,0 +1,95 @@
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 server_component_context_exports = {};
20
+ __export(server_component_context_exports, {
21
+ headers: () => headerKeys,
22
+ restoreServerComponentContext: () => restoreServerComponentContext,
23
+ serializeServerComponentContext: () => serializeServerComponentContext
24
+ });
25
+ module.exports = __toCommonJS(server_component_context_exports);
26
+ const HEADER_PREFIX = "x-nc-";
27
+ const headerKeys = {
28
+ pathname: `${HEADER_PREFIX}pathname`,
29
+ search: `${HEADER_PREFIX}search`,
30
+ pageRenderId: `${HEADER_PREFIX}page-render-id`,
31
+ scripts: `${HEADER_PREFIX}scripts`,
32
+ templates: `${HEADER_PREFIX}templates`
33
+ };
34
+ function serializeServerComponentContext(response, ctx) {
35
+ response.headers.set(headerKeys.pageRenderId, ctx.pageRenderId);
36
+ response.headers.set(headerKeys.pathname, ctx.pathname);
37
+ response.headers.set(headerKeys.search, ctx.search);
38
+ if (ctx.scripts.length > 0) {
39
+ const scriptParts = ctx.scripts.filter((item) => item.type === "script-template").map((s) => `${s.templateId}=${JSON.stringify(s.params)}`);
40
+ if (scriptParts.length > 0) {
41
+ response.headers.set(headerKeys.scripts, scriptParts.join(";"));
42
+ }
43
+ }
44
+ if (Object.keys(ctx.templates).length > 0) {
45
+ response.headers.set(headerKeys.templates, JSON.stringify(ctx.templates));
46
+ }
47
+ }
48
+ function parseScriptsHeader(header) {
49
+ const scripts = [];
50
+ for (const part of header.split(";")) {
51
+ const eqIdx = part.indexOf("=");
52
+ if (eqIdx === -1) continue;
53
+ const templateId = part.slice(0, eqIdx);
54
+ const paramsJson = part.slice(eqIdx + 1);
55
+ try {
56
+ const params = JSON.parse(paramsJson);
57
+ scripts.push({ type: "script-template", templateId, params });
58
+ } catch {
59
+ console.warn(`[Nextlytics] Failed to parse script params for ${templateId}`);
60
+ }
61
+ }
62
+ return scripts;
63
+ }
64
+ function restoreServerComponentContext(headersList) {
65
+ const pageRenderId = headersList.get(headerKeys.pageRenderId);
66
+ if (!pageRenderId) {
67
+ return null;
68
+ }
69
+ const pathname = headersList.get(headerKeys.pathname) || "";
70
+ const search = headersList.get(headerKeys.search) || "";
71
+ const scriptsHeader = headersList.get(headerKeys.scripts);
72
+ const scripts = scriptsHeader ? parseScriptsHeader(scriptsHeader) : [];
73
+ let templates = {};
74
+ const templatesHeader = headersList.get(headerKeys.templates);
75
+ if (templatesHeader) {
76
+ try {
77
+ templates = JSON.parse(templatesHeader);
78
+ } catch {
79
+ console.warn("[Nextlytics] Failed to parse templates header");
80
+ }
81
+ }
82
+ return {
83
+ pageRenderId,
84
+ pathname,
85
+ search,
86
+ scripts,
87
+ templates
88
+ };
89
+ }
90
+ // Annotate the CommonJS export names for ESM import in node:
91
+ 0 && (module.exports = {
92
+ headers,
93
+ restoreServerComponentContext,
94
+ serializeServerComponentContext
95
+ });
@@ -0,0 +1,30 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { TemplatizedScriptInsertion, JavascriptTemplate } from './types.mjs';
3
+ import 'next/dist/server/web/spec-extension/cookies';
4
+
5
+ declare const headerKeys: {
6
+ readonly pathname: "x-nc-pathname";
7
+ readonly search: "x-nc-search";
8
+ readonly pageRenderId: "x-nc-page-render-id";
9
+ readonly scripts: "x-nc-scripts";
10
+ readonly templates: "x-nc-templates";
11
+ };
12
+ /** Context passed from middleware to server components via headers */
13
+ type ServerComponentContext = {
14
+ /** Unique page render ID (event ID) */
15
+ pageRenderId: string;
16
+ /** Request pathname */
17
+ pathname: string;
18
+ /** Query string */
19
+ search: string;
20
+ /** Script actions to execute on client */
21
+ scripts: TemplatizedScriptInsertion<unknown>[];
22
+ /** Template definitions for scripts */
23
+ templates: Record<string, JavascriptTemplate>;
24
+ };
25
+ /** Serialize context to response headers (called in middleware) */
26
+ declare function serializeServerComponentContext(response: NextResponse, ctx: ServerComponentContext): void;
27
+ /** Restore context from request headers (called in server components) */
28
+ declare function restoreServerComponentContext(headersList: Headers): ServerComponentContext | null;
29
+
30
+ export { type ServerComponentContext, headerKeys as headers, restoreServerComponentContext, serializeServerComponentContext };
@@ -0,0 +1,30 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { TemplatizedScriptInsertion, JavascriptTemplate } from './types.js';
3
+ import 'next/dist/server/web/spec-extension/cookies';
4
+
5
+ declare const headerKeys: {
6
+ readonly pathname: "x-nc-pathname";
7
+ readonly search: "x-nc-search";
8
+ readonly pageRenderId: "x-nc-page-render-id";
9
+ readonly scripts: "x-nc-scripts";
10
+ readonly templates: "x-nc-templates";
11
+ };
12
+ /** Context passed from middleware to server components via headers */
13
+ type ServerComponentContext = {
14
+ /** Unique page render ID (event ID) */
15
+ pageRenderId: string;
16
+ /** Request pathname */
17
+ pathname: string;
18
+ /** Query string */
19
+ search: string;
20
+ /** Script actions to execute on client */
21
+ scripts: TemplatizedScriptInsertion<unknown>[];
22
+ /** Template definitions for scripts */
23
+ templates: Record<string, JavascriptTemplate>;
24
+ };
25
+ /** Serialize context to response headers (called in middleware) */
26
+ declare function serializeServerComponentContext(response: NextResponse, ctx: ServerComponentContext): void;
27
+ /** Restore context from request headers (called in server components) */
28
+ declare function restoreServerComponentContext(headersList: Headers): ServerComponentContext | null;
29
+
30
+ export { type ServerComponentContext, headerKeys as headers, restoreServerComponentContext, serializeServerComponentContext };
@@ -0,0 +1,69 @@
1
+ const HEADER_PREFIX = "x-nc-";
2
+ const headerKeys = {
3
+ pathname: `${HEADER_PREFIX}pathname`,
4
+ search: `${HEADER_PREFIX}search`,
5
+ pageRenderId: `${HEADER_PREFIX}page-render-id`,
6
+ scripts: `${HEADER_PREFIX}scripts`,
7
+ templates: `${HEADER_PREFIX}templates`
8
+ };
9
+ function serializeServerComponentContext(response, ctx) {
10
+ response.headers.set(headerKeys.pageRenderId, ctx.pageRenderId);
11
+ response.headers.set(headerKeys.pathname, ctx.pathname);
12
+ response.headers.set(headerKeys.search, ctx.search);
13
+ if (ctx.scripts.length > 0) {
14
+ const scriptParts = ctx.scripts.filter((item) => item.type === "script-template").map((s) => `${s.templateId}=${JSON.stringify(s.params)}`);
15
+ if (scriptParts.length > 0) {
16
+ response.headers.set(headerKeys.scripts, scriptParts.join(";"));
17
+ }
18
+ }
19
+ if (Object.keys(ctx.templates).length > 0) {
20
+ response.headers.set(headerKeys.templates, JSON.stringify(ctx.templates));
21
+ }
22
+ }
23
+ function parseScriptsHeader(header) {
24
+ const scripts = [];
25
+ for (const part of header.split(";")) {
26
+ const eqIdx = part.indexOf("=");
27
+ if (eqIdx === -1) continue;
28
+ const templateId = part.slice(0, eqIdx);
29
+ const paramsJson = part.slice(eqIdx + 1);
30
+ try {
31
+ const params = JSON.parse(paramsJson);
32
+ scripts.push({ type: "script-template", templateId, params });
33
+ } catch {
34
+ console.warn(`[Nextlytics] Failed to parse script params for ${templateId}`);
35
+ }
36
+ }
37
+ return scripts;
38
+ }
39
+ function restoreServerComponentContext(headersList) {
40
+ const pageRenderId = headersList.get(headerKeys.pageRenderId);
41
+ if (!pageRenderId) {
42
+ return null;
43
+ }
44
+ const pathname = headersList.get(headerKeys.pathname) || "";
45
+ const search = headersList.get(headerKeys.search) || "";
46
+ const scriptsHeader = headersList.get(headerKeys.scripts);
47
+ const scripts = scriptsHeader ? parseScriptsHeader(scriptsHeader) : [];
48
+ let templates = {};
49
+ const templatesHeader = headersList.get(headerKeys.templates);
50
+ if (templatesHeader) {
51
+ try {
52
+ templates = JSON.parse(templatesHeader);
53
+ } catch {
54
+ console.warn("[Nextlytics] Failed to parse templates header");
55
+ }
56
+ }
57
+ return {
58
+ pageRenderId,
59
+ pathname,
60
+ search,
61
+ scripts,
62
+ templates
63
+ };
64
+ }
65
+ export {
66
+ headerKeys as headers,
67
+ restoreServerComponentContext,
68
+ serializeServerComponentContext
69
+ };
@@ -0,0 +1,236 @@
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 server_exports = {};
20
+ __export(server_exports, {
21
+ Nextlytics: () => Nextlytics,
22
+ NextlyticsServer: () => NextlyticsServer,
23
+ createRequestContext: () => createRequestContext
24
+ });
25
+ module.exports = __toCommonJS(server_exports);
26
+ var import_jsx_runtime = require("react/jsx-runtime");
27
+ var import_headers = require("next/headers");
28
+ var import_headers2 = require("./headers");
29
+ var import_server_component_context = require("./server-component-context");
30
+ var import_anonymous_user = require("./anonymous-user");
31
+ var import_client = require("./client");
32
+ var import_handlers = require("./handlers");
33
+ var import_config_helpers = require("./config-helpers");
34
+ var import_middleware = require("./middleware");
35
+ var import_uitils = require("./uitils");
36
+ function resolveBackends(config, ctx) {
37
+ const backends = config.backends || [];
38
+ return backends.map((backend) => {
39
+ if (typeof backend === "function") {
40
+ return backend(ctx);
41
+ }
42
+ return backend;
43
+ }).filter((b) => b !== null);
44
+ }
45
+ function resolvePlugins(config, ctx) {
46
+ const plugins = config.plugins || [];
47
+ return plugins.map((plugin) => {
48
+ if (typeof plugin === "function") {
49
+ if (!ctx) {
50
+ return null;
51
+ }
52
+ return plugin(ctx);
53
+ }
54
+ return plugin;
55
+ }).filter((p) => p !== null);
56
+ }
57
+ function mergeClientActions(actions) {
58
+ const items = [];
59
+ for (const action of actions) {
60
+ if (action?.items) {
61
+ items.push(...action.items);
62
+ }
63
+ }
64
+ return { items };
65
+ }
66
+ async function createRequestContext() {
67
+ const [_cookies, _headers] = await Promise.all([(0, import_headers.cookies)(), (0, import_headers.headers)()]);
68
+ return {
69
+ cookies: _cookies,
70
+ headers: _headers
71
+ };
72
+ }
73
+ async function NextlyticsServer({ children }) {
74
+ const headersList = await (0, import_headers.headers)();
75
+ const ctx = (0, import_server_component_context.restoreServerComponentContext)(headersList);
76
+ if (!ctx) {
77
+ console.warn(
78
+ "[Nextlytics] nextlyticsMiddleware should be added in order for NextlyticsServer to work"
79
+ );
80
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
81
+ }
82
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_client.NextlyticsClient, { requestId: ctx.pageRenderId, scripts: ctx.scripts, templates: ctx.templates, children });
83
+ }
84
+ function Nextlytics(userConfig) {
85
+ const config = (0, import_config_helpers.withDefaults)(userConfig);
86
+ const validationResult = (0, import_config_helpers.validateConfig)(config);
87
+ (0, import_config_helpers.logConfigWarnings)(validationResult);
88
+ const dispatchEventInternal = (event, ctx) => {
89
+ const plugins = resolvePlugins(config, ctx);
90
+ const backends = resolveBackends(config, ctx);
91
+ const pluginsDone = (async () => {
92
+ for (const plugin of plugins) {
93
+ try {
94
+ await plugin.onDispatch(event);
95
+ } catch (err) {
96
+ console.warn("[Nextlytics] Plugin failed on onDispatch:", err);
97
+ }
98
+ }
99
+ })();
100
+ const backendResults = pluginsDone.then(() => {
101
+ return backends.map((backend) => {
102
+ const start = Date.now();
103
+ const promise = backend.onEvent(event).then((result) => ({ ok: true, ms: Date.now() - start, result })).catch((err) => {
104
+ console.warn(`[Nextlytics] Backend "${backend.name}" failed on onEvent:`, err);
105
+ return { ok: false, ms: Date.now() - start, result: void 0 };
106
+ });
107
+ return { backend, promise };
108
+ });
109
+ });
110
+ const clientActions = backendResults.then(async (results) => {
111
+ const actionResults = results.filter((r) => r.backend.returnsClientActions);
112
+ const actions = await Promise.all(actionResults.map((r) => r.promise));
113
+ return mergeClientActions(actions.map((a) => a.result));
114
+ });
115
+ const completion = backendResults.then(async (results) => {
116
+ const settled = await Promise.all(results.map((r) => r.promise));
117
+ if (config.debug) {
118
+ const nameWidth = Math.max(...results.map((r) => r.backend.name.length));
119
+ console.log(
120
+ `[Nextlytics] dispatchEvent ${event.type} ${event.eventId} (${results.length} backends)`
121
+ );
122
+ results.forEach((r, i) => {
123
+ const s = settled[i];
124
+ const status = s.ok ? "ok" : "fail";
125
+ console.log(` ${r.backend.name.padEnd(nameWidth)} ${status.padEnd(4)} ${s.ms}ms`);
126
+ });
127
+ }
128
+ }).then(() => {
129
+ });
130
+ return { clientActions, completion };
131
+ };
132
+ const updateEventInternal = async (eventId, patch, ctx) => {
133
+ const backends = resolveBackends(config, ctx).filter((backend) => backend.supportsUpdates);
134
+ const results = await Promise.all(
135
+ backends.map(async (backend) => {
136
+ const start = Date.now();
137
+ try {
138
+ await backend.updateEvent(eventId, patch);
139
+ return { backend, ok: true, ms: Date.now() - start };
140
+ } catch (err) {
141
+ console.warn(`[Nextlytics] Backend "${backend.name}" failed on updateEvent:`, err);
142
+ return { backend, ok: false, ms: Date.now() - start };
143
+ }
144
+ })
145
+ );
146
+ if (config.debug && backends.length > 0) {
147
+ const nameWidth = Math.max(...backends.map((b) => b.name.length));
148
+ console.log(`[Nextlytics] updateEvent ${eventId} (${backends.length} backends)`);
149
+ results.forEach((r) => {
150
+ const status = r.ok ? "ok" : "fail";
151
+ console.log(` ${r.backend.name.padEnd(nameWidth)} ${status.padEnd(4)} ${r.ms}ms`);
152
+ });
153
+ }
154
+ };
155
+ const dispatchEvent = async (event) => {
156
+ const ctx = await createRequestContext();
157
+ return dispatchEventInternal(event, ctx);
158
+ };
159
+ const updateEvent = async (eventId, patch) => {
160
+ const ctx = await createRequestContext();
161
+ return updateEventInternal(eventId, patch, ctx);
162
+ };
163
+ const middleware = (0, import_middleware.createNextlyticsMiddleware)(config, dispatchEventInternal, updateEventInternal);
164
+ const handlers = (0, import_handlers.createHandlers)(config, dispatchEventInternal, updateEventInternal);
165
+ const analytics = async () => {
166
+ const headersList = await (0, import_headers.headers)();
167
+ const cookieStore = await (0, import_headers.cookies)();
168
+ const pageRenderId = headersList.get(import_server_component_context.headers.pageRenderId);
169
+ const serverContext = createServerContextFromHeaders(headersList);
170
+ const ctx = { headers: headersList, cookies: cookieStore };
171
+ const { anonId: anonymousUserId } = await (0, import_anonymous_user.resolveAnonymousUser)({ ctx, serverContext, config });
172
+ let userContext;
173
+ if (config.callbacks.getUser) {
174
+ try {
175
+ userContext = await config.callbacks.getUser(ctx) || void 0;
176
+ } catch {
177
+ }
178
+ }
179
+ return {
180
+ sendEvent: async (eventName, opts) => {
181
+ if (!pageRenderId) {
182
+ console.error("[Nextlytics] analytics() requires nextlyticsMiddleware");
183
+ return { ok: false };
184
+ }
185
+ const event = {
186
+ eventId: (0, import_uitils.generateId)(),
187
+ parentEventId: pageRenderId,
188
+ type: eventName,
189
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
190
+ anonymousUserId,
191
+ serverContext,
192
+ userContext,
193
+ properties: opts?.props || {}
194
+ };
195
+ await dispatchEventInternal(event, ctx);
196
+ return { ok: true };
197
+ }
198
+ };
199
+ };
200
+ return { middleware, handlers, analytics, dispatchEvent, updateEvent };
201
+ }
202
+ function createServerContextFromHeaders(headersList) {
203
+ const rawHeaders = {};
204
+ headersList.forEach((value, key) => {
205
+ rawHeaders[key] = value;
206
+ });
207
+ const requestHeaders = (0, import_headers2.removeSensitiveHeaders)(rawHeaders);
208
+ const pathname = headersList.get(import_server_component_context.headers.pathname) || "";
209
+ const search = headersList.get(import_server_component_context.headers.search) || "";
210
+ const searchParams = {};
211
+ if (search) {
212
+ const params = new URLSearchParams(search);
213
+ params.forEach((value, key) => {
214
+ if (!searchParams[key]) {
215
+ searchParams[key] = [];
216
+ }
217
+ searchParams[key].push(value);
218
+ });
219
+ }
220
+ return {
221
+ collectedAt: /* @__PURE__ */ new Date(),
222
+ host: headersList.get("host") || "",
223
+ method: "GET",
224
+ path: pathname,
225
+ search: searchParams,
226
+ ip: headersList.get("x-forwarded-for")?.split(",")[0]?.trim() || "",
227
+ requestHeaders,
228
+ responseHeaders: {}
229
+ };
230
+ }
231
+ // Annotate the CommonJS export names for ESM import in node:
232
+ 0 && (module.exports = {
233
+ Nextlytics,
234
+ NextlyticsServer,
235
+ createRequestContext
236
+ });
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { NextlyticsConfig, NextlyticsResult, RequestContext } from './types.mjs';
4
+ import 'next/dist/server/web/spec-extension/cookies';
5
+ import 'next/server';
6
+
7
+ declare function createRequestContext(): Promise<RequestContext>;
8
+ declare function NextlyticsServer({ children }: {
9
+ children: ReactNode;
10
+ }): Promise<react_jsx_runtime.JSX.Element>;
11
+ declare function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult;
12
+
13
+ export { Nextlytics, NextlyticsServer, createRequestContext };
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { NextlyticsConfig, NextlyticsResult, RequestContext } from './types.js';
4
+ import 'next/dist/server/web/spec-extension/cookies';
5
+ import 'next/server';
6
+
7
+ declare function createRequestContext(): Promise<RequestContext>;
8
+ declare function NextlyticsServer({ children }: {
9
+ children: ReactNode;
10
+ }): Promise<react_jsx_runtime.JSX.Element>;
11
+ declare function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult;
12
+
13
+ export { Nextlytics, NextlyticsServer, createRequestContext };