@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.
- package/dist/anonymous-user.cjs +118 -0
- package/dist/anonymous-user.d.mts +22 -0
- package/dist/anonymous-user.d.ts +22 -0
- package/dist/anonymous-user.js +94 -0
- package/dist/backends/clickhouse.cjs +110 -0
- package/dist/backends/clickhouse.d.mts +58 -0
- package/dist/backends/clickhouse.d.ts +58 -0
- package/dist/backends/clickhouse.js +92 -0
- package/dist/backends/ga.cjs +207 -0
- package/dist/backends/ga.d.mts +21 -0
- package/dist/backends/ga.d.ts +21 -0
- package/dist/backends/ga.js +183 -0
- package/dist/backends/gtm.cjs +155 -0
- package/dist/backends/gtm.d.mts +11 -0
- package/dist/backends/gtm.d.ts +11 -0
- package/dist/backends/gtm.js +131 -0
- package/dist/backends/lib/db.cjs +150 -0
- package/dist/backends/lib/db.d.mts +121 -0
- package/dist/backends/lib/db.d.ts +121 -0
- package/dist/backends/lib/db.js +119 -0
- package/dist/backends/logging.cjs +45 -0
- package/dist/backends/logging.d.mts +7 -0
- package/dist/backends/logging.d.ts +7 -0
- package/dist/backends/logging.js +21 -0
- package/dist/backends/neon.cjs +84 -0
- package/dist/backends/neon.d.mts +11 -0
- package/dist/backends/neon.d.ts +11 -0
- package/dist/backends/neon.js +66 -0
- package/dist/backends/postgrest.cjs +98 -0
- package/dist/backends/postgrest.d.mts +46 -0
- package/dist/backends/postgrest.d.ts +46 -0
- package/dist/backends/postgrest.js +73 -0
- package/dist/backends/posthog.cjs +120 -0
- package/dist/backends/posthog.d.mts +13 -0
- package/dist/backends/posthog.d.ts +13 -0
- package/dist/backends/posthog.js +96 -0
- package/dist/backends/segment.cjs +112 -0
- package/dist/backends/segment.d.mts +43 -0
- package/dist/backends/segment.d.ts +43 -0
- package/dist/backends/segment.js +88 -0
- package/dist/client.cjs +171 -0
- package/dist/client.d.mts +29 -0
- package/dist/client.d.ts +29 -0
- package/dist/client.js +146 -0
- package/dist/config-helpers.cjs +71 -0
- package/dist/config-helpers.d.mts +16 -0
- package/dist/config-helpers.d.ts +16 -0
- package/dist/config-helpers.js +45 -0
- package/dist/handlers.cjs +123 -0
- package/dist/handlers.d.mts +9 -0
- package/dist/handlers.d.ts +9 -0
- package/dist/handlers.js +99 -0
- package/dist/headers.cjs +41 -0
- package/dist/headers.d.mts +3 -0
- package/dist/headers.d.ts +3 -0
- package/dist/headers.js +17 -0
- package/dist/index.cjs +41 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +12 -0
- package/dist/middleware.cjs +204 -0
- package/dist/middleware.d.mts +10 -0
- package/dist/middleware.d.ts +10 -0
- package/dist/middleware.js +183 -0
- package/dist/pages-router.cjs +45 -0
- package/dist/pages-router.d.mts +45 -0
- package/dist/pages-router.d.ts +45 -0
- package/dist/pages-router.js +21 -0
- package/dist/plugins/vercel-geo.cjs +60 -0
- package/dist/plugins/vercel-geo.d.mts +25 -0
- package/dist/plugins/vercel-geo.d.ts +25 -0
- package/dist/plugins/vercel-geo.js +36 -0
- package/dist/server-component-context.cjs +95 -0
- package/dist/server-component-context.d.mts +30 -0
- package/dist/server-component-context.d.ts +30 -0
- package/dist/server-component-context.js +69 -0
- package/dist/server.cjs +236 -0
- package/dist/server.d.mts +13 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +213 -0
- package/dist/template.cjs +108 -0
- package/dist/template.d.mts +27 -0
- package/dist/template.d.ts +27 -0
- package/dist/template.js +83 -0
- package/dist/types.cjs +16 -0
- package/dist/types.d.mts +216 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.js +0 -0
- package/dist/uitils.cjs +94 -0
- package/dist/uitils.d.mts +22 -0
- package/dist/uitils.d.ts +22 -0
- package/dist/uitils.js +68 -0
- 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 };
|
package/dist/handlers.js
ADDED
|
@@ -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
|
+
};
|
package/dist/headers.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 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
|
+
});
|
package/dist/headers.js
ADDED
|
@@ -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
|
+
});
|
package/dist/index.d.mts
ADDED
|
@@ -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';
|
package/dist/index.d.ts
ADDED
|
@@ -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';
|