@nextlytics/core 0.4.1-canary.104 → 0.4.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/api-handler.d.ts +3 -5
- package/dist/api-handler.js +5 -24
- package/dist/client.js +16 -56
- package/dist/middleware.d.ts +2 -2
- package/dist/middleware.js +2 -2
- package/dist/pages-router.d.ts +1 -6
- package/dist/pages-router.js +1 -5
- package/dist/server-component-context.d.ts +0 -3
- package/dist/server-component-context.js +1 -4
- package/dist/server.js +2 -9
- package/dist/types.d.ts +0 -3
- package/package.json +1 -1
package/dist/api-handler.d.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { NextRequest } from 'next/server';
|
|
2
|
-
import {
|
|
2
|
+
import { NextlyticsEvent, RequestContext, PageViewDelivery, DispatchResult, UserContext } from './types.js';
|
|
3
3
|
import { NextlyticsConfigWithDefaults } from './config-helpers.js';
|
|
4
4
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
5
5
|
|
|
6
6
|
type DispatchEvent = (event: NextlyticsEvent, ctx: RequestContext, policyFilter?: PageViewDelivery | "client-actions") => DispatchResult;
|
|
7
7
|
type UpdateEvent = (eventId: string, patch: Partial<NextlyticsEvent>, ctx: RequestContext) => Promise<void>;
|
|
8
|
-
/** Collect the client-side templates from the configured backends. */
|
|
9
|
-
type CollectTemplates = (ctx: RequestContext) => Record<string, JavascriptTemplate>;
|
|
10
8
|
declare function getUserContext(config: NextlyticsConfigWithDefaults, ctx: RequestContext): Promise<UserContext | undefined>;
|
|
11
9
|
declare function getEventProps(config: NextlyticsConfigWithDefaults, ctx: RequestContext, userContext?: UserContext): Promise<Record<string, unknown> | undefined>;
|
|
12
|
-
declare function handleEventPost(request: NextRequest, config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent
|
|
10
|
+
declare function handleEventPost(request: NextRequest, config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent): Promise<Response>;
|
|
13
11
|
|
|
14
|
-
export { type
|
|
12
|
+
export { type DispatchEvent, type UpdateEvent, getEventProps, getUserContext, handleEventPost };
|
package/dist/api-handler.js
CHANGED
|
@@ -27,14 +27,6 @@ var import_server = require("next/server");
|
|
|
27
27
|
var import_server_component_context = require("./server-component-context");
|
|
28
28
|
var import_uitils = require("./uitils");
|
|
29
29
|
var import_anonymous_user = require("./anonymous-user");
|
|
30
|
-
function newTemplatesFor(hctx) {
|
|
31
|
-
const all = hctx.collectTemplates(hctx.ctx);
|
|
32
|
-
const missing = {};
|
|
33
|
-
for (const [id, template] of Object.entries(all)) {
|
|
34
|
-
if (!hctx.knownTemplateIds.has(id)) missing[id] = template;
|
|
35
|
-
}
|
|
36
|
-
return Object.keys(missing).length > 0 ? missing : void 0;
|
|
37
|
-
}
|
|
38
30
|
function createRequestContext(request) {
|
|
39
31
|
return {
|
|
40
32
|
headers: request.headers,
|
|
@@ -118,14 +110,13 @@ async function handleClientInit(request, hctx) {
|
|
|
118
110
|
(0, import_server.after)(() => completion2);
|
|
119
111
|
return Response.json({
|
|
120
112
|
ok: true,
|
|
121
|
-
items: filterScripts(actions)
|
|
122
|
-
templates: newTemplatesFor(hctx)
|
|
113
|
+
items: filterScripts(actions)
|
|
123
114
|
});
|
|
124
115
|
}
|
|
125
116
|
const { completion } = dispatchEvent(event, ctx, "client-actions");
|
|
126
117
|
(0, import_server.after)(() => completion);
|
|
127
118
|
(0, import_server.after)(() => updateEvent(pageRenderId, { clientContext, userContext, anonymousUserId }, ctx));
|
|
128
|
-
return Response.json({ ok: true
|
|
119
|
+
return Response.json({ ok: true });
|
|
129
120
|
}
|
|
130
121
|
async function handleClientEvent(request, hctx) {
|
|
131
122
|
const { pageRenderId, ctx, apiCallServerContext, userContext, config, dispatchEvent } = hctx;
|
|
@@ -153,13 +144,9 @@ async function handleClientEvent(request, hctx) {
|
|
|
153
144
|
const { clientActions, completion } = dispatchEvent(event, ctx);
|
|
154
145
|
const actions = await clientActions;
|
|
155
146
|
(0, import_server.after)(() => completion);
|
|
156
|
-
return Response.json({
|
|
157
|
-
ok: true,
|
|
158
|
-
items: filterScripts(actions),
|
|
159
|
-
templates: newTemplatesFor(hctx)
|
|
160
|
-
});
|
|
147
|
+
return Response.json({ ok: true, items: filterScripts(actions) });
|
|
161
148
|
}
|
|
162
|
-
async function handleEventPost(request, config, dispatchEvent, updateEvent
|
|
149
|
+
async function handleEventPost(request, config, dispatchEvent, updateEvent) {
|
|
163
150
|
const softNavHeader = request.headers.get(import_server_component_context.headerNames.isSoftNavigation);
|
|
164
151
|
const isSoftNavigation = softNavHeader === "1";
|
|
165
152
|
const pageRenderIdHeader = request.headers.get(import_server_component_context.headerNames.pageRenderId);
|
|
@@ -175,10 +162,6 @@ async function handleEventPost(request, config, dispatchEvent, updateEvent, coll
|
|
|
175
162
|
const ctx = createRequestContext(request);
|
|
176
163
|
const apiCallServerContext = (0, import_uitils.createServerContext)(request);
|
|
177
164
|
const userContext = await getUserContext(config, ctx);
|
|
178
|
-
const knownTemplatesHeader = request.headers.get(import_server_component_context.headerNames.knownTemplates);
|
|
179
|
-
const knownTemplateIds = new Set(
|
|
180
|
-
knownTemplatesHeader ? knownTemplatesHeader.split(",").map((id) => id.trim()).filter(Boolean) : []
|
|
181
|
-
);
|
|
182
165
|
const cookiePageRenderId = request.cookies.get(import_server_component_context.LAST_PAGE_RENDER_ID_COOKIE)?.value;
|
|
183
166
|
const pageRenderId = isSoftNavigation ? cookiePageRenderId ?? (0, import_uitils.generateId)() : pageRenderIdHeader;
|
|
184
167
|
if (isSoftNavigation && !cookiePageRenderId && config.debug) {
|
|
@@ -194,9 +177,7 @@ async function handleEventPost(request, config, dispatchEvent, updateEvent, coll
|
|
|
194
177
|
userContext,
|
|
195
178
|
config,
|
|
196
179
|
dispatchEvent,
|
|
197
|
-
updateEvent
|
|
198
|
-
collectTemplates,
|
|
199
|
-
knownTemplateIds
|
|
180
|
+
updateEvent
|
|
200
181
|
};
|
|
201
182
|
const bodyType = body.type;
|
|
202
183
|
switch (bodyType) {
|
package/dist/client.js
CHANGED
|
@@ -153,11 +153,7 @@ function NextlyticsScripts({
|
|
|
153
153
|
});
|
|
154
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
155
|
}
|
|
156
|
-
async function sendEventToServer(requestId, request, {
|
|
157
|
-
signal,
|
|
158
|
-
isSoftNavigation,
|
|
159
|
-
knownTemplateIds
|
|
160
|
-
} = {}) {
|
|
156
|
+
async function sendEventToServer(requestId, request, { signal, isSoftNavigation } = {}) {
|
|
161
157
|
try {
|
|
162
158
|
const headers = {
|
|
163
159
|
"Content-Type": "application/json",
|
|
@@ -166,9 +162,6 @@ async function sendEventToServer(requestId, request, {
|
|
|
166
162
|
if (isSoftNavigation) {
|
|
167
163
|
headers[import_server_component_context.headerNames.isSoftNavigation] = "1";
|
|
168
164
|
}
|
|
169
|
-
if (knownTemplateIds?.length) {
|
|
170
|
-
headers[import_server_component_context.headerNames.knownTemplates] = knownTemplateIds.join(",");
|
|
171
|
-
}
|
|
172
165
|
const response = await fetch("/api/event", {
|
|
173
166
|
method: "POST",
|
|
174
167
|
headers,
|
|
@@ -182,7 +175,7 @@ async function sendEventToServer(requestId, request, {
|
|
|
182
175
|
return { ok: false };
|
|
183
176
|
}
|
|
184
177
|
const data = await response.json().catch(() => ({ ok: response.ok }));
|
|
185
|
-
return { ok: data.ok ?? response.ok, items: data.items
|
|
178
|
+
return { ok: data.ok ?? response.ok, items: data.items };
|
|
186
179
|
} catch (error) {
|
|
187
180
|
if (error instanceof Error && error.name === "AbortError") {
|
|
188
181
|
return { ok: false };
|
|
@@ -192,28 +185,9 @@ async function sendEventToServer(requestId, request, {
|
|
|
192
185
|
}
|
|
193
186
|
}
|
|
194
187
|
function NextlyticsClient(props) {
|
|
195
|
-
const { requestId, scripts: initialScripts = [] } = props.ctx;
|
|
188
|
+
const { requestId, scripts: initialScripts = [], templates = {} } = props.ctx;
|
|
196
189
|
const scriptsRef = (0, import_react.useRef)([]);
|
|
197
190
|
const subscribersRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
198
|
-
const [templates, setTemplates] = (0, import_react.useState)(
|
|
199
|
-
() => props.ctx.templates ?? {}
|
|
200
|
-
);
|
|
201
|
-
const mergeTemplates = (0, import_react.useCallback)((incoming) => {
|
|
202
|
-
if (!incoming) return;
|
|
203
|
-
const keys = Object.keys(incoming);
|
|
204
|
-
if (keys.length === 0) return;
|
|
205
|
-
setTemplates((prev) => {
|
|
206
|
-
const hasNew = keys.some((k) => prev[k] !== incoming[k]);
|
|
207
|
-
return hasNew ? { ...prev, ...incoming } : prev;
|
|
208
|
-
});
|
|
209
|
-
}, []);
|
|
210
|
-
(0, import_react.useEffect)(() => {
|
|
211
|
-
mergeTemplates(props.ctx.templates);
|
|
212
|
-
}, [props.ctx.templates, mergeTemplates]);
|
|
213
|
-
const knownTemplateIdsRef = (0, import_react.useRef)(Object.keys(props.ctx.templates ?? {}));
|
|
214
|
-
(0, import_react.useEffect)(() => {
|
|
215
|
-
knownTemplateIdsRef.current = Object.keys(templates);
|
|
216
|
-
}, [templates]);
|
|
217
191
|
const addScripts = (0, import_react.useCallback)((newScripts) => {
|
|
218
192
|
(0, import_client_utils.debug)("Adding scripts", {
|
|
219
193
|
newCount: newScripts.length,
|
|
@@ -223,16 +197,8 @@ function NextlyticsClient(props) {
|
|
|
223
197
|
subscribersRef.current.forEach((cb) => cb());
|
|
224
198
|
}, []);
|
|
225
199
|
const contextValue = (0, import_react.useMemo)(
|
|
226
|
-
() => ({
|
|
227
|
-
|
|
228
|
-
templates,
|
|
229
|
-
addScripts,
|
|
230
|
-
scriptsRef,
|
|
231
|
-
subscribersRef,
|
|
232
|
-
mergeTemplates,
|
|
233
|
-
knownTemplateIdsRef
|
|
234
|
-
}),
|
|
235
|
-
[requestId, templates, addScripts, mergeTemplates]
|
|
200
|
+
() => ({ requestId, templates, addScripts, scriptsRef, subscribersRef }),
|
|
201
|
+
[requestId, templates, addScripts]
|
|
236
202
|
);
|
|
237
203
|
(0, import_client_utils.useNavigation)(requestId, ({ softNavigation, signal }) => {
|
|
238
204
|
(0, import_client_utils.debug)("Sending page-view", { requestId, softNavigation });
|
|
@@ -240,10 +206,9 @@ function NextlyticsClient(props) {
|
|
|
240
206
|
sendEventToServer(
|
|
241
207
|
requestId,
|
|
242
208
|
{ type: "page-view", clientContext, softNavigation: softNavigation || void 0 },
|
|
243
|
-
{ signal, isSoftNavigation: softNavigation
|
|
244
|
-
).then(({ items
|
|
209
|
+
{ signal, isSoftNavigation: softNavigation }
|
|
210
|
+
).then(({ items }) => {
|
|
245
211
|
(0, import_client_utils.debug)("page-view response", { scriptsCount: items?.length ?? 0 });
|
|
246
|
-
mergeTemplates(responseTemplates);
|
|
247
212
|
if (items?.length) addScripts(items);
|
|
248
213
|
});
|
|
249
214
|
});
|
|
@@ -259,27 +224,22 @@ function useNextlytics() {
|
|
|
259
224
|
"[Nextlytics] useNextlytics() must be used within a component wrapped by <NextlyticsServer>. Add <NextlyticsServer> at the top of your layout.tsx file."
|
|
260
225
|
);
|
|
261
226
|
}
|
|
262
|
-
const { requestId, addScripts
|
|
227
|
+
const { requestId, addScripts } = context;
|
|
263
228
|
const sendEvent = (0, import_react.useCallback)(
|
|
264
229
|
async (eventName, opts) => {
|
|
265
|
-
const result = await sendEventToServer(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
clientContext: createClientContext()
|
|
273
|
-
},
|
|
274
|
-
{ knownTemplateIds: knownTemplateIdsRef.current }
|
|
275
|
-
);
|
|
276
|
-
mergeTemplates(result.templates);
|
|
230
|
+
const result = await sendEventToServer(requestId, {
|
|
231
|
+
type: "custom-event",
|
|
232
|
+
name: eventName,
|
|
233
|
+
props: opts?.props,
|
|
234
|
+
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
235
|
+
clientContext: createClientContext()
|
|
236
|
+
});
|
|
277
237
|
if (result.items && result.items.length > 0) {
|
|
278
238
|
addScripts(result.items);
|
|
279
239
|
}
|
|
280
240
|
return { ok: result.ok };
|
|
281
241
|
},
|
|
282
|
-
[requestId, addScripts
|
|
242
|
+
[requestId, addScripts]
|
|
283
243
|
);
|
|
284
244
|
return { sendEvent };
|
|
285
245
|
}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { NextMiddleware } from 'next/server';
|
|
2
2
|
import { NextlyticsConfigWithDefaults } from './config-helpers.js';
|
|
3
|
-
import { DispatchEvent, UpdateEvent
|
|
3
|
+
import { DispatchEvent, UpdateEvent } from './api-handler.js';
|
|
4
4
|
import './types.js';
|
|
5
5
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
6
6
|
|
|
7
|
-
declare function createNextlyticsMiddleware(config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent
|
|
7
|
+
declare function createNextlyticsMiddleware(config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent): NextMiddleware;
|
|
8
8
|
|
|
9
9
|
export { createNextlyticsMiddleware };
|
package/dist/middleware.js
CHANGED
|
@@ -33,7 +33,7 @@ function createRequestContext(request) {
|
|
|
33
33
|
path: request.nextUrl.pathname
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function createNextlyticsMiddleware(config, dispatchEvent, updateEvent
|
|
36
|
+
function createNextlyticsMiddleware(config, dispatchEvent, updateEvent) {
|
|
37
37
|
const { eventEndpoint } = config;
|
|
38
38
|
return async (request) => {
|
|
39
39
|
const pathname = request.nextUrl.pathname;
|
|
@@ -67,7 +67,7 @@ function createNextlyticsMiddleware(config, dispatchEvent, updateEvent, collectT
|
|
|
67
67
|
}
|
|
68
68
|
if (pathname === eventEndpoint) {
|
|
69
69
|
if (request.method === "POST") {
|
|
70
|
-
return (0, import_api_handler.handleEventPost)(request, config, dispatchEvent, updateEvent
|
|
70
|
+
return (0, import_api_handler.handleEventPost)(request, config, dispatchEvent, updateEvent);
|
|
71
71
|
}
|
|
72
72
|
return Response.json({ error: "Method not allowed" }, { status: 405 });
|
|
73
73
|
}
|
package/dist/pages-router.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import 'next/dist/server/web/spec-extension/cookies';
|
|
|
6
6
|
import 'next/server';
|
|
7
7
|
|
|
8
8
|
type PagesRouterContext = {
|
|
9
|
-
req
|
|
9
|
+
req: {
|
|
10
10
|
headers: Record<string, string | string[] | undefined>;
|
|
11
11
|
cookies?: Record<string, string>;
|
|
12
12
|
};
|
|
@@ -14,11 +14,6 @@ type PagesRouterContext = {
|
|
|
14
14
|
/**
|
|
15
15
|
* Get Nextlytics props for Pages Router _app.tsx.
|
|
16
16
|
* Reads context from headers set by middleware.
|
|
17
|
-
*
|
|
18
|
-
* `_app`'s getInitialProps re-runs on every client-side navigation, where there
|
|
19
|
-
* is no `req`. Return an empty context in that case rather than throwing — the
|
|
20
|
-
* client already has its scripts and templates from the initial render and the
|
|
21
|
-
* /api/event round-trip.
|
|
22
17
|
*/
|
|
23
18
|
declare function getNextlyticsProps(ctx: PagesRouterContext): NextlyticsContext;
|
|
24
19
|
|
package/dist/pages-router.js
CHANGED
|
@@ -23,12 +23,8 @@ __export(pages_router_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(pages_router_exports);
|
|
24
24
|
var import_server_component_context = require("./server-component-context");
|
|
25
25
|
function getNextlyticsProps(ctx) {
|
|
26
|
-
const reqHeaders = ctx?.req?.headers;
|
|
27
|
-
if (!reqHeaders) {
|
|
28
|
-
return { requestId: "" };
|
|
29
|
-
}
|
|
30
26
|
const headersList = new Headers();
|
|
31
|
-
for (const [key, value] of Object.entries(
|
|
27
|
+
for (const [key, value] of Object.entries(ctx.req.headers)) {
|
|
32
28
|
if (value) {
|
|
33
29
|
headersList.set(key, Array.isArray(value) ? value[0] : value);
|
|
34
30
|
}
|
|
@@ -9,9 +9,6 @@ declare const headerNames: {
|
|
|
9
9
|
readonly isSoftNavigation: "x-nl-is-soft-nav";
|
|
10
10
|
readonly active: "x-nl-active";
|
|
11
11
|
readonly scripts: "x-nl-scripts";
|
|
12
|
-
/** Comma-separated template ids the client already holds, so the server only
|
|
13
|
-
* returns the ones it's missing (see api-handler / client templates merge). */
|
|
14
|
-
readonly knownTemplates: "x-nl-known-templates";
|
|
15
12
|
};
|
|
16
13
|
declare const LAST_PAGE_RENDER_ID_COOKIE = "last-page-render-id";
|
|
17
14
|
/** Context passed from middleware to server components via headers */
|
|
@@ -31,10 +31,7 @@ const headerNames = {
|
|
|
31
31
|
pageRenderId: `${HEADER_PREFIX}page-render-id`,
|
|
32
32
|
isSoftNavigation: `${HEADER_PREFIX}is-soft-nav`,
|
|
33
33
|
active: `${HEADER_PREFIX}active`,
|
|
34
|
-
scripts: `${HEADER_PREFIX}scripts
|
|
35
|
-
/** Comma-separated template ids the client already holds, so the server only
|
|
36
|
-
* returns the ones it's missing (see api-handler / client templates merge). */
|
|
37
|
-
knownTemplates: `${HEADER_PREFIX}known-templates`
|
|
34
|
+
scripts: `${HEADER_PREFIX}scripts`
|
|
38
35
|
};
|
|
39
36
|
const LAST_PAGE_RENDER_ID_COOKIE = "last-page-render-id";
|
|
40
37
|
function serializeServerComponentContext(response, ctx) {
|
package/dist/server.js
CHANGED
|
@@ -174,20 +174,13 @@ function Nextlytics(userConfig) {
|
|
|
174
174
|
const ctx = await createRequestContext();
|
|
175
175
|
return updateEventInternal(eventId, patch, ctx);
|
|
176
176
|
};
|
|
177
|
-
const middleware = (0, import_middleware.createNextlyticsMiddleware)(
|
|
178
|
-
config,
|
|
179
|
-
dispatchEventInternal,
|
|
180
|
-
updateEventInternal,
|
|
181
|
-
(ctx) => collectTemplates(config, ctx)
|
|
182
|
-
);
|
|
177
|
+
const middleware = (0, import_middleware.createNextlyticsMiddleware)(config, dispatchEventInternal, updateEventInternal);
|
|
183
178
|
async function Server({ children }) {
|
|
184
179
|
const headersList = await (0, import_headers.headers)();
|
|
185
180
|
const ctx = (0, import_server_component_context.restoreServerComponentContext)(headersList);
|
|
186
181
|
if (!ctx) {
|
|
187
182
|
if (!headersList.get(import_server_component_context.headerNames.active)) {
|
|
188
|
-
console.warn(
|
|
189
|
-
"[Nextlytics] nextlyticsMiddleware should be added in order for Server to work"
|
|
190
|
-
);
|
|
183
|
+
console.warn("[Nextlytics] nextlyticsMiddleware should be added in order for Server to work");
|
|
191
184
|
}
|
|
192
185
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
193
186
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -266,9 +266,6 @@ type ClientRequest = {
|
|
|
266
266
|
type ClientRequestResult = {
|
|
267
267
|
ok: boolean;
|
|
268
268
|
items?: ClientActionItem[];
|
|
269
|
-
/** Client-side templates from the backends, so Pages Router clients (which
|
|
270
|
-
* can't read them from config) can compile the script insertions. */
|
|
271
|
-
templates?: Record<string, JavascriptTemplate>;
|
|
272
269
|
};
|
|
273
270
|
/** Return value from Nextlytics() */
|
|
274
271
|
type NextlyticsResult = {
|