@nextlytics/core 0.3.1-canary.94 → 0.3.1-canary.98
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 +2 -1
- package/dist/api-handler.js +18 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/middleware.js +9 -6
- package/dist/path-matcher.d.ts +20 -0
- package/dist/path-matcher.js +58 -0
- package/dist/server.js +10 -3
- package/dist/types.d.ts +9 -0
- package/package.json +1 -1
package/dist/api-handler.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import 'next/dist/server/web/spec-extension/cookies';
|
|
|
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
8
|
declare function getUserContext(config: NextlyticsConfigWithDefaults, ctx: RequestContext): Promise<UserContext | undefined>;
|
|
9
|
+
declare function getEventProps(config: NextlyticsConfigWithDefaults, ctx: RequestContext, userContext?: UserContext): Promise<Record<string, unknown> | undefined>;
|
|
9
10
|
declare function handleEventPost(request: NextRequest, config: NextlyticsConfigWithDefaults, dispatchEvent: DispatchEvent, updateEvent: UpdateEvent): Promise<Response>;
|
|
10
11
|
|
|
11
|
-
export { type DispatchEvent, type UpdateEvent, getUserContext, handleEventPost };
|
|
12
|
+
export { type DispatchEvent, type UpdateEvent, getEventProps, getUserContext, handleEventPost };
|
package/dist/api-handler.js
CHANGED
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var api_handler_exports = {};
|
|
20
20
|
__export(api_handler_exports, {
|
|
21
|
+
getEventProps: () => getEventProps,
|
|
21
22
|
getUserContext: () => getUserContext,
|
|
22
23
|
handleEventPost: () => handleEventPost
|
|
23
24
|
});
|
|
@@ -29,7 +30,8 @@ var import_anonymous_user = require("./anonymous-user");
|
|
|
29
30
|
function createRequestContext(request) {
|
|
30
31
|
return {
|
|
31
32
|
headers: request.headers,
|
|
32
|
-
cookies: request.cookies
|
|
33
|
+
cookies: request.cookies,
|
|
34
|
+
path: request.nextUrl.pathname
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
async function getUserContext(config, ctx) {
|
|
@@ -40,6 +42,14 @@ async function getUserContext(config, ctx) {
|
|
|
40
42
|
return void 0;
|
|
41
43
|
}
|
|
42
44
|
}
|
|
45
|
+
async function getEventProps(config, ctx, userContext) {
|
|
46
|
+
if (!config.callbacks.getProps) return void 0;
|
|
47
|
+
try {
|
|
48
|
+
return await config.callbacks.getProps({ ...ctx, user: userContext }) || void 0;
|
|
49
|
+
} catch {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
43
53
|
function reconstructServerContext(apiCallContext, clientContext) {
|
|
44
54
|
const searchParams = {};
|
|
45
55
|
if (clientContext.search) {
|
|
@@ -78,6 +88,8 @@ async function handleClientInit(request, hctx) {
|
|
|
78
88
|
serverContext,
|
|
79
89
|
config
|
|
80
90
|
});
|
|
91
|
+
const pageCtx = { ...ctx, path: serverContext.path };
|
|
92
|
+
const propsFromCallback = await getEventProps(config, pageCtx, userContext);
|
|
81
93
|
const isSoftNavigation = hctx.isSoftNavigation;
|
|
82
94
|
const eventId = isSoftNavigation ? (0, import_uitils.generateId)() : pageRenderId;
|
|
83
95
|
const event = {
|
|
@@ -90,7 +102,7 @@ async function handleClientInit(request, hctx) {
|
|
|
90
102
|
serverContext,
|
|
91
103
|
clientContext,
|
|
92
104
|
userContext,
|
|
93
|
-
properties: {}
|
|
105
|
+
properties: { ...propsFromCallback }
|
|
94
106
|
};
|
|
95
107
|
if (isSoftNavigation) {
|
|
96
108
|
const { clientActions, completion: completion2 } = dispatchEvent(event, ctx);
|
|
@@ -115,6 +127,8 @@ async function handleClientEvent(request, hctx) {
|
|
|
115
127
|
serverContext,
|
|
116
128
|
config
|
|
117
129
|
});
|
|
130
|
+
const pageCtx = { ...ctx, path: serverContext.path };
|
|
131
|
+
const propsFromCallback = await getEventProps(config, pageCtx, userContext);
|
|
118
132
|
const event = {
|
|
119
133
|
origin: "client",
|
|
120
134
|
eventId: (0, import_uitils.generateId)(),
|
|
@@ -125,7 +139,7 @@ async function handleClientEvent(request, hctx) {
|
|
|
125
139
|
serverContext,
|
|
126
140
|
clientContext,
|
|
127
141
|
userContext,
|
|
128
|
-
properties: props
|
|
142
|
+
properties: { ...propsFromCallback, ...props }
|
|
129
143
|
};
|
|
130
144
|
const { clientActions, completion } = dispatchEvent(event, ctx);
|
|
131
145
|
const actions = await clientActions;
|
|
@@ -177,6 +191,7 @@ async function handleEventPost(request, config, dispatchEvent, updateEvent) {
|
|
|
177
191
|
}
|
|
178
192
|
// Annotate the CommonJS export names for ESM import in node:
|
|
179
193
|
0 && (module.exports = {
|
|
194
|
+
getEventProps,
|
|
180
195
|
getUserContext,
|
|
181
196
|
handleEventPost
|
|
182
197
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { Nextlytics } from './server.js';
|
|
|
2
2
|
export { getNextlyticsProps } from './pages-router.js';
|
|
3
3
|
export { NextlyticsClient, NextlyticsContext, useNextlytics } from './client.js';
|
|
4
4
|
export { loggingBackend } from './backends/logging.js';
|
|
5
|
+
export { PathMatcherOptions, pathMatcher } from './path-matcher.js';
|
|
5
6
|
export { AnonymousUserResult, BackendConfigEntry, BackendWithConfig, ClientAction, ClientContext, ClientRequest, JavascriptTemplate, NextlyticsBackend, NextlyticsBackendFactory, NextlyticsClientContext, NextlyticsConfig, NextlyticsEvent, NextlyticsPlugin, NextlyticsPluginFactory, NextlyticsResult, NextlyticsServerSide, PageViewDelivery, PagesRouterContext, RequestContext, ServerEventContext, UserContext } from './types.js';
|
|
6
7
|
import 'react/jsx-runtime';
|
|
7
8
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ __export(index_exports, {
|
|
|
22
22
|
NextlyticsClient: () => import_client.NextlyticsClient,
|
|
23
23
|
getNextlyticsProps: () => import_pages_router.getNextlyticsProps,
|
|
24
24
|
loggingBackend: () => import_logging.loggingBackend,
|
|
25
|
+
pathMatcher: () => import_path_matcher.pathMatcher,
|
|
25
26
|
useNextlytics: () => import_client.useNextlytics
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -29,11 +30,13 @@ var import_server = require("./server");
|
|
|
29
30
|
var import_pages_router = require("./pages-router");
|
|
30
31
|
var import_client = require("./client");
|
|
31
32
|
var import_logging = require("./backends/logging");
|
|
33
|
+
var import_path_matcher = require("./path-matcher");
|
|
32
34
|
// Annotate the CommonJS export names for ESM import in node:
|
|
33
35
|
0 && (module.exports = {
|
|
34
36
|
Nextlytics,
|
|
35
37
|
NextlyticsClient,
|
|
36
38
|
getNextlyticsProps,
|
|
37
39
|
loggingBackend,
|
|
40
|
+
pathMatcher,
|
|
38
41
|
useNextlytics
|
|
39
42
|
});
|
package/dist/middleware.js
CHANGED
|
@@ -29,7 +29,8 @@ var import_api_handler = require("./api-handler");
|
|
|
29
29
|
function createRequestContext(request) {
|
|
30
30
|
return {
|
|
31
31
|
headers: request.headers,
|
|
32
|
-
cookies: request.cookies
|
|
32
|
+
cookies: request.cookies,
|
|
33
|
+
path: request.nextUrl.pathname
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
function createNextlyticsMiddleware(config, dispatchEvent, updateEvent) {
|
|
@@ -71,10 +72,10 @@ function createNextlyticsMiddleware(config, dispatchEvent, updateEvent) {
|
|
|
71
72
|
return Response.json({ error: "Method not allowed" }, { status: 405 });
|
|
72
73
|
}
|
|
73
74
|
if (reqInfo.isNextjsInternal || reqInfo.isPrefetch || reqInfo.isStaticFile) {
|
|
74
|
-
return
|
|
75
|
+
return void 0;
|
|
75
76
|
}
|
|
76
77
|
if (!reqInfo.isPageNavigation && !config.isApiPath(pathname)) {
|
|
77
|
-
return
|
|
78
|
+
return void 0;
|
|
78
79
|
}
|
|
79
80
|
const pageRenderId = (0, import_uitils.generateId)();
|
|
80
81
|
const serverContext = (0, import_uitils.createServerContext)(request);
|
|
@@ -102,12 +103,14 @@ function createNextlyticsMiddleware(config, dispatchEvent, updateEvent) {
|
|
|
102
103
|
return response;
|
|
103
104
|
}
|
|
104
105
|
const userContext = await (0, import_api_handler.getUserContext)(config, ctx);
|
|
106
|
+
const extraProps = await (0, import_api_handler.getEventProps)(config, ctx, userContext);
|
|
105
107
|
const pageViewEvent = createPageViewEvent(
|
|
106
108
|
pageRenderId,
|
|
107
109
|
serverContext,
|
|
108
110
|
isApiPath,
|
|
109
111
|
userContext,
|
|
110
|
-
anonId
|
|
112
|
+
anonId,
|
|
113
|
+
extraProps
|
|
111
114
|
);
|
|
112
115
|
const { clientActions, completion } = dispatchEvent(pageViewEvent, ctx, "on-request");
|
|
113
116
|
const actions = await clientActions;
|
|
@@ -124,7 +127,7 @@ function createNextlyticsMiddleware(config, dispatchEvent, updateEvent) {
|
|
|
124
127
|
return response;
|
|
125
128
|
};
|
|
126
129
|
}
|
|
127
|
-
function createPageViewEvent(pageRenderId, serverContext, isApiPath, userContext, anonymousUserId) {
|
|
130
|
+
function createPageViewEvent(pageRenderId, serverContext, isApiPath, userContext, anonymousUserId, extraProps) {
|
|
128
131
|
const eventType = isApiPath ? "apiCall" : "pageView";
|
|
129
132
|
return {
|
|
130
133
|
origin: "server",
|
|
@@ -134,7 +137,7 @@ function createPageViewEvent(pageRenderId, serverContext, isApiPath, userContext
|
|
|
134
137
|
anonymousUserId,
|
|
135
138
|
serverContext,
|
|
136
139
|
userContext,
|
|
137
|
-
properties: {}
|
|
140
|
+
properties: { ...extraProps }
|
|
138
141
|
};
|
|
139
142
|
}
|
|
140
143
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type PathMatcherOptions = {
|
|
2
|
+
/** Paths to exclude. Matches exact path or path prefix (with `/` boundary). */
|
|
3
|
+
not?: string | string[];
|
|
4
|
+
/** Allow partial matches — path can have fewer segments than pattern. */
|
|
5
|
+
prefix?: boolean;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Match a URL path against a Next.js-style `[param]` pattern.
|
|
9
|
+
*
|
|
10
|
+
* Returns extracted params on match, or `null` on mismatch.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* pathMatcher("/[workspace]/[project]", "/acme/myproject")
|
|
15
|
+
* // => { workspace: "acme", project: "myproject" }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare function pathMatcher(pattern: string, path: string, opts?: PathMatcherOptions): Record<string, string> | null;
|
|
19
|
+
|
|
20
|
+
export { type PathMatcherOptions, pathMatcher };
|
|
@@ -0,0 +1,58 @@
|
|
|
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 path_matcher_exports = {};
|
|
20
|
+
__export(path_matcher_exports, {
|
|
21
|
+
pathMatcher: () => pathMatcher
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(path_matcher_exports);
|
|
24
|
+
function pathMatcher(pattern, path, opts) {
|
|
25
|
+
if (opts?.not) {
|
|
26
|
+
const exclusions = Array.isArray(opts.not) ? opts.not : [opts.not];
|
|
27
|
+
for (const excl of exclusions) {
|
|
28
|
+
if (path === excl || path.startsWith(excl + "/")) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
34
|
+
const pathSegments = path.split("/").filter(Boolean);
|
|
35
|
+
if (opts?.prefix) {
|
|
36
|
+
if (pathSegments.length === 0) return null;
|
|
37
|
+
if (pathSegments.length > patternSegments.length) return null;
|
|
38
|
+
} else {
|
|
39
|
+
if (pathSegments.length !== patternSegments.length) return null;
|
|
40
|
+
}
|
|
41
|
+
const params = {};
|
|
42
|
+
const segmentsToMatch = Math.min(patternSegments.length, pathSegments.length);
|
|
43
|
+
for (let i = 0; i < segmentsToMatch; i++) {
|
|
44
|
+
const pat = patternSegments[i];
|
|
45
|
+
const seg = pathSegments[i];
|
|
46
|
+
const paramMatch = pat.match(/^\[(\w+)]$/);
|
|
47
|
+
if (paramMatch) {
|
|
48
|
+
params[paramMatch[1]] = decodeURIComponent(seg);
|
|
49
|
+
} else if (pat !== seg) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return params;
|
|
54
|
+
}
|
|
55
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
56
|
+
0 && (module.exports = {
|
|
57
|
+
pathMatcher
|
|
58
|
+
});
|
package/dist/server.js
CHANGED
|
@@ -31,6 +31,7 @@ var import_client = require("./client");
|
|
|
31
31
|
var import_config_helpers = require("./config-helpers");
|
|
32
32
|
var import_middleware = require("./middleware");
|
|
33
33
|
var import_uitils = require("./uitils");
|
|
34
|
+
var import_api_handler = require("./api-handler");
|
|
34
35
|
function isBackendWithConfig(entry) {
|
|
35
36
|
return typeof entry === "object" && entry !== null && "backend" in entry;
|
|
36
37
|
}
|
|
@@ -76,7 +77,8 @@ async function createRequestContext() {
|
|
|
76
77
|
const [_cookies, _headers] = await Promise.all([(0, import_headers.cookies)(), (0, import_headers.headers)()]);
|
|
77
78
|
return {
|
|
78
79
|
cookies: _cookies,
|
|
79
|
-
headers: _headers
|
|
80
|
+
headers: _headers,
|
|
81
|
+
path: _headers.get("x-nl-pathname") || ""
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
function collectTemplates(config, ctx) {
|
|
@@ -189,7 +191,11 @@ function Nextlytics(userConfig) {
|
|
|
189
191
|
const cookieStore = await (0, import_headers.cookies)();
|
|
190
192
|
const pageRenderId = headersList.get(import_server_component_context.headerNames.pageRenderId);
|
|
191
193
|
const serverContext = createServerContextFromHeaders(headersList);
|
|
192
|
-
const ctx = {
|
|
194
|
+
const ctx = {
|
|
195
|
+
headers: headersList,
|
|
196
|
+
cookies: cookieStore,
|
|
197
|
+
path: headersList.get(import_server_component_context.headerNames.pathname) || ""
|
|
198
|
+
};
|
|
193
199
|
const { anonId: anonymousUserId } = await (0, import_anonymous_user.resolveAnonymousUser)({ ctx, serverContext, config });
|
|
194
200
|
let userContext;
|
|
195
201
|
if (config.callbacks.getUser) {
|
|
@@ -198,6 +204,7 @@ function Nextlytics(userConfig) {
|
|
|
198
204
|
} catch {
|
|
199
205
|
}
|
|
200
206
|
}
|
|
207
|
+
const propsFromCallback = await (0, import_api_handler.getEventProps)(config, ctx, userContext);
|
|
201
208
|
return {
|
|
202
209
|
sendEvent: async (eventName, opts) => {
|
|
203
210
|
if (!pageRenderId) {
|
|
@@ -213,7 +220,7 @@ function Nextlytics(userConfig) {
|
|
|
213
220
|
anonymousUserId,
|
|
214
221
|
serverContext,
|
|
215
222
|
userContext,
|
|
216
|
-
properties: opts?.props
|
|
223
|
+
properties: { ...propsFromCallback, ...opts?.props }
|
|
217
224
|
};
|
|
218
225
|
await dispatchEventInternal(event, ctx);
|
|
219
226
|
return { ok: true };
|
package/dist/types.d.ts
CHANGED
|
@@ -104,6 +104,7 @@ type AnonymousUserResult = {
|
|
|
104
104
|
type RequestContext = {
|
|
105
105
|
headers: Headers;
|
|
106
106
|
cookies: Pick<RequestCookies, "get" | "getAll" | "has">;
|
|
107
|
+
path: string;
|
|
107
108
|
};
|
|
108
109
|
type NextlyticsPlugin = {
|
|
109
110
|
/**
|
|
@@ -160,6 +161,14 @@ type NextlyticsConfig = {
|
|
|
160
161
|
ctx: RequestContext;
|
|
161
162
|
originalAnonymousUserId?: string;
|
|
162
163
|
}) => Promise<AnonymousUserResult>;
|
|
164
|
+
/**
|
|
165
|
+
* Derive extra event properties from the request context.
|
|
166
|
+
* Called on every request; the returned object is merged into `event.properties`.
|
|
167
|
+
* User-provided properties (e.g. from `sendEvent` or client custom events) take priority.
|
|
168
|
+
*/
|
|
169
|
+
getProps?: (ctx: RequestContext & {
|
|
170
|
+
user?: UserContext;
|
|
171
|
+
}) => Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;
|
|
163
172
|
};
|
|
164
173
|
/** Analytics backends to send events to */
|
|
165
174
|
backends?: BackendConfigEntry[];
|