@polishd/next 0.1.0 → 0.2.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/AGENTS.md +161 -46
- package/CHANGELOG.md +128 -0
- package/README.md +238 -48
- package/bin/doctor.mjs +374 -0
- package/bin/init.mjs +215 -188
- package/bin/polishd.mjs +85 -0
- package/bin/shared.mjs +114 -0
- package/dist/ai/actions.d.ts +7 -2
- package/dist/ai/actions.d.ts.map +1 -1
- package/dist/ai/actions.js +9 -1
- package/dist/ai/actions.js.map +1 -1
- package/dist/ai/guard.d.ts +44 -3
- package/dist/ai/guard.d.ts.map +1 -1
- package/dist/ai/guard.js +13 -2
- package/dist/ai/guard.js.map +1 -1
- package/dist/ai/providers.d.ts +2 -0
- package/dist/ai/providers.d.ts.map +1 -1
- package/dist/ai/providers.js +70 -0
- package/dist/ai/providers.js.map +1 -1
- package/dist/ai/settings.d.ts +15 -1
- package/dist/ai/settings.d.ts.map +1 -1
- package/dist/ai/settings.js +38 -1
- package/dist/ai/settings.js.map +1 -1
- package/dist/ai/types.d.ts +10 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/client/init.d.ts.map +1 -1
- package/dist/client/init.js +51 -2
- package/dist/client/init.js.map +1 -1
- package/dist/config.d.ts +57 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +62 -3
- package/dist/config.js.map +1 -1
- package/dist/dashboard/index.d.ts +34 -5
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +145 -17
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/summary.d.ts.map +1 -1
- package/dist/dashboard/summary.js +59 -5
- package/dist/dashboard/summary.js.map +1 -1
- package/dist/dashboard/token-auth.d.ts +56 -0
- package/dist/dashboard/token-auth.d.ts.map +1 -0
- package/dist/dashboard/token-auth.js +158 -0
- package/dist/dashboard/token-auth.js.map +1 -0
- package/dist/dashboard/unlock.d.ts +2 -0
- package/dist/dashboard/unlock.d.ts.map +1 -0
- package/dist/dashboard/unlock.js +54 -0
- package/dist/dashboard/unlock.js.map +1 -0
- package/dist/dashboard.css +2601 -0
- package/dist/proxy.d.ts +53 -5
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +73 -3
- package/dist/proxy.js.map +1 -1
- package/dist/route.d.ts.map +1 -1
- package/dist/route.js +11 -3
- package/dist/route.js.map +1 -1
- package/dist/server/ingest.d.ts +33 -2
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +61 -7
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/queries.d.ts +16 -0
- package/dist/server/queries.d.ts.map +1 -1
- package/dist/server/queries.js +80 -16
- package/dist/server/queries.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +4 -2
- package/dist/session.js.map +1 -1
- package/docs/SETUP.md +308 -51
- package/package.json +14 -7
package/dist/proxy.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* To compose with your own proxy logic, import `withPolishdSession` and
|
|
10
10
|
* `polishdMatcher` instead and thread the same NextResponse through.
|
|
11
11
|
*/
|
|
12
|
-
import type
|
|
12
|
+
import { NextResponse, type NextRequest } from "next/server";
|
|
13
13
|
import type { PolishdConfig } from "./config";
|
|
14
14
|
import { withPolishdSession } from "./session";
|
|
15
15
|
export { withPolishdSession };
|
|
@@ -21,7 +21,7 @@ export { withPolishdSession };
|
|
|
21
21
|
* routes don't need it. This is Next's officially recommended matcher shape.
|
|
22
22
|
*/
|
|
23
23
|
export declare const polishdMatcher: string[];
|
|
24
|
-
export declare function proxy(request: NextRequest):
|
|
24
|
+
export declare function proxy(request: NextRequest): NextResponse<unknown>;
|
|
25
25
|
export declare const config: {
|
|
26
26
|
matcher: string[];
|
|
27
27
|
};
|
|
@@ -29,12 +29,60 @@ export declare const config: {
|
|
|
29
29
|
* Build a configured proxy — use when you need a non-default cookie name (e.g.
|
|
30
30
|
* preserving a legacy `session` cookie across a migration):
|
|
31
31
|
*
|
|
32
|
-
* const { proxy
|
|
32
|
+
* const { proxy } = createPolishdProxy({ sessionCookie: "polish_session" });
|
|
33
33
|
* export { proxy };
|
|
34
|
-
* export const config = {
|
|
34
|
+
* export const config = {
|
|
35
|
+
* matcher: ["/((?!api|_next/static|_next/image|favicon|assets).*)"],
|
|
36
|
+
* };
|
|
35
37
|
*/
|
|
36
38
|
export declare function createPolishdProxy(config?: Partial<PolishdConfig>): {
|
|
37
|
-
proxy: (request: NextRequest) =>
|
|
39
|
+
proxy: (request: NextRequest) => NextResponse<unknown>;
|
|
38
40
|
matcher: string[];
|
|
39
41
|
};
|
|
42
|
+
/** A host's own proxy handler. May be sync or async, and may return nothing. */
|
|
43
|
+
export type PolishdComposableHandler = (request: NextRequest) => NextResponse | undefined | void | Promise<NextResponse | undefined | void>;
|
|
44
|
+
export interface ComposePolishdOptions {
|
|
45
|
+
/**
|
|
46
|
+
* The paths your own handler ran on *before* Polishd was added.
|
|
47
|
+
*
|
|
48
|
+
* This is the part of merging that goes wrong quietly. Next allows exactly
|
|
49
|
+
* one proxy module per app, so adding Polishd means widening
|
|
50
|
+
* `config.matcher` to the union of both — and Polishd's matcher is
|
|
51
|
+
* near-total. Your handler, which you deliberately scoped to two routes,
|
|
52
|
+
* silently starts running on every request in the app. Nothing errors; your
|
|
53
|
+
* redirects and rewrites just begin firing where they never did before.
|
|
54
|
+
*
|
|
55
|
+
* Declare the original scope here and it is re-applied as an internal guard,
|
|
56
|
+
* so the widened matcher feeds Polishd everything while your handler keeps
|
|
57
|
+
* seeing exactly what it saw before.
|
|
58
|
+
*
|
|
59
|
+
* Accepts Next's matcher strings (`"/admin/:path*"`, `"/((?!api).*)"`) or a
|
|
60
|
+
* `RegExp` when you want to be exact. Omit it only if your handler genuinely
|
|
61
|
+
* did run on everything.
|
|
62
|
+
*/
|
|
63
|
+
matcher?: string | RegExp | Array<string | RegExp>;
|
|
64
|
+
/** Non-default cookie name, matching your route and client config. */
|
|
65
|
+
config?: Partial<PolishdConfig>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Wrap an existing proxy handler so Polishd's session cookie is minted
|
|
69
|
+
* alongside it:
|
|
70
|
+
*
|
|
71
|
+
* // proxy.ts (middleware.ts on Next 15)
|
|
72
|
+
* export const proxy = composePolishd(myProxy, { matcher: "/admin/:path*" });
|
|
73
|
+
* export const config = {
|
|
74
|
+
* // Still written by hand: Next statically parses this and it must be an
|
|
75
|
+
* // inline literal. The union of your paths and Polishd's.
|
|
76
|
+
* matcher: ["/((?!api|_next/static|_next/image|favicon|assets).*)"],
|
|
77
|
+
* };
|
|
78
|
+
*
|
|
79
|
+
* Your handler runs first and its response is threaded through, so a redirect
|
|
80
|
+
* or rewrite you return carries the analytics cookie rather than losing it.
|
|
81
|
+
* Returning nothing is fine — Polishd continues with a default response.
|
|
82
|
+
*
|
|
83
|
+
* Widening the matcher is safe from Polishd's side: `withPolishdSession`
|
|
84
|
+
* returns early once the cookie is present (see session.ts), so the extra
|
|
85
|
+
* paths cost a cookie lookup and nothing else.
|
|
86
|
+
*/
|
|
87
|
+
export declare function composePolishd(handler: PolishdComposableHandler, opts?: ComposePolishdOptions): (request: NextRequest) => Promise<NextResponse>;
|
|
40
88
|
//# sourceMappingURL=proxy.d.ts.map
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,UAA2D,CAAC;AAEvF,wBAAgB,KAAK,CAAC,OAAO,EAAE,WAAW,yBAEzC;AAED,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;qBAEjD,WAAW;;EAG/B;AAID,gFAAgF;AAChF,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,WAAW,KACjB,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;AAEhF,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACnD,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACjC;AAyBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,wBAAwB,EACjC,IAAI,GAAE,qBAA0B,IAKJ,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,CAMzE"}
|
package/dist/proxy.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @polishd/next/proxy — anonymous session assignment.
|
|
3
|
+
*
|
|
4
|
+
* Consumers wire this up with a one-line re-export:
|
|
5
|
+
*
|
|
6
|
+
* // src/proxy.ts (Next 16; `middleware.ts` on Next 15)
|
|
7
|
+
* export { proxy, config } from "@polishd/next/proxy";
|
|
8
|
+
*
|
|
9
|
+
* To compose with your own proxy logic, import `withPolishdSession` and
|
|
10
|
+
* `polishdMatcher` instead and thread the same NextResponse through.
|
|
11
|
+
*/
|
|
12
|
+
import { NextResponse } from "next/server";
|
|
1
13
|
import { withPolishdSession } from "./session";
|
|
2
14
|
export { withPolishdSession };
|
|
3
15
|
/**
|
|
@@ -11,14 +23,18 @@ export const polishdMatcher = ["/((?!api|_next/static|_next/image|favicon|assets
|
|
|
11
23
|
export function proxy(request) {
|
|
12
24
|
return withPolishdSession(request);
|
|
13
25
|
}
|
|
14
|
-
export const config = {
|
|
26
|
+
export const config = {
|
|
27
|
+
matcher: ["/((?!api|_next/static|_next/image|favicon|assets).*)"],
|
|
28
|
+
};
|
|
15
29
|
/**
|
|
16
30
|
* Build a configured proxy — use when you need a non-default cookie name (e.g.
|
|
17
31
|
* preserving a legacy `session` cookie across a migration):
|
|
18
32
|
*
|
|
19
|
-
* const { proxy
|
|
33
|
+
* const { proxy } = createPolishdProxy({ sessionCookie: "polish_session" });
|
|
20
34
|
* export { proxy };
|
|
21
|
-
* export const config = {
|
|
35
|
+
* export const config = {
|
|
36
|
+
* matcher: ["/((?!api|_next/static|_next/image|favicon|assets).*)"],
|
|
37
|
+
* };
|
|
22
38
|
*/
|
|
23
39
|
export function createPolishdProxy(config = {}) {
|
|
24
40
|
return {
|
|
@@ -26,4 +42,58 @@ export function createPolishdProxy(config = {}) {
|
|
|
26
42
|
matcher: polishdMatcher,
|
|
27
43
|
};
|
|
28
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Translate one Next matcher entry into a testable RegExp.
|
|
47
|
+
*
|
|
48
|
+
* Next's own matcher syntax is a subset of path-to-regexp: literal paths,
|
|
49
|
+
* `:param` and `:param*` segments, and raw regex bodies in parentheses. Those
|
|
50
|
+
* are handled here; anything more exotic can be passed as a `RegExp` directly.
|
|
51
|
+
*/
|
|
52
|
+
function toRegExp(pattern) {
|
|
53
|
+
if (pattern instanceof RegExp)
|
|
54
|
+
return pattern;
|
|
55
|
+
// Already regex-shaped, as in the near-total matcher Polishd itself uses.
|
|
56
|
+
if (pattern.includes("("))
|
|
57
|
+
return new RegExp(`^${pattern}$`);
|
|
58
|
+
let out = "";
|
|
59
|
+
for (const seg of pattern.split("/").slice(1)) {
|
|
60
|
+
if (seg.startsWith(":")) {
|
|
61
|
+
// `:path*` matches zero or more segments, so the slash goes with it.
|
|
62
|
+
out += seg.endsWith("*") ? "(?:/.*)?" : "/[^/]+";
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
out += `/${seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return new RegExp(`^${out || "/"}$`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wrap an existing proxy handler so Polishd's session cookie is minted
|
|
72
|
+
* alongside it:
|
|
73
|
+
*
|
|
74
|
+
* // proxy.ts (middleware.ts on Next 15)
|
|
75
|
+
* export const proxy = composePolishd(myProxy, { matcher: "/admin/:path*" });
|
|
76
|
+
* export const config = {
|
|
77
|
+
* // Still written by hand: Next statically parses this and it must be an
|
|
78
|
+
* // inline literal. The union of your paths and Polishd's.
|
|
79
|
+
* matcher: ["/((?!api|_next/static|_next/image|favicon|assets).*)"],
|
|
80
|
+
* };
|
|
81
|
+
*
|
|
82
|
+
* Your handler runs first and its response is threaded through, so a redirect
|
|
83
|
+
* or rewrite you return carries the analytics cookie rather than losing it.
|
|
84
|
+
* Returning nothing is fine — Polishd continues with a default response.
|
|
85
|
+
*
|
|
86
|
+
* Widening the matcher is safe from Polishd's side: `withPolishdSession`
|
|
87
|
+
* returns early once the cookie is present (see session.ts), so the extra
|
|
88
|
+
* paths cost a cookie lookup and nothing else.
|
|
89
|
+
*/
|
|
90
|
+
export function composePolishd(handler, opts = {}) {
|
|
91
|
+
const declared = opts.matcher === undefined ? [] : [opts.matcher].flat();
|
|
92
|
+
const guards = declared.map(toRegExp);
|
|
93
|
+
return async function proxy(request) {
|
|
94
|
+
const inScope = guards.length === 0 || guards.some((re) => re.test(request.nextUrl.pathname));
|
|
95
|
+
const response = inScope ? await handler(request) : undefined;
|
|
96
|
+
return withPolishdSession(request, response ?? NextResponse.next(), opts.config);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
29
99
|
//# sourceMappingURL=proxy.js.map
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,sDAAsD,CAAC,CAAC;AAEvF,MAAM,UAAU,KAAK,CAAC,OAAoB;IACxC,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,OAAO,EAAE,CAAC,sDAAsD,CAAC;CAClE,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiC,EAAE;IACpE,OAAO;QACL,KAAK,EAAE,CAAC,OAAoB,EAAE,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;QAC/E,OAAO,EAAE,cAAc;KACxB,CAAC;AACJ,CAAC;AAiCD;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,OAAwB;IACxC,IAAI,OAAO,YAAY,MAAM;QAAE,OAAO,OAAO,CAAC;IAC9C,0EAA0E;IAC1E,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;IAC7D,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,qEAAqE;YACrE,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAiC,EACjC,OAA8B,EAAE;IAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACzE,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEtC,OAAO,KAAK,UAAU,KAAK,CAAC,OAAoB;QAC9C,MAAM,OAAO,GACX,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,OAAO,kBAAkB,CAAC,OAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACnF,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/route.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAA8C,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAI1F,eAAO,MAAM,OAAO,WAAW,CAAC;AAEhC,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM,IAWzC,KAAK,WAAW;;;oDAe5C;AAED,wDAAwD;AACxD,eAAO,MAAM,IAAI,QAlBiB,WAAW;;;mDAkBL,CAAC"}
|
package/dist/route.js
CHANGED
|
@@ -9,14 +9,22 @@
|
|
|
9
9
|
* Or build a configured handler with `createPolishdRoute({ sessionCookie })`.
|
|
10
10
|
*/
|
|
11
11
|
import { NextResponse } from "next/server";
|
|
12
|
-
import { defaultPolishdConfig } from "./config";
|
|
12
|
+
import { defaultPolishdConfig, resolveSessionCookie } from "./config";
|
|
13
13
|
import { ingest } from "./server/ingest";
|
|
14
14
|
// node:sqlite / pg need the Node runtime — never the Edge runtime.
|
|
15
15
|
export const runtime = "nodejs";
|
|
16
16
|
// This route mutates per-request; it must never be statically cached.
|
|
17
17
|
export const dynamic = "force-dynamic";
|
|
18
18
|
export function createPolishdRoute(config = {}) {
|
|
19
|
-
|
|
19
|
+
// The cookie name is resolved the way the proxy resolves it, so a
|
|
20
|
+
// `POLISHD_SESSION_COOKIE` set once reaches both sides rather than half of
|
|
21
|
+
// them — and it is folded into `cfg` so everything downstream, ingest
|
|
22
|
+
// included, sees the same name this handler reads.
|
|
23
|
+
const cfg = {
|
|
24
|
+
...defaultPolishdConfig,
|
|
25
|
+
...config,
|
|
26
|
+
sessionCookie: resolveSessionCookie(config.sessionCookie),
|
|
27
|
+
};
|
|
20
28
|
return async function POST(req) {
|
|
21
29
|
let body;
|
|
22
30
|
try {
|
|
@@ -26,7 +34,7 @@ export function createPolishdRoute(config = {}) {
|
|
|
26
34
|
return NextResponse.json({ ok: false, reason: "bad_json" }, { status: 400 });
|
|
27
35
|
}
|
|
28
36
|
const cookieValue = req.cookies.get(cfg.sessionCookie)?.value;
|
|
29
|
-
const result = await ingest(body, cookieValue);
|
|
37
|
+
const result = await ingest(body, cookieValue, cfg);
|
|
30
38
|
// Always succeed for valid requests so the beacon never retries on the
|
|
31
39
|
// client; real failures (bad payloads) return 4xx above.
|
|
32
40
|
return NextResponse.json(result, { status: result.ok ? 200 : 400 });
|
package/dist/route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,mEAAmE;AACnE,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC;AAChC,sEAAsE;AACtE,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC;AAEvC,MAAM,UAAU,kBAAkB,CAAC,SAAiC,EAAE;IACpE,kEAAkE;IAClE,2EAA2E;IAC3E,sEAAsE;IACtE,mDAAmD;IACnD,MAAM,GAAG,GAAG;QACV,GAAG,oBAAoB;QACvB,GAAG,MAAM;QACT,aAAa,EAAE,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC;KAC1D,CAAC;IAEF,OAAO,KAAK,UAAU,IAAI,CAAC,GAAgB;QACzC,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;QAEpD,uEAAuE;QACvE,yDAAyD;QACzD,OAAO,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC"}
|
package/dist/server/ingest.d.ts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polishd — ingest (server only).
|
|
3
|
+
*
|
|
4
|
+
* Validates and sanitizes an inbound batch, then hands clean events to the
|
|
5
|
+
* store. The session id is taken from the request's cookie, never from the
|
|
6
|
+
* body, so events are always attributed to the bearer of the cookie.
|
|
7
|
+
*/
|
|
8
|
+
import { type PolishdConfig } from "../config";
|
|
9
|
+
/**
|
|
10
|
+
* Beacons dropped for want of a session cookie, recorded in `polishd_meta`.
|
|
11
|
+
*
|
|
12
|
+
* A missing cookie means the proxy isn't running — a misnamed proxy file, a
|
|
13
|
+
* matcher that excludes the path, or a botched merge with an existing handler.
|
|
14
|
+
* Left uncounted this is the worst failure mode in the package: ingest returns
|
|
15
|
+
* `ok: true` with HTTP 200, the client cannot read the reason (`sendBeacon`
|
|
16
|
+
* has no response), and the only symptom is an empty dashboard with nothing
|
|
17
|
+
* anywhere pointing at the cause. Counting it is what lets the dashboard say
|
|
18
|
+
* so out loud.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NO_SESSION_META_KEY = "no_session_rejects";
|
|
21
|
+
/** Shape stored under {@link NO_SESSION_META_KEY}. */
|
|
22
|
+
export interface NoSessionRecord {
|
|
23
|
+
count: number;
|
|
24
|
+
lastAt: number;
|
|
25
|
+
}
|
|
1
26
|
export interface IngestResult {
|
|
2
27
|
ok: boolean;
|
|
3
28
|
stored: number;
|
|
@@ -9,6 +34,12 @@ export interface IngestResult {
|
|
|
9
34
|
* legitimately has none, in which case we skip rather than error.
|
|
10
35
|
*/
|
|
11
36
|
export declare function sessionIdFromCookie(cookieValue: string | undefined): string | null;
|
|
12
|
-
/**
|
|
13
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Ingest a raw request body. `cookieValue` is the session cookie's value.
|
|
39
|
+
*
|
|
40
|
+
* `config` carries the host app's overrides (the route handler forwards what it
|
|
41
|
+
* was built with) so `enabled` and `dashboardRoute` mean the same thing here as
|
|
42
|
+
* they do in the browser. It falls back to the defaults when omitted.
|
|
43
|
+
*/
|
|
44
|
+
export declare function ingest(body: unknown, cookieValue: string | undefined, config?: Partial<PolishdConfig>): Promise<IngestResult>;
|
|
14
45
|
//# sourceMappingURL=ingest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAQtF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AA+BD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAElF;AAiCD;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM,GAClC,OAAO,CAAC,YAAY,CAAC,CAwBvB"}
|
package/dist/server/ingest.js
CHANGED
|
@@ -5,12 +5,54 @@
|
|
|
5
5
|
* store. The session id is taken from the request's cookie, never from the
|
|
6
6
|
* body, so events are always attributed to the bearer of the cookie.
|
|
7
7
|
*/
|
|
8
|
-
import { defaultPolishdConfig } from "../config";
|
|
8
|
+
import { defaultPolishdConfig, isDashboardPath } from "../config";
|
|
9
9
|
import { CLIENT_EVENT_TYPES } from "../shared/types";
|
|
10
|
-
import { insertEvents } from "./store";
|
|
10
|
+
import { getMeta, insertEvents, setMeta } from "./store";
|
|
11
11
|
const MAX_EVENTS_PER_BATCH = 200;
|
|
12
12
|
const MAX_TEXT_LEN = 120;
|
|
13
13
|
const MAX_SELECTOR_LEN = 300;
|
|
14
|
+
/**
|
|
15
|
+
* Beacons dropped for want of a session cookie, recorded in `polishd_meta`.
|
|
16
|
+
*
|
|
17
|
+
* A missing cookie means the proxy isn't running — a misnamed proxy file, a
|
|
18
|
+
* matcher that excludes the path, or a botched merge with an existing handler.
|
|
19
|
+
* Left uncounted this is the worst failure mode in the package: ingest returns
|
|
20
|
+
* `ok: true` with HTTP 200, the client cannot read the reason (`sendBeacon`
|
|
21
|
+
* has no response), and the only symptom is an empty dashboard with nothing
|
|
22
|
+
* anywhere pointing at the cause. Counting it is what lets the dashboard say
|
|
23
|
+
* so out loud.
|
|
24
|
+
*/
|
|
25
|
+
export const NO_SESSION_META_KEY = "no_session_rejects";
|
|
26
|
+
// A broken proxy means *every* beacon is rejected, so writing per rejection
|
|
27
|
+
// would answer a diagnostic with a write storm. Collapse them instead: count
|
|
28
|
+
// in memory, persist at most once a minute.
|
|
29
|
+
const RECORD_INTERVAL_MS = 60_000;
|
|
30
|
+
let lastPersistedAt = 0;
|
|
31
|
+
let unpersisted = 0;
|
|
32
|
+
async function recordNoSession() {
|
|
33
|
+
unpersisted++;
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
if (now - lastPersistedAt < RECORD_INTERVAL_MS)
|
|
36
|
+
return;
|
|
37
|
+
lastPersistedAt = now;
|
|
38
|
+
const batch = unpersisted;
|
|
39
|
+
unpersisted = 0;
|
|
40
|
+
try {
|
|
41
|
+
let count = 0;
|
|
42
|
+
const raw = await getMeta(NO_SESSION_META_KEY);
|
|
43
|
+
if (raw) {
|
|
44
|
+
const prev = JSON.parse(raw);
|
|
45
|
+
if (typeof prev.count === "number" && Number.isFinite(prev.count))
|
|
46
|
+
count = prev.count;
|
|
47
|
+
}
|
|
48
|
+
const next = { count: count + batch, lastAt: now };
|
|
49
|
+
await setMeta(NO_SESSION_META_KEY, JSON.stringify(next));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Diagnostics must never take ingest down with them. A store that can't
|
|
53
|
+
// record the rejection still returns a clean result to the beacon.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
14
56
|
/**
|
|
15
57
|
* Pull the anonymous session id from the cookie. Returns null when absent —
|
|
16
58
|
* the middleware normally guarantees one, but a client with cookies disabled
|
|
@@ -53,20 +95,32 @@ function sanitize(raw) {
|
|
|
53
95
|
}
|
|
54
96
|
return out;
|
|
55
97
|
}
|
|
56
|
-
/**
|
|
57
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Ingest a raw request body. `cookieValue` is the session cookie's value.
|
|
100
|
+
*
|
|
101
|
+
* `config` carries the host app's overrides (the route handler forwards what it
|
|
102
|
+
* was built with) so `enabled` and `dashboardRoute` mean the same thing here as
|
|
103
|
+
* they do in the browser. It falls back to the defaults when omitted.
|
|
104
|
+
*/
|
|
105
|
+
export async function ingest(body, cookieValue, config = {}) {
|
|
106
|
+
const cfg = { ...defaultPolishdConfig, ...config };
|
|
58
107
|
const sessionId = sessionIdFromCookie(cookieValue);
|
|
59
|
-
if (!sessionId)
|
|
108
|
+
if (!sessionId) {
|
|
109
|
+
await recordNoSession();
|
|
60
110
|
return { ok: true, stored: 0, reason: "no_session" };
|
|
61
|
-
|
|
111
|
+
}
|
|
112
|
+
if (!cfg.enabled)
|
|
62
113
|
return { ok: true, stored: 0, reason: "disabled" };
|
|
63
114
|
const rawEvents = body?.events;
|
|
64
115
|
if (!Array.isArray(rawEvents))
|
|
65
116
|
return { ok: false, stored: 0, reason: "no_events" };
|
|
117
|
+
// The client already drops the dashboard's own traffic; this is the copy of
|
|
118
|
+
// that rule that actually holds, since the endpoint is a public POST and a
|
|
119
|
+
// cached client bundle can lag a config change by a full session.
|
|
66
120
|
const events = rawEvents
|
|
67
121
|
.slice(0, MAX_EVENTS_PER_BATCH)
|
|
68
122
|
.map(sanitize)
|
|
69
|
-
.filter((e) => e !== null);
|
|
123
|
+
.filter((e) => e !== null && !isDashboardPath(e.path, cfg.dashboardRoute));
|
|
70
124
|
const stored = await insertEvents(sessionId, events);
|
|
71
125
|
return { ok: true, stored };
|
|
72
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"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"}
|
package/dist/server/queries.d.ts
CHANGED
|
@@ -225,9 +225,25 @@ export interface MonitoredComponent {
|
|
|
225
225
|
* matching how `getSessionJourneys` and `getTopPages` keep their SQL portable.
|
|
226
226
|
*/
|
|
227
227
|
export declare function getMonitoredComponents(): Promise<MonitoredComponent[]>;
|
|
228
|
+
/** Whether capture itself is wired up, as opposed to what it captured. */
|
|
229
|
+
export interface CaptureHealth {
|
|
230
|
+
/** Beacons dropped because the request carried no session cookie. */
|
|
231
|
+
noSessionCount: number;
|
|
232
|
+
/** When the most recent such drop happened (ms epoch), or null for none. */
|
|
233
|
+
lastNoSessionAt: number | null;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Read the proxy-health counter recorded by ingest.
|
|
237
|
+
*
|
|
238
|
+
* This is the one number that distinguishes "nobody has visited yet" from
|
|
239
|
+
* "everybody has visited and every event was thrown away", which otherwise
|
|
240
|
+
* look identical on the dashboard: an empty page with no error.
|
|
241
|
+
*/
|
|
242
|
+
export declare function getCaptureHealth(): Promise<CaptureHealth>;
|
|
228
243
|
/** Everything the dashboard (and the AI summary) reads, in one shape. */
|
|
229
244
|
export interface PolishdDashboardData {
|
|
230
245
|
overview: Awaited<ReturnType<typeof getOverview>>;
|
|
246
|
+
health: CaptureHealth;
|
|
231
247
|
pages: Awaited<ReturnType<typeof getTopPages>>;
|
|
232
248
|
elements: Awaited<ReturnType<typeof getElementStats>>;
|
|
233
249
|
devices: Awaited<ReturnType<typeof getDeviceBreakdown>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/server/queries.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/server/queries.ts"],"names":[],"mappings":"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"}
|