@nextlytics/core 0.4.2 → 0.5.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/anonymous-user.d.ts +1 -0
- package/dist/api-handler.d.ts +1 -0
- package/dist/backends/clickhouse.d.ts +1 -0
- package/dist/backends/ga.d.ts +1 -0
- package/dist/backends/gtm.d.ts +1 -0
- package/dist/backends/lib/db.d.ts +1 -0
- package/dist/backends/logging.d.ts +1 -0
- package/dist/backends/neon.d.ts +1 -0
- package/dist/backends/postgrest.d.ts +1 -0
- package/dist/backends/posthog.d.ts +1 -0
- package/dist/backends/segment.d.ts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/config-helpers.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/middleware.d.ts +1 -0
- package/dist/pages-router.d.ts +1 -0
- package/dist/plugins/vercel-geo.d.ts +1 -0
- package/dist/server-component-context.d.ts +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +71 -31
- package/dist/types.d.ts +12 -4
- package/dist/uitils.d.ts +1 -0
- package/package.json +1 -1
package/dist/anonymous-user.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import { RequestContext, ServerEventContext, NextlyticsConfig, AnonymousUserResult } from './types.js';
|
|
3
3
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
4
|
+
import 'next';
|
|
4
5
|
|
|
5
6
|
type ResolveAnonymousUserParams = {
|
|
6
7
|
ctx: RequestContext;
|
package/dist/api-handler.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { NextRequest } from 'next/server';
|
|
|
2
2
|
import { RequestContext, JavascriptTemplate, NextlyticsEvent, 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
|
+
import 'next';
|
|
5
6
|
|
|
6
7
|
type DispatchEvent = (event: NextlyticsEvent, ctx: RequestContext, policyFilter?: PageViewDelivery | "client-actions") => DispatchResult;
|
|
7
8
|
type UpdateEvent = (eventId: string, patch: Partial<NextlyticsEvent>, ctx: RequestContext) => Promise<void>;
|
package/dist/backends/ga.d.ts
CHANGED
package/dist/backends/gtm.d.ts
CHANGED
package/dist/backends/neon.d.ts
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import { TemplatizedScriptInsertion, JavascriptTemplate } from './types.js';
|
|
4
4
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
5
5
|
import 'next/server';
|
|
6
|
+
import 'next';
|
|
6
7
|
|
|
7
8
|
/** Context object for Pages Router integration */
|
|
8
9
|
type NextlyticsContext = {
|
package/dist/config-helpers.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextlyticsConfig } from './types.js';
|
|
2
2
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
3
|
import 'next/server';
|
|
4
|
+
import 'next';
|
|
4
5
|
|
|
5
6
|
type NextlyticsConfigWithDefaults = Required<Pick<NextlyticsConfig, "excludeApiCalls" | "eventEndpoint" | "isApiPath" | "backends">> & NextlyticsConfig & {
|
|
6
7
|
anonymousUsers: Required<NonNullable<NextlyticsConfig["anonymousUsers"]>>;
|
package/dist/index.d.ts
CHANGED
package/dist/middleware.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { NextlyticsConfigWithDefaults } from './config-helpers.js';
|
|
|
3
3
|
import { DispatchEvent, UpdateEvent, CollectTemplates } from './api-handler.js';
|
|
4
4
|
import './types.js';
|
|
5
5
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
6
|
+
import 'next';
|
|
6
7
|
|
|
7
8
|
declare function createNextlyticsMiddleware(config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent, collectTemplates: CollectTemplates): NextMiddleware;
|
|
8
9
|
|
package/dist/pages-router.d.ts
CHANGED
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextlyticsConfig, NextlyticsResult, RequestContext } from './types.js';
|
|
2
2
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
3
|
import 'next/server';
|
|
4
|
+
import 'next';
|
|
4
5
|
|
|
5
6
|
declare function createRequestContext(): Promise<RequestContext>;
|
|
6
7
|
declare function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult;
|
package/dist/server.js
CHANGED
|
@@ -195,15 +195,14 @@ function Nextlytics(userConfig) {
|
|
|
195
195
|
const templates = collectTemplates(config, requestCtx);
|
|
196
196
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_client.NextlyticsClient, { ctx: { requestId: ctx.pageRenderId, scripts: ctx.scripts, templates }, children });
|
|
197
197
|
}
|
|
198
|
-
const analytics = async () => {
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
const serverContext = createServerContextFromHeaders(headersList);
|
|
198
|
+
const analytics = async (req) => {
|
|
199
|
+
const source = req ? normalizeRequest(req) : await normalizeFromNextHeaders();
|
|
200
|
+
const pageRenderId = source.headers.get(import_server_component_context.headerNames.pageRenderId) || source.cookies.get(import_server_component_context.LAST_PAGE_RENDER_ID_COOKIE)?.value || void 0;
|
|
201
|
+
const serverContext = buildServerContext(source);
|
|
203
202
|
const ctx = {
|
|
204
|
-
headers:
|
|
205
|
-
cookies:
|
|
206
|
-
path:
|
|
203
|
+
headers: source.headers,
|
|
204
|
+
cookies: source.cookies,
|
|
205
|
+
path: source.path
|
|
207
206
|
};
|
|
208
207
|
const { anonId: anonymousUserId } = await (0, import_anonymous_user.resolveAnonymousUser)({ ctx, serverContext, config });
|
|
209
208
|
let userContext;
|
|
@@ -216,14 +215,14 @@ function Nextlytics(userConfig) {
|
|
|
216
215
|
const propsFromCallback = await (0, import_api_handler.getEventProps)(config, ctx, userContext);
|
|
217
216
|
return {
|
|
218
217
|
sendEvent: async (eventName, opts) => {
|
|
219
|
-
if (!pageRenderId) {
|
|
218
|
+
if (!pageRenderId && !req) {
|
|
220
219
|
console.error("[Nextlytics] analytics() requires nextlyticsMiddleware");
|
|
221
220
|
return { ok: false };
|
|
222
221
|
}
|
|
223
222
|
const event = {
|
|
224
223
|
origin: "server",
|
|
225
224
|
eventId: (0, import_uitils.generateId)(),
|
|
226
|
-
parentEventId: pageRenderId,
|
|
225
|
+
...pageRenderId ? { parentEventId: pageRenderId } : {},
|
|
227
226
|
type: eventName,
|
|
228
227
|
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
229
228
|
anonymousUserId,
|
|
@@ -244,32 +243,73 @@ function Nextlytics(userConfig) {
|
|
|
244
243
|
NextlyticsServer: Server
|
|
245
244
|
};
|
|
246
245
|
}
|
|
247
|
-
function
|
|
246
|
+
function searchToRecord(params) {
|
|
247
|
+
const out = {};
|
|
248
|
+
params.forEach((value, key) => {
|
|
249
|
+
(out[key] ?? (out[key] = [])).push(value);
|
|
250
|
+
});
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
function isNextApiRequest(req) {
|
|
254
|
+
return typeof req.headers?.get !== "function";
|
|
255
|
+
}
|
|
256
|
+
async function normalizeFromNextHeaders() {
|
|
257
|
+
const [_cookies, _headers] = await Promise.all([(0, import_headers.cookies)(), (0, import_headers.headers)()]);
|
|
258
|
+
return {
|
|
259
|
+
headers: _headers,
|
|
260
|
+
cookies: _cookies,
|
|
261
|
+
path: _headers.get(import_server_component_context.headerNames.pathname) || "",
|
|
262
|
+
search: searchToRecord(new URLSearchParams(_headers.get(import_server_component_context.headerNames.search) || "")),
|
|
263
|
+
method: "GET"
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function normalizeRequest(req) {
|
|
267
|
+
if (!isNextApiRequest(req)) {
|
|
268
|
+
return {
|
|
269
|
+
headers: req.headers,
|
|
270
|
+
cookies: req.cookies,
|
|
271
|
+
path: req.nextUrl.pathname,
|
|
272
|
+
search: searchToRecord(req.nextUrl.searchParams),
|
|
273
|
+
method: req.method
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const headersList = new Headers();
|
|
277
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
278
|
+
if (value !== void 0) {
|
|
279
|
+
headersList.set(key, Array.isArray(value) ? value.join(", ") : value);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const cookieMap = req.cookies || {};
|
|
283
|
+
const cookieStore = {
|
|
284
|
+
get: (name) => {
|
|
285
|
+
const value = cookieMap[name];
|
|
286
|
+
return value === void 0 ? void 0 : { name, value };
|
|
287
|
+
},
|
|
288
|
+
getAll: () => Object.entries(cookieMap).map(([name, value]) => ({ name, value })),
|
|
289
|
+
has: (name) => name in cookieMap
|
|
290
|
+
};
|
|
291
|
+
const url = new URL(req.url || "/", `http://${headersList.get("host") || "localhost"}`);
|
|
292
|
+
return {
|
|
293
|
+
headers: headersList,
|
|
294
|
+
cookies: cookieStore,
|
|
295
|
+
path: url.pathname,
|
|
296
|
+
search: searchToRecord(url.searchParams),
|
|
297
|
+
method: req.method || "GET"
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function buildServerContext(source) {
|
|
248
301
|
const rawHeaders = {};
|
|
249
|
-
|
|
302
|
+
source.headers.forEach((value, key) => {
|
|
250
303
|
rawHeaders[key] = value;
|
|
251
304
|
});
|
|
252
|
-
const requestHeaders = (0, import_headers2.removeSensitiveHeaders)(rawHeaders);
|
|
253
|
-
const pathname = headersList.get(import_server_component_context.headerNames.pathname) || "";
|
|
254
|
-
const search = headersList.get(import_server_component_context.headerNames.search) || "";
|
|
255
|
-
const searchParams = {};
|
|
256
|
-
if (search) {
|
|
257
|
-
const params = new URLSearchParams(search);
|
|
258
|
-
params.forEach((value, key) => {
|
|
259
|
-
if (!searchParams[key]) {
|
|
260
|
-
searchParams[key] = [];
|
|
261
|
-
}
|
|
262
|
-
searchParams[key].push(value);
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
305
|
return {
|
|
266
306
|
collectedAt: /* @__PURE__ */ new Date(),
|
|
267
|
-
host:
|
|
268
|
-
method:
|
|
269
|
-
path:
|
|
270
|
-
search:
|
|
271
|
-
ip:
|
|
272
|
-
requestHeaders,
|
|
307
|
+
host: source.headers.get("host") || "",
|
|
308
|
+
method: source.method,
|
|
309
|
+
path: source.path,
|
|
310
|
+
search: source.search,
|
|
311
|
+
ip: source.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || "",
|
|
312
|
+
requestHeaders: (0, import_headers2.removeSensitiveHeaders)(rawHeaders),
|
|
273
313
|
responseHeaders: {}
|
|
274
314
|
};
|
|
275
315
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RequestCookies } from 'next/dist/server/web/spec-extension/cookies';
|
|
2
|
-
import { NextMiddleware } from 'next/server';
|
|
2
|
+
import { NextRequest, NextMiddleware } from 'next/server';
|
|
3
|
+
import { NextApiRequest } from 'next';
|
|
3
4
|
|
|
4
5
|
/** Server-side request context collected in middleware */
|
|
5
6
|
interface ServerEventContext {
|
|
@@ -227,7 +228,7 @@ type NextlyticsBackend = {
|
|
|
227
228
|
type NextlyticsBackendFactory = (ctx: RequestContext) => NextlyticsBackend;
|
|
228
229
|
/** Server-side analytics API */
|
|
229
230
|
type NextlyticsServerSide = {
|
|
230
|
-
/** Send custom event from server component
|
|
231
|
+
/** Send custom event from a server component, server action, or API route */
|
|
231
232
|
sendEvent: (eventName: string, opts?: {
|
|
232
233
|
props?: Record<string, unknown>;
|
|
233
234
|
}) => Promise<{
|
|
@@ -272,8 +273,15 @@ type ClientRequestResult = {
|
|
|
272
273
|
};
|
|
273
274
|
/** Return value from Nextlytics() */
|
|
274
275
|
type NextlyticsResult = {
|
|
275
|
-
/** Get server-side analytics API
|
|
276
|
-
|
|
276
|
+
/** Get server-side analytics API.
|
|
277
|
+
*
|
|
278
|
+
* App Router (server components, server actions, route handlers): call with no
|
|
279
|
+
* argument — context is read from `next/headers`.
|
|
280
|
+
*
|
|
281
|
+
* Pages Router API routes: `next/headers` is unavailable there, so pass the
|
|
282
|
+
* request (`analytics(req)`). A NextRequest (App Router route handler) is also
|
|
283
|
+
* accepted. */
|
|
284
|
+
analytics: (req?: NextRequest | NextApiRequest) => Promise<NextlyticsServerSide>;
|
|
277
285
|
/** Middleware to intercept requests */
|
|
278
286
|
middleware: NextMiddleware;
|
|
279
287
|
/** Manually dispatch event (returns two-phase result) */
|
package/dist/uitils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextRequest } from 'next/server';
|
|
2
2
|
import { ServerEventContext } from './types.js';
|
|
3
3
|
import 'next/dist/server/web/spec-extension/cookies';
|
|
4
|
+
import 'next';
|
|
4
5
|
|
|
5
6
|
/** Returns the full installed Next.js version string (e.g. "16.1.6"), or undefined. */
|
|
6
7
|
declare function getNextVersion(): string | undefined;
|