@nextlytics/core 0.3.0-canary.80 → 0.3.0
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/backends/ga.d.ts +0 -5
- package/dist/backends/ga.js +17 -93
- package/dist/backends/gtm.js +8 -25
- package/dist/backends/logging.js +0 -33
- package/dist/backends/segment.js +0 -1
- package/dist/client.d.ts +4 -1
- package/dist/client.js +67 -141
- package/dist/config-helpers.js +1 -1
- package/dist/handlers.d.ts +12 -0
- package/dist/handlers.js +40 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -1
- package/dist/middleware.d.ts +3 -2
- package/dist/middleware.js +127 -39
- package/dist/pages-router.d.ts +31 -6
- package/dist/pages-router.js +2 -1
- package/dist/server-component-context.d.ts +11 -10
- package/dist/server-component-context.js +28 -18
- package/dist/server.d.ts +6 -1
- package/dist/server.js +21 -40
- package/dist/types.d.ts +18 -61
- package/dist/uitils.d.ts +1 -7
- package/dist/uitils.js +5 -39
- package/package.json +1 -1
- package/dist/api-handler.d.ts +0 -11
- package/dist/api-handler.js +0 -182
- package/dist/client-utils.d.ts +0 -35
- package/dist/client-utils.js +0 -121
- package/dist/stable-hash.d.ts +0 -6
- package/dist/stable-hash.js +0 -76
package/dist/backends/ga.d.ts
CHANGED
|
@@ -15,11 +15,6 @@ type GoogleAnalyticsBackendOptions = {
|
|
|
15
15
|
* - "anonymousUserId": Always use Nextlytics anonymousUserId
|
|
16
16
|
*/
|
|
17
17
|
clientIdSource?: "gaCookie" | "anonymousUserId";
|
|
18
|
-
/**
|
|
19
|
-
* Prefer sending client-origin events from the browser (gtag) instead of Measurement Protocol.
|
|
20
|
-
* Default: true. Set to false to force Measurement Protocol when apiSecret is provided.
|
|
21
|
-
*/
|
|
22
|
-
preferClientSideForClientEvents?: boolean;
|
|
23
18
|
};
|
|
24
19
|
declare function googleAnalyticsBackend(opts: GoogleAnalyticsBackendOptions): NextlyticsBackendFactory;
|
|
25
20
|
|
package/dist/backends/ga.js
CHANGED
|
@@ -21,9 +21,7 @@ __export(ga_exports, {
|
|
|
21
21
|
googleAnalyticsBackend: () => googleAnalyticsBackend
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(ga_exports);
|
|
24
|
-
const
|
|
25
|
-
const GA_PROPERTIES_TEMPLATE = "ga-properties";
|
|
26
|
-
const GA_EVENT_TEMPLATE = "ga-event";
|
|
24
|
+
const GA_TEMPLATE_ID = "ga-gtag";
|
|
27
25
|
function parseGaCookie(cookieValue) {
|
|
28
26
|
const match = cookieValue.match(/^GA\d+\.\d+\.(.+)$/);
|
|
29
27
|
return match ? match[1] : null;
|
|
@@ -120,51 +118,27 @@ function googleAnalyticsBackend(opts) {
|
|
|
120
118
|
return (ctx) => {
|
|
121
119
|
const gaCookie = ctx.cookies.get("_ga");
|
|
122
120
|
const gaCookieClientId = gaCookie ? parseGaCookie(gaCookie.value) : null;
|
|
123
|
-
const preferClientSideForClientEvents = opts.preferClientSideForClientEvents ?? true;
|
|
124
121
|
return {
|
|
125
122
|
name: "google-analytics",
|
|
126
123
|
returnsClientActions: true,
|
|
127
124
|
supportsUpdates: false,
|
|
128
125
|
getClientSideTemplates() {
|
|
129
126
|
return {
|
|
130
|
-
[
|
|
131
|
-
deps: "{{eventId}}",
|
|
127
|
+
[GA_TEMPLATE_ID]: {
|
|
132
128
|
items: [
|
|
133
|
-
// Update user properties for this event (if provided)
|
|
134
|
-
{
|
|
135
|
-
body: [
|
|
136
|
-
"gtag('set', {{json(properties)}});",
|
|
137
|
-
"gtag('event', '{{eventName}}', {{json(eventParams)}});"
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
]
|
|
141
|
-
},
|
|
142
|
-
[GA_INIT_TEMPLATE]: {
|
|
143
|
-
deps: "{{measurementId}}{{json(initial_config)}}",
|
|
144
|
-
items: [
|
|
145
|
-
// External gtag.js - load once
|
|
146
129
|
{
|
|
130
|
+
async: "true",
|
|
147
131
|
src: "https://www.googletagmanager.com/gtag/js?id={{measurementId}}",
|
|
148
|
-
|
|
132
|
+
singleton: true
|
|
149
133
|
},
|
|
150
|
-
// gtag definition and initialization - run once
|
|
151
134
|
{
|
|
152
135
|
body: [
|
|
153
136
|
"window.dataLayer = window.dataLayer || [];",
|
|
154
|
-
|
|
155
|
-
"window.gtag = gtag;",
|
|
137
|
+
"function gtag(){dataLayer.push(arguments);}",
|
|
156
138
|
"gtag('js', new Date());",
|
|
157
|
-
"gtag('config', '{{measurementId}}', {{json(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
]
|
|
161
|
-
},
|
|
162
|
-
[GA_PROPERTIES_TEMPLATE]: {
|
|
163
|
-
deps: "{{json(properties)}}",
|
|
164
|
-
items: [
|
|
165
|
-
// Updates that should NOT trigger page_view (e.g., user_id, user_properties)
|
|
166
|
-
{
|
|
167
|
-
body: "gtag('set', {{json(properties)}});"
|
|
139
|
+
"gtag('config', '{{measurementId}}', {{json(config)}});",
|
|
140
|
+
"gtag('event', 'page_view');"
|
|
141
|
+
].join("\n")
|
|
168
142
|
}
|
|
169
143
|
]
|
|
170
144
|
}
|
|
@@ -181,66 +155,33 @@ function googleAnalyticsBackend(opts) {
|
|
|
181
155
|
} = event.userContext?.traits ?? {};
|
|
182
156
|
const userProperties = Object.keys(customTraits).length > 0 ? customTraits : void 0;
|
|
183
157
|
if (event.type === "pageView") {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
send_page_view: true,
|
|
158
|
+
const config = {
|
|
159
|
+
send_page_view: false,
|
|
187
160
|
client_id: clientId
|
|
188
161
|
};
|
|
189
162
|
if (debugMode) {
|
|
190
|
-
|
|
163
|
+
config.debug_mode = true;
|
|
191
164
|
}
|
|
192
|
-
const properties2 = {};
|
|
193
165
|
if (userId) {
|
|
194
|
-
|
|
166
|
+
config.user_id = userId;
|
|
195
167
|
}
|
|
196
168
|
if (userProperties) {
|
|
197
|
-
|
|
169
|
+
config.user_properties = userProperties;
|
|
198
170
|
}
|
|
199
171
|
return {
|
|
200
172
|
items: [
|
|
201
173
|
{
|
|
202
174
|
type: "script-template",
|
|
203
|
-
templateId:
|
|
175
|
+
templateId: GA_TEMPLATE_ID,
|
|
204
176
|
params: {
|
|
205
177
|
measurementId,
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
type: "script-template",
|
|
211
|
-
templateId: GA_PROPERTIES_TEMPLATE,
|
|
212
|
-
params: {
|
|
213
|
-
properties: properties2
|
|
178
|
+
config
|
|
214
179
|
}
|
|
215
180
|
}
|
|
216
181
|
]
|
|
217
182
|
};
|
|
218
183
|
}
|
|
219
|
-
|
|
220
|
-
const properties = {};
|
|
221
|
-
if (userId) {
|
|
222
|
-
properties.user_id = userId;
|
|
223
|
-
}
|
|
224
|
-
if (userProperties) {
|
|
225
|
-
properties.user_properties = userProperties;
|
|
226
|
-
}
|
|
227
|
-
if (event.origin === "client") {
|
|
228
|
-
if (preferClientSideForClientEvents || !apiSecret) {
|
|
229
|
-
return {
|
|
230
|
-
items: [
|
|
231
|
-
{
|
|
232
|
-
type: "script-template",
|
|
233
|
-
templateId: GA_EVENT_TEMPLATE,
|
|
234
|
-
params: {
|
|
235
|
-
eventId: event.eventId,
|
|
236
|
-
eventName: toGA4EventName(event.type),
|
|
237
|
-
eventParams,
|
|
238
|
-
properties
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
]
|
|
242
|
-
};
|
|
243
|
-
}
|
|
184
|
+
if (apiSecret) {
|
|
244
185
|
await sendToMeasurementProtocol({
|
|
245
186
|
measurementId,
|
|
246
187
|
apiSecret,
|
|
@@ -248,29 +189,12 @@ function googleAnalyticsBackend(opts) {
|
|
|
248
189
|
userId,
|
|
249
190
|
userProperties,
|
|
250
191
|
eventName: toGA4EventName(event.type),
|
|
251
|
-
eventParams,
|
|
192
|
+
eventParams: buildEventParams(event),
|
|
252
193
|
userAgent: getUserAgent(event),
|
|
253
194
|
clientIp: getClientIp(event),
|
|
254
195
|
debugMode
|
|
255
196
|
});
|
|
256
|
-
return void 0;
|
|
257
|
-
}
|
|
258
|
-
if (!apiSecret) {
|
|
259
|
-
return void 0;
|
|
260
197
|
}
|
|
261
|
-
await sendToMeasurementProtocol({
|
|
262
|
-
measurementId,
|
|
263
|
-
apiSecret,
|
|
264
|
-
clientId,
|
|
265
|
-
userId,
|
|
266
|
-
userProperties,
|
|
267
|
-
eventName: toGA4EventName(event.type),
|
|
268
|
-
eventParams,
|
|
269
|
-
userAgent: getUserAgent(event),
|
|
270
|
-
clientIp: getClientIp(event),
|
|
271
|
-
debugMode
|
|
272
|
-
});
|
|
273
|
-
return void 0;
|
|
274
198
|
},
|
|
275
199
|
updateEvent() {
|
|
276
200
|
}
|
package/dist/backends/gtm.js
CHANGED
|
@@ -22,7 +22,6 @@ __export(gtm_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(gtm_exports);
|
|
24
24
|
const GTM_INIT_TEMPLATE_ID = "gtm-init";
|
|
25
|
-
const GTM_INIT_DATA_TEMPLATE_ID = "gtm-init-data";
|
|
26
25
|
const GTM_PAGEVIEW_TEMPLATE_ID = "gtm-pageview";
|
|
27
26
|
const GTM_EVENT_TEMPLATE_ID = "gtm-event";
|
|
28
27
|
function toSnakeCase(str) {
|
|
@@ -38,27 +37,21 @@ function googleTagManagerBackend(opts) {
|
|
|
38
37
|
return {
|
|
39
38
|
[GTM_INIT_TEMPLATE_ID]: {
|
|
40
39
|
items: [
|
|
41
|
-
// GTM script loader - run once
|
|
42
40
|
{
|
|
43
41
|
body: [
|
|
44
42
|
"window.dataLayer = window.dataLayer || [];",
|
|
45
|
-
"(
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"'
|
|
49
|
-
"
|
|
43
|
+
"dataLayer.push({{json(initialData)}});",
|
|
44
|
+
"if (!window.google_tag_manager || !window.google_tag_manager['{{containerId}}']) {",
|
|
45
|
+
" (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':",
|
|
46
|
+
" new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],",
|
|
47
|
+
" j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=",
|
|
48
|
+
" 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);",
|
|
49
|
+
" })(window,document,'script','dataLayer','{{containerId}}');",
|
|
50
|
+
"}"
|
|
50
51
|
].join("\n")
|
|
51
52
|
}
|
|
52
53
|
]
|
|
53
54
|
},
|
|
54
|
-
[GTM_INIT_DATA_TEMPLATE_ID]: {
|
|
55
|
-
items: [
|
|
56
|
-
// Initial data push - run when params change (e.g., user logs in)
|
|
57
|
-
{
|
|
58
|
-
body: "dataLayer.push({{json(initialData)}});"
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
|
-
},
|
|
62
55
|
[GTM_PAGEVIEW_TEMPLATE_ID]: {
|
|
63
56
|
items: [
|
|
64
57
|
{
|
|
@@ -129,11 +122,6 @@ function googleTagManagerBackend(opts) {
|
|
|
129
122
|
if (event.clientContext) {
|
|
130
123
|
return {
|
|
131
124
|
items: [
|
|
132
|
-
{
|
|
133
|
-
type: "script-template",
|
|
134
|
-
templateId: GTM_INIT_DATA_TEMPLATE_ID,
|
|
135
|
-
params: { initialData }
|
|
136
|
-
},
|
|
137
125
|
{
|
|
138
126
|
type: "script-template",
|
|
139
127
|
templateId: GTM_PAGEVIEW_TEMPLATE_ID,
|
|
@@ -149,11 +137,6 @@ function googleTagManagerBackend(opts) {
|
|
|
149
137
|
templateId: GTM_INIT_TEMPLATE_ID,
|
|
150
138
|
params: { containerId, initialData }
|
|
151
139
|
},
|
|
152
|
-
{
|
|
153
|
-
type: "script-template",
|
|
154
|
-
templateId: GTM_INIT_DATA_TEMPLATE_ID,
|
|
155
|
-
params: { initialData }
|
|
156
|
-
},
|
|
157
140
|
{
|
|
158
141
|
type: "script-template",
|
|
159
142
|
templateId: GTM_PAGEVIEW_TEMPLATE_ID,
|
package/dist/backends/logging.js
CHANGED
|
@@ -21,24 +21,10 @@ __export(logging_exports, {
|
|
|
21
21
|
loggingBackend: () => loggingBackend
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(logging_exports);
|
|
24
|
-
const LOG_TEMPLATE_ID = "log-console";
|
|
25
24
|
function loggingBackend() {
|
|
26
25
|
return {
|
|
27
26
|
name: "logging",
|
|
28
27
|
supportsUpdates: true,
|
|
29
|
-
returnsClientActions: true,
|
|
30
|
-
getClientSideTemplates() {
|
|
31
|
-
return {
|
|
32
|
-
[LOG_TEMPLATE_ID]: {
|
|
33
|
-
deps: "{{eventId}}",
|
|
34
|
-
items: [
|
|
35
|
-
{
|
|
36
|
-
body: "console.log('[Nextlytics Log][client]', {{json(event)}});"
|
|
37
|
-
}
|
|
38
|
-
]
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
28
|
async onEvent(event) {
|
|
43
29
|
const { type, eventId, serverContext, ...rest } = event;
|
|
44
30
|
const method = serverContext?.method || "";
|
|
@@ -46,25 +32,6 @@ function loggingBackend() {
|
|
|
46
32
|
const route = method && path ? `${method} ${path}` : "";
|
|
47
33
|
console.log(`[Nextlytics Log] ${type}${route ? ` ${route}` : ""} (${eventId})`);
|
|
48
34
|
console.log(JSON.stringify({ serverContext, ...rest }, null, 2));
|
|
49
|
-
if (event.origin === "client") {
|
|
50
|
-
return {
|
|
51
|
-
items: [
|
|
52
|
-
{
|
|
53
|
-
type: "script-template",
|
|
54
|
-
templateId: LOG_TEMPLATE_ID,
|
|
55
|
-
params: {
|
|
56
|
-
eventId: event.eventId,
|
|
57
|
-
event: {
|
|
58
|
-
type: event.type,
|
|
59
|
-
eventProps: event.properties,
|
|
60
|
-
userProps: event.userContext
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return void 0;
|
|
68
35
|
},
|
|
69
36
|
updateEvent(eventId, patch) {
|
|
70
37
|
console.log(`[Nextlytics Log] Update ${eventId}`);
|
package/dist/backends/segment.js
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -11,7 +11,10 @@ type NextlyticsContext = {
|
|
|
11
11
|
templates?: Record<string, JavascriptTemplate>;
|
|
12
12
|
};
|
|
13
13
|
declare function NextlyticsClient(props: {
|
|
14
|
-
ctx
|
|
14
|
+
ctx?: NextlyticsContext;
|
|
15
|
+
requestId?: string;
|
|
16
|
+
scripts?: TemplatizedScriptInsertion<unknown>[];
|
|
17
|
+
templates?: Record<string, JavascriptTemplate>;
|
|
15
18
|
children?: ReactNode;
|
|
16
19
|
}): react_jsx_runtime.JSX.Element;
|
|
17
20
|
type NextlyticsClientApi = {
|
package/dist/client.js
CHANGED
|
@@ -25,15 +25,13 @@ __export(client_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(client_exports);
|
|
26
26
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
27
27
|
var import_react = require("react");
|
|
28
|
-
var import_client_utils = require("./client-utils");
|
|
29
28
|
var import_server_component_context = require("./server-component-context");
|
|
30
29
|
var import_template = require("./template");
|
|
31
|
-
var import_stable_hash = require("./stable-hash");
|
|
32
30
|
const templateFunctions = {
|
|
33
31
|
q: (v) => JSON.stringify(v ?? null),
|
|
34
|
-
json: (v) => JSON.stringify(v ?? null)
|
|
35
|
-
stableHash: (v) => (0, import_stable_hash.stableHash)(v)
|
|
32
|
+
json: (v) => JSON.stringify(v ?? null)
|
|
36
33
|
};
|
|
34
|
+
const compiledCache = {};
|
|
37
35
|
const NextlyticsContext = (0, import_react.createContext)(null);
|
|
38
36
|
function createClientContext() {
|
|
39
37
|
const isBrowser = typeof window !== "undefined";
|
|
@@ -57,165 +55,94 @@ function createClientContext() {
|
|
|
57
55
|
locale: isBrowser ? navigator.language : void 0
|
|
58
56
|
};
|
|
59
57
|
}
|
|
60
|
-
function
|
|
61
|
-
const
|
|
62
|
-
|
|
58
|
+
function getCompiledTemplate(templateId, itemIndex, item) {
|
|
59
|
+
const cacheKey = `${templateId}:${itemIndex}`;
|
|
60
|
+
if (!compiledCache[cacheKey]) {
|
|
61
|
+
compiledCache[cacheKey] = {
|
|
62
|
+
src: item.src ? (0, import_template.compile)(item.src) : void 0,
|
|
63
|
+
body: item.body ? (0, import_template.compile)(item.body) : void 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return compiledCache[cacheKey];
|
|
67
|
+
}
|
|
68
|
+
function executeTemplatedScripts(scripts, templates) {
|
|
69
|
+
if (!scripts || typeof window === "undefined") return;
|
|
63
70
|
for (const script of scripts) {
|
|
64
|
-
if (script.type !== "script-template")
|
|
65
|
-
|
|
66
|
-
if (!template) continue;
|
|
67
|
-
if (!template.deps) {
|
|
68
|
-
result.push(script);
|
|
71
|
+
if (script.type !== "script-template") {
|
|
72
|
+
console.warn(`[Nextlytics] unsupported script type ${script.type} `);
|
|
69
73
|
continue;
|
|
70
74
|
}
|
|
71
|
-
const paramsRecord = script.params || {};
|
|
72
|
-
const deps = compileTemplateDeps(template, paramsRecord);
|
|
73
|
-
const depsKey = `${script.templateId}\0${deps.join("\0")}`;
|
|
74
|
-
if (firstSeenByDeps.has(depsKey)) continue;
|
|
75
|
-
firstSeenByDeps.add(depsKey);
|
|
76
|
-
result.push(script);
|
|
77
|
-
}
|
|
78
|
-
return result;
|
|
79
|
-
}
|
|
80
|
-
function compileScripts(scripts, templates) {
|
|
81
|
-
const result = [];
|
|
82
|
-
for (const [scriptIndex, script] of scripts.entries()) {
|
|
83
|
-
if (script.type !== "script-template") continue;
|
|
84
75
|
const template = templates[script.templateId];
|
|
85
76
|
if (!template) {
|
|
86
|
-
console.warn(`[Nextlytics]
|
|
77
|
+
console.warn(`[Nextlytics] Missing template: ${script.templateId}`);
|
|
87
78
|
continue;
|
|
88
79
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
if (item.src) {
|
|
95
|
-
const compiledSrc = (0, import_template.compile)(item.src);
|
|
96
|
-
const src = (0, import_template.apply)(compiledSrc, paramsRecord, templateFunctions);
|
|
97
|
-
result.push({
|
|
98
|
-
key: keyPrefix,
|
|
99
|
-
src,
|
|
100
|
-
async: item.async,
|
|
101
|
-
deps
|
|
102
|
-
});
|
|
103
|
-
itemIndex++;
|
|
80
|
+
const params = script.params;
|
|
81
|
+
for (let i = 0; i < template.items.length; i++) {
|
|
82
|
+
const item = template.items[i];
|
|
83
|
+
const compiled = getCompiledTemplate(script.templateId, i, item);
|
|
84
|
+
const src = compiled.src ? (0, import_template.apply)(compiled.src, params, templateFunctions) : void 0;
|
|
85
|
+
if (item.singleton && src && document.querySelector(`script[src="${src}"]`)) {
|
|
104
86
|
continue;
|
|
105
87
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
88
|
+
const el = document.createElement("script");
|
|
89
|
+
if (src) {
|
|
90
|
+
el.src = src;
|
|
91
|
+
}
|
|
92
|
+
if (compiled.body) {
|
|
93
|
+
el.textContent = (0, import_template.apply)(compiled.body, params, templateFunctions);
|
|
109
94
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
itemIndex++;
|
|
95
|
+
if (item.async) {
|
|
96
|
+
el.async = true;
|
|
97
|
+
}
|
|
98
|
+
document.head.appendChild(el);
|
|
115
99
|
}
|
|
116
100
|
}
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
function compileTemplateDeps(template, paramsRecord) {
|
|
120
|
-
if (!template.deps) return [];
|
|
121
|
-
const rawDeps = Array.isArray(template.deps) ? template.deps : [template.deps];
|
|
122
|
-
return rawDeps.map((dep) => (0, import_template.apply)((0, import_template.compile)(dep), paramsRecord, templateFunctions));
|
|
123
101
|
}
|
|
124
|
-
function
|
|
125
|
-
initialScripts
|
|
126
|
-
}) {
|
|
127
|
-
const context = (0, import_react.useContext)(NextlyticsContext);
|
|
128
|
-
if (!context) {
|
|
129
|
-
throw new Error("NextlyticsScripts should be called within NextlyticsContext");
|
|
130
|
-
}
|
|
131
|
-
const { scriptsRef, subscribersRef, templates } = context;
|
|
132
|
-
const [, forceUpdate] = (0, import_react.useReducer)((x) => x + 1, 0);
|
|
133
|
-
(0, import_react.useEffect)(() => {
|
|
134
|
-
subscribersRef.current.add(forceUpdate);
|
|
135
|
-
return () => {
|
|
136
|
-
subscribersRef.current.delete(forceUpdate);
|
|
137
|
-
};
|
|
138
|
-
}, [subscribersRef]);
|
|
139
|
-
const allScripts = [...initialScripts, ...scriptsRef.current];
|
|
140
|
-
const dedupedScripts = (0, import_react.useMemo)(
|
|
141
|
-
() => deduplicateScripts(allScripts, templates),
|
|
142
|
-
[allScripts, templates]
|
|
143
|
-
);
|
|
144
|
-
const compiled = (0, import_react.useMemo)(
|
|
145
|
-
() => compileScripts(dedupedScripts, templates),
|
|
146
|
-
[dedupedScripts, templates]
|
|
147
|
-
);
|
|
148
|
-
(0, import_client_utils.debug)("Rendering scripts", {
|
|
149
|
-
initialCount: initialScripts.length,
|
|
150
|
-
dynamicCount: scriptsRef.current.length,
|
|
151
|
-
totalCount: allScripts.length,
|
|
152
|
-
compiledCount: compiled.length
|
|
153
|
-
});
|
|
154
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: compiled.map(({ key, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_client_utils.InjectScript, { ...props }, key)) });
|
|
155
|
-
}
|
|
156
|
-
async function sendEventToServer(requestId, request, { signal, isSoftNavigation } = {}) {
|
|
102
|
+
async function sendEvent(requestId, type, payload) {
|
|
157
103
|
try {
|
|
158
|
-
const headers = {
|
|
159
|
-
"Content-Type": "application/json",
|
|
160
|
-
[import_server_component_context.headerNames.pageRenderId]: requestId
|
|
161
|
-
};
|
|
162
|
-
if (isSoftNavigation) {
|
|
163
|
-
headers[import_server_component_context.headerNames.isSoftNavigation] = "1";
|
|
164
|
-
}
|
|
165
104
|
const response = await fetch("/api/event", {
|
|
166
105
|
method: "POST",
|
|
167
|
-
headers
|
|
168
|
-
|
|
169
|
-
|
|
106
|
+
headers: {
|
|
107
|
+
"Content-Type": "application/json",
|
|
108
|
+
[import_server_component_context.headers.pageRenderId]: requestId
|
|
109
|
+
},
|
|
110
|
+
body: JSON.stringify({ type, payload })
|
|
170
111
|
});
|
|
171
112
|
if (response.status === 404) {
|
|
172
113
|
console.error(
|
|
173
|
-
"[Nextlytics] In order for NextlyticsClient to work, you must
|
|
114
|
+
"[Nextlytics] In order for NextlyticsClient to work, you must mount nextlyticsRouteHandler to /api/event"
|
|
174
115
|
);
|
|
175
116
|
return { ok: false };
|
|
176
117
|
}
|
|
177
118
|
const data = await response.json().catch(() => ({ ok: response.ok }));
|
|
178
|
-
return { ok: data.ok ?? response.ok,
|
|
119
|
+
return { ok: data.ok ?? response.ok, scripts: data.scripts };
|
|
179
120
|
} catch (error) {
|
|
180
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
181
|
-
return { ok: false };
|
|
182
|
-
}
|
|
183
121
|
console.error("[Nextlytics] Failed to send event:", error);
|
|
184
122
|
return { ok: false };
|
|
185
123
|
}
|
|
186
124
|
}
|
|
125
|
+
const initializedRequestIds = /* @__PURE__ */ new Set();
|
|
187
126
|
function NextlyticsClient(props) {
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
subscribersRef.current.forEach((cb) => cb());
|
|
198
|
-
}, []);
|
|
199
|
-
const contextValue = (0, import_react.useMemo)(
|
|
200
|
-
() => ({ requestId, templates, addScripts, scriptsRef, subscribersRef }),
|
|
201
|
-
[requestId, templates, addScripts]
|
|
202
|
-
);
|
|
203
|
-
(0, import_client_utils.useNavigation)(requestId, ({ softNavigation, signal }) => {
|
|
204
|
-
(0, import_client_utils.debug)("Sending page-view", { requestId, softNavigation });
|
|
127
|
+
const requestId = props.ctx?.requestId ?? props.requestId ?? "";
|
|
128
|
+
const scripts = props.ctx?.scripts ?? props.scripts;
|
|
129
|
+
const templates = props.ctx?.templates ?? props.templates ?? {};
|
|
130
|
+
(0, import_react.useEffect)(() => {
|
|
131
|
+
if (initializedRequestIds.has(requestId)) return;
|
|
132
|
+
initializedRequestIds.add(requestId);
|
|
133
|
+
if (scripts && Object.keys(templates).length > 0) {
|
|
134
|
+
executeTemplatedScripts(scripts, templates);
|
|
135
|
+
}
|
|
205
136
|
const clientContext = createClientContext();
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(NextlyticsContext.Provider, { value: contextValue, children: [
|
|
216
|
-
props.children,
|
|
217
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(NextlyticsScripts, { initialScripts })
|
|
218
|
-
] });
|
|
137
|
+
sendEvent(requestId, "client-init", clientContext).then(
|
|
138
|
+
({ scripts: responseScripts }) => {
|
|
139
|
+
if (responseScripts) {
|
|
140
|
+
executeTemplatedScripts(responseScripts, templates);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}, [requestId, scripts, templates]);
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NextlyticsContext.Provider, { value: { requestId, templates }, children: props.children });
|
|
219
146
|
}
|
|
220
147
|
function useNextlytics() {
|
|
221
148
|
const context = (0, import_react.useContext)(NextlyticsContext);
|
|
@@ -224,24 +151,23 @@ function useNextlytics() {
|
|
|
224
151
|
"[Nextlytics] useNextlytics() must be used within a component wrapped by <NextlyticsServer>. Add <NextlyticsServer> at the top of your layout.tsx file."
|
|
225
152
|
);
|
|
226
153
|
}
|
|
227
|
-
const { requestId,
|
|
228
|
-
const
|
|
154
|
+
const { requestId, templates } = context;
|
|
155
|
+
const send = (0, import_react.useCallback)(
|
|
229
156
|
async (eventName, opts) => {
|
|
230
|
-
const result = await
|
|
231
|
-
type: "custom-event",
|
|
157
|
+
const result = await sendEvent(requestId, "client-event", {
|
|
232
158
|
name: eventName,
|
|
233
159
|
props: opts?.props,
|
|
234
160
|
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
235
161
|
clientContext: createClientContext()
|
|
236
162
|
});
|
|
237
|
-
if (result.
|
|
238
|
-
|
|
163
|
+
if (result.scripts) {
|
|
164
|
+
executeTemplatedScripts(result.scripts, templates);
|
|
239
165
|
}
|
|
240
166
|
return { ok: result.ok };
|
|
241
167
|
},
|
|
242
|
-
[requestId,
|
|
168
|
+
[requestId, templates]
|
|
243
169
|
);
|
|
244
|
-
return { sendEvent };
|
|
170
|
+
return { sendEvent: send };
|
|
245
171
|
}
|
|
246
172
|
// Annotate the CommonJS export names for ESM import in node:
|
|
247
173
|
0 && (module.exports = {
|
package/dist/config-helpers.js
CHANGED
|
@@ -28,7 +28,7 @@ function withDefaults(config) {
|
|
|
28
28
|
...config,
|
|
29
29
|
excludeApiCalls: config.excludeApiCalls ?? false,
|
|
30
30
|
eventEndpoint: config.eventEndpoint ?? "/api/event",
|
|
31
|
-
isApiPath: config.isApiPath ?? ((
|
|
31
|
+
isApiPath: config.isApiPath ?? (() => false),
|
|
32
32
|
backends: config.backends ?? [],
|
|
33
33
|
anonymousUsers: {
|
|
34
34
|
gdprMode: config.anonymousUsers?.gdprMode ?? true,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
|
|
3
|
+
type AppRouteHandlers = Record<"GET" | "POST", (req: NextRequest) => Promise<Response>>;
|
|
4
|
+
/**
|
|
5
|
+
* Route handlers for /api/event (deprecated - middleware handles this now)
|
|
6
|
+
*
|
|
7
|
+
* Kept for backward compatibility. If you have mounted these handlers at /api/event,
|
|
8
|
+
* the middleware will intercept the request first, so these won't be called.
|
|
9
|
+
*/
|
|
10
|
+
declare function createHandlers(): AppRouteHandlers;
|
|
11
|
+
|
|
12
|
+
export { createHandlers };
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
function createHandlers() {
|
|
25
|
+
return {
|
|
26
|
+
GET: async () => {
|
|
27
|
+
return Response.json({ status: "ok" });
|
|
28
|
+
},
|
|
29
|
+
POST: async () => {
|
|
30
|
+
return Response.json(
|
|
31
|
+
{ error: "Middleware not configured. Events are handled by nextlyticsMiddleware." },
|
|
32
|
+
{ status: 500 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
createHandlers
|
|
40
|
+
});
|