@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.
@@ -1,14 +1,12 @@
1
1
  import { NextRequest } from 'next/server';
2
- import { RequestContext, JavascriptTemplate, NextlyticsEvent, PageViewDelivery, DispatchResult, UserContext } from './types.js';
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, collectTemplates: CollectTemplates): Promise<Response>;
10
+ declare function handleEventPost(request: NextRequest, config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent): Promise<Response>;
13
11
 
14
- export { type CollectTemplates, type DispatchEvent, type UpdateEvent, getEventProps, getUserContext, handleEventPost };
12
+ export { type DispatchEvent, type UpdateEvent, getEventProps, getUserContext, handleEventPost };
@@ -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, templates: newTemplatesFor(hctx) });
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, collectTemplates) {
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, templates: data.templates };
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
- requestId,
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, knownTemplateIds: knownTemplateIdsRef.current }
244
- ).then(({ items, templates: responseTemplates }) => {
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, mergeTemplates, knownTemplateIdsRef } = context;
227
+ const { requestId, addScripts } = context;
263
228
  const sendEvent = (0, import_react.useCallback)(
264
229
  async (eventName, opts) => {
265
- const result = await sendEventToServer(
266
- requestId,
267
- {
268
- type: "custom-event",
269
- name: eventName,
270
- props: opts?.props,
271
- collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
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, mergeTemplates, knownTemplateIdsRef]
242
+ [requestId, addScripts]
283
243
  );
284
244
  return { sendEvent };
285
245
  }
@@ -1,9 +1,9 @@
1
1
  import { NextMiddleware } from 'next/server';
2
2
  import { NextlyticsConfigWithDefaults } from './config-helpers.js';
3
- import { DispatchEvent, UpdateEvent, CollectTemplates } from './api-handler.js';
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, collectTemplates: CollectTemplates): NextMiddleware;
7
+ declare function createNextlyticsMiddleware(config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent): NextMiddleware;
8
8
 
9
9
  export { createNextlyticsMiddleware };
@@ -33,7 +33,7 @@ function createRequestContext(request) {
33
33
  path: request.nextUrl.pathname
34
34
  };
35
35
  }
36
- function createNextlyticsMiddleware(config, dispatchEvent, updateEvent, collectTemplates) {
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, collectTemplates);
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
  }
@@ -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
 
@@ -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(reqHeaders)) {
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 = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextlytics/core",
3
- "version": "0.4.1-canary.104",
3
+ "version": "0.4.1",
4
4
  "description": "Analytics library for Next.js",
5
5
  "license": "MIT",
6
6
  "repository": {