next-fetch-panel 0.1.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/README.md +175 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +922 -0
- package/dist/index.mjs +922 -0
- package/dist/middleware.d.mts +35 -0
- package/dist/middleware.d.ts +35 -0
- package/dist/middleware.js +65 -0
- package/dist/middleware.mjs +38 -0
- package/dist/patch.d.mts +15 -0
- package/dist/patch.d.ts +15 -0
- package/dist/patch.js +244 -0
- package/dist/patch.mjs +215 -0
- package/dist/route.d.mts +23 -0
- package/dist/route.d.ts +23 -0
- package/dist/route.js +96 -0
- package/dist/route.mjs +69 -0
- package/package.json +72 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
type MiddlewareHandler = (request: NextRequest) => NextResponse | Response | null | undefined | void | Promise<NextResponse | Response | null | undefined | void>;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps your existing middleware with the dev panel session logic.
|
|
6
|
+
*
|
|
7
|
+
* Simple (no other middleware):
|
|
8
|
+
* export const { middleware, config } = withDevPanel()
|
|
9
|
+
*
|
|
10
|
+
* With your own logic:
|
|
11
|
+
* export const { middleware, config } = withDevPanel(async (request) => {
|
|
12
|
+
* if (!isAuthenticated(request))
|
|
13
|
+
* return NextResponse.redirect(new URL("/login", request.url))
|
|
14
|
+
* // return nothing to let the request continue normally
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* Custom matcher:
|
|
18
|
+
* export const { middleware, config } = withDevPanel(handler, {
|
|
19
|
+
* matcher: ["/api/:path*", "/((?!_next).*)"],
|
|
20
|
+
* })
|
|
21
|
+
*/
|
|
22
|
+
declare function withDevPanel(handler?: MiddlewareHandler, options?: {
|
|
23
|
+
matcher?: string[];
|
|
24
|
+
}): {
|
|
25
|
+
middleware: (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
26
|
+
config: {
|
|
27
|
+
matcher: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
declare const middleware: (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
31
|
+
declare const config: {
|
|
32
|
+
matcher: string[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { config, middleware, withDevPanel };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
type MiddlewareHandler = (request: NextRequest) => NextResponse | Response | null | undefined | void | Promise<NextResponse | Response | null | undefined | void>;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps your existing middleware with the dev panel session logic.
|
|
6
|
+
*
|
|
7
|
+
* Simple (no other middleware):
|
|
8
|
+
* export const { middleware, config } = withDevPanel()
|
|
9
|
+
*
|
|
10
|
+
* With your own logic:
|
|
11
|
+
* export const { middleware, config } = withDevPanel(async (request) => {
|
|
12
|
+
* if (!isAuthenticated(request))
|
|
13
|
+
* return NextResponse.redirect(new URL("/login", request.url))
|
|
14
|
+
* // return nothing to let the request continue normally
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* Custom matcher:
|
|
18
|
+
* export const { middleware, config } = withDevPanel(handler, {
|
|
19
|
+
* matcher: ["/api/:path*", "/((?!_next).*)"],
|
|
20
|
+
* })
|
|
21
|
+
*/
|
|
22
|
+
declare function withDevPanel(handler?: MiddlewareHandler, options?: {
|
|
23
|
+
matcher?: string[];
|
|
24
|
+
}): {
|
|
25
|
+
middleware: (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
26
|
+
config: {
|
|
27
|
+
matcher: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
declare const middleware: (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
31
|
+
declare const config: {
|
|
32
|
+
matcher: string[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { config, middleware, withDevPanel };
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
|
|
20
|
+
// src/middleware.ts
|
|
21
|
+
var middleware_exports = {};
|
|
22
|
+
__export(middleware_exports, {
|
|
23
|
+
config: () => config,
|
|
24
|
+
middleware: () => middleware,
|
|
25
|
+
withDevPanel: () => withDevPanel
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(middleware_exports);
|
|
28
|
+
var import_server = require("next/server");
|
|
29
|
+
function withDevPanel(handler, options) {
|
|
30
|
+
async function middleware2(request) {
|
|
31
|
+
const existing = request.cookies.get("__dev_sid")?.value;
|
|
32
|
+
const sid = existing ?? crypto.randomUUID();
|
|
33
|
+
const userResponse = await handler?.(request);
|
|
34
|
+
let response;
|
|
35
|
+
if (userResponse instanceof Response) {
|
|
36
|
+
response = userResponse;
|
|
37
|
+
} else {
|
|
38
|
+
const requestHeaders = new Headers(request.headers);
|
|
39
|
+
requestHeaders.set("x-dev-sid", sid);
|
|
40
|
+
response = import_server.NextResponse.next({ request: { headers: requestHeaders } });
|
|
41
|
+
}
|
|
42
|
+
if (!existing) {
|
|
43
|
+
response.cookies.set("__dev_sid", sid, {
|
|
44
|
+
httpOnly: true,
|
|
45
|
+
sameSite: "lax",
|
|
46
|
+
path: "/",
|
|
47
|
+
maxAge: 60 * 60 * 24 * 365
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
middleware: middleware2,
|
|
54
|
+
config: {
|
|
55
|
+
matcher: options?.matcher ?? ["/((?!_next/static|_next/image|favicon.ico).*)"]
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var { middleware, config } = withDevPanel();
|
|
60
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
61
|
+
0 && (module.exports = {
|
|
62
|
+
config,
|
|
63
|
+
middleware,
|
|
64
|
+
withDevPanel
|
|
65
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/middleware.ts
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
function withDevPanel(handler, options) {
|
|
4
|
+
async function middleware2(request) {
|
|
5
|
+
const existing = request.cookies.get("__dev_sid")?.value;
|
|
6
|
+
const sid = existing ?? crypto.randomUUID();
|
|
7
|
+
const userResponse = await handler?.(request);
|
|
8
|
+
let response;
|
|
9
|
+
if (userResponse instanceof Response) {
|
|
10
|
+
response = userResponse;
|
|
11
|
+
} else {
|
|
12
|
+
const requestHeaders = new Headers(request.headers);
|
|
13
|
+
requestHeaders.set("x-dev-sid", sid);
|
|
14
|
+
response = NextResponse.next({ request: { headers: requestHeaders } });
|
|
15
|
+
}
|
|
16
|
+
if (!existing) {
|
|
17
|
+
response.cookies.set("__dev_sid", sid, {
|
|
18
|
+
httpOnly: true,
|
|
19
|
+
sameSite: "lax",
|
|
20
|
+
path: "/",
|
|
21
|
+
maxAge: 60 * 60 * 24 * 365
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
middleware: middleware2,
|
|
28
|
+
config: {
|
|
29
|
+
matcher: options?.matcher ?? ["/((?!_next/static|_next/image|favicon.ico).*)"]
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
var { middleware, config } = withDevPanel();
|
|
34
|
+
export {
|
|
35
|
+
config,
|
|
36
|
+
middleware,
|
|
37
|
+
withDevPanel
|
|
38
|
+
};
|
package/dist/patch.d.mts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patches globalThis.fetch to capture server-side requests.
|
|
3
|
+
* Call this inside your own register() if you already have one:
|
|
4
|
+
*
|
|
5
|
+
* export async function register() {
|
|
6
|
+
* registerOTel("my-app") // your existing setup
|
|
7
|
+
* await registerDevPanel() // add the panel
|
|
8
|
+
* }
|
|
9
|
+
*
|
|
10
|
+
* For simple use with no other setup:
|
|
11
|
+
* export { register } from "./server-network-panel/patch"
|
|
12
|
+
*/
|
|
13
|
+
declare function registerDevPanel(): Promise<void>;
|
|
14
|
+
|
|
15
|
+
export { registerDevPanel as register, registerDevPanel };
|
package/dist/patch.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patches globalThis.fetch to capture server-side requests.
|
|
3
|
+
* Call this inside your own register() if you already have one:
|
|
4
|
+
*
|
|
5
|
+
* export async function register() {
|
|
6
|
+
* registerOTel("my-app") // your existing setup
|
|
7
|
+
* await registerDevPanel() // add the panel
|
|
8
|
+
* }
|
|
9
|
+
*
|
|
10
|
+
* For simple use with no other setup:
|
|
11
|
+
* export { register } from "./server-network-panel/patch"
|
|
12
|
+
*/
|
|
13
|
+
declare function registerDevPanel(): Promise<void>;
|
|
14
|
+
|
|
15
|
+
export { registerDevPanel as register, registerDevPanel };
|
package/dist/patch.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/store.ts
|
|
34
|
+
var store_exports = {};
|
|
35
|
+
__export(store_exports, {
|
|
36
|
+
devLogStore: () => devLogStore
|
|
37
|
+
});
|
|
38
|
+
function createStore() {
|
|
39
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
40
|
+
const buffer = [];
|
|
41
|
+
return {
|
|
42
|
+
push(entry) {
|
|
43
|
+
buffer.push(entry);
|
|
44
|
+
if (buffer.length > BUFFER_SIZE) buffer.shift();
|
|
45
|
+
subscribers.forEach((fn) => fn(entry));
|
|
46
|
+
},
|
|
47
|
+
subscribe(fn) {
|
|
48
|
+
subscribers.add(fn);
|
|
49
|
+
return () => subscribers.delete(fn);
|
|
50
|
+
},
|
|
51
|
+
getBuffer() {
|
|
52
|
+
return buffer.slice();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
var BUFFER_SIZE, devLogStore;
|
|
57
|
+
var init_store = __esm({
|
|
58
|
+
"src/store.ts"() {
|
|
59
|
+
"use strict";
|
|
60
|
+
BUFFER_SIZE = 100;
|
|
61
|
+
devLogStore = globalThis.__devLogStore ?? (globalThis.__devLogStore = createStore());
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// src/redact.ts
|
|
66
|
+
var redact_exports = {};
|
|
67
|
+
__export(redact_exports, {
|
|
68
|
+
redactConfig: () => redactConfig,
|
|
69
|
+
redactEntry: () => redactEntry
|
|
70
|
+
});
|
|
71
|
+
function redactUrl(url, params) {
|
|
72
|
+
try {
|
|
73
|
+
const u = new URL(url);
|
|
74
|
+
for (const key of params) {
|
|
75
|
+
if (u.searchParams.has(key)) u.searchParams.set(key, REDACTED);
|
|
76
|
+
}
|
|
77
|
+
return u.toString();
|
|
78
|
+
} catch {
|
|
79
|
+
return url;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function redactHeaders(headers, names) {
|
|
83
|
+
const lower = new Set(names.map((n) => n.toLowerCase()));
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
86
|
+
out[k] = lower.has(k.toLowerCase()) ? REDACTED : v;
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
function redactBody(body, keys) {
|
|
91
|
+
if (!body) return body;
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(body);
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
if (key in parsed) parsed[key] = REDACTED;
|
|
96
|
+
}
|
|
97
|
+
return JSON.stringify(parsed, null, 2);
|
|
98
|
+
} catch {
|
|
99
|
+
return body;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function redactEntry(entry) {
|
|
103
|
+
return {
|
|
104
|
+
...entry,
|
|
105
|
+
url: redactUrl(entry.url, redactConfig.urlParams),
|
|
106
|
+
requestHeaders: redactHeaders(entry.requestHeaders, redactConfig.headers),
|
|
107
|
+
responseHeaders: redactHeaders(entry.responseHeaders, redactConfig.headers),
|
|
108
|
+
requestBody: redactBody(entry.requestBody, redactConfig.bodyKeys),
|
|
109
|
+
responseBody: redactBody(entry.responseBody, redactConfig.bodyKeys)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
var redactConfig, REDACTED;
|
|
113
|
+
var init_redact = __esm({
|
|
114
|
+
"src/redact.ts"() {
|
|
115
|
+
"use strict";
|
|
116
|
+
redactConfig = {
|
|
117
|
+
urlParams: ["api_key", "apikey", "secret", "token", "access_token", "password", "key"],
|
|
118
|
+
headers: ["authorization", "x-api-key", "x-secret", "x-auth-token"],
|
|
119
|
+
bodyKeys: ["password", "secret", "token", "api_key", "apiKey", "accessToken", "access_token"]
|
|
120
|
+
};
|
|
121
|
+
REDACTED = "[REDACTED]";
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// src/patch.ts
|
|
126
|
+
var patch_exports = {};
|
|
127
|
+
__export(patch_exports, {
|
|
128
|
+
register: () => registerDevPanel,
|
|
129
|
+
registerDevPanel: () => registerDevPanel
|
|
130
|
+
});
|
|
131
|
+
module.exports = __toCommonJS(patch_exports);
|
|
132
|
+
var BODY_LIMIT = 5e4;
|
|
133
|
+
function headersToObject(headers) {
|
|
134
|
+
if (!headers) return {};
|
|
135
|
+
if (headers instanceof Headers) {
|
|
136
|
+
const obj = {};
|
|
137
|
+
headers.forEach((v, k) => {
|
|
138
|
+
obj[k] = v;
|
|
139
|
+
});
|
|
140
|
+
return obj;
|
|
141
|
+
}
|
|
142
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
143
|
+
return headers;
|
|
144
|
+
}
|
|
145
|
+
function extractRequestBody(init) {
|
|
146
|
+
const body = init?.body;
|
|
147
|
+
if (body == null) return null;
|
|
148
|
+
if (typeof body === "string") return body.slice(0, BODY_LIMIT);
|
|
149
|
+
if (body instanceof URLSearchParams) return body.toString().slice(0, BODY_LIMIT);
|
|
150
|
+
return "[binary]";
|
|
151
|
+
}
|
|
152
|
+
var nextHeaders = null;
|
|
153
|
+
async function getSessionId() {
|
|
154
|
+
try {
|
|
155
|
+
if (!nextHeaders) {
|
|
156
|
+
const mod = await import("next/headers");
|
|
157
|
+
nextHeaders = mod.headers;
|
|
158
|
+
}
|
|
159
|
+
return (await nextHeaders()).get("x-dev-sid");
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function registerDevPanel() {
|
|
165
|
+
if (process.env.NEXT_RUNTIME !== "nodejs") return;
|
|
166
|
+
const { devLogStore: devLogStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
167
|
+
const { redactEntry: redactEntry2 } = await Promise.resolve().then(() => (init_redact(), redact_exports));
|
|
168
|
+
const originalFetch = globalThis.fetch;
|
|
169
|
+
globalThis.fetch = async function patchedFetch(input, init) {
|
|
170
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
171
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
172
|
+
const ts = Date.now();
|
|
173
|
+
const id = `${ts}-${Math.random().toString(36).slice(2, 8)}`;
|
|
174
|
+
const requestHeaders = headersToObject(init?.headers);
|
|
175
|
+
const requestBody = extractRequestBody(init);
|
|
176
|
+
const sessionId = await getSessionId();
|
|
177
|
+
const start = performance.now();
|
|
178
|
+
try {
|
|
179
|
+
const response = await originalFetch(input, init);
|
|
180
|
+
const duration = Math.round(performance.now() - start);
|
|
181
|
+
const responseHeaders = {};
|
|
182
|
+
response.headers.forEach((v, k) => {
|
|
183
|
+
responseHeaders[k] = v;
|
|
184
|
+
});
|
|
185
|
+
response.clone().text().then(
|
|
186
|
+
(text) => devLogStore2.push(redactEntry2({
|
|
187
|
+
id,
|
|
188
|
+
url,
|
|
189
|
+
method,
|
|
190
|
+
ts,
|
|
191
|
+
duration,
|
|
192
|
+
error: void 0,
|
|
193
|
+
status: response.status,
|
|
194
|
+
statusText: response.statusText,
|
|
195
|
+
requestHeaders,
|
|
196
|
+
responseHeaders,
|
|
197
|
+
requestBody,
|
|
198
|
+
responseBody: text.slice(0, BODY_LIMIT),
|
|
199
|
+
sessionId
|
|
200
|
+
})),
|
|
201
|
+
() => devLogStore2.push(redactEntry2({
|
|
202
|
+
id,
|
|
203
|
+
url,
|
|
204
|
+
method,
|
|
205
|
+
ts,
|
|
206
|
+
duration,
|
|
207
|
+
error: void 0,
|
|
208
|
+
status: response.status,
|
|
209
|
+
statusText: response.statusText,
|
|
210
|
+
requestHeaders,
|
|
211
|
+
responseHeaders,
|
|
212
|
+
requestBody,
|
|
213
|
+
responseBody: null,
|
|
214
|
+
sessionId
|
|
215
|
+
}))
|
|
216
|
+
);
|
|
217
|
+
return response;
|
|
218
|
+
} catch (err) {
|
|
219
|
+
const duration = Math.round(performance.now() - start);
|
|
220
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
221
|
+
devLogStore2.push(redactEntry2({
|
|
222
|
+
id,
|
|
223
|
+
url,
|
|
224
|
+
method,
|
|
225
|
+
ts,
|
|
226
|
+
duration,
|
|
227
|
+
error,
|
|
228
|
+
status: null,
|
|
229
|
+
statusText: null,
|
|
230
|
+
requestHeaders,
|
|
231
|
+
responseHeaders: {},
|
|
232
|
+
requestBody,
|
|
233
|
+
responseBody: null,
|
|
234
|
+
sessionId
|
|
235
|
+
}));
|
|
236
|
+
throw err;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
241
|
+
0 && (module.exports = {
|
|
242
|
+
register,
|
|
243
|
+
registerDevPanel
|
|
244
|
+
});
|
package/dist/patch.mjs
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/store.ts
|
|
12
|
+
var store_exports = {};
|
|
13
|
+
__export(store_exports, {
|
|
14
|
+
devLogStore: () => devLogStore
|
|
15
|
+
});
|
|
16
|
+
function createStore() {
|
|
17
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
18
|
+
const buffer = [];
|
|
19
|
+
return {
|
|
20
|
+
push(entry) {
|
|
21
|
+
buffer.push(entry);
|
|
22
|
+
if (buffer.length > BUFFER_SIZE) buffer.shift();
|
|
23
|
+
subscribers.forEach((fn) => fn(entry));
|
|
24
|
+
},
|
|
25
|
+
subscribe(fn) {
|
|
26
|
+
subscribers.add(fn);
|
|
27
|
+
return () => subscribers.delete(fn);
|
|
28
|
+
},
|
|
29
|
+
getBuffer() {
|
|
30
|
+
return buffer.slice();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var BUFFER_SIZE, devLogStore;
|
|
35
|
+
var init_store = __esm({
|
|
36
|
+
"src/store.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
BUFFER_SIZE = 100;
|
|
39
|
+
devLogStore = globalThis.__devLogStore ?? (globalThis.__devLogStore = createStore());
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// src/redact.ts
|
|
44
|
+
var redact_exports = {};
|
|
45
|
+
__export(redact_exports, {
|
|
46
|
+
redactConfig: () => redactConfig,
|
|
47
|
+
redactEntry: () => redactEntry
|
|
48
|
+
});
|
|
49
|
+
function redactUrl(url, params) {
|
|
50
|
+
try {
|
|
51
|
+
const u = new URL(url);
|
|
52
|
+
for (const key of params) {
|
|
53
|
+
if (u.searchParams.has(key)) u.searchParams.set(key, REDACTED);
|
|
54
|
+
}
|
|
55
|
+
return u.toString();
|
|
56
|
+
} catch {
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function redactHeaders(headers, names) {
|
|
61
|
+
const lower = new Set(names.map((n) => n.toLowerCase()));
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
64
|
+
out[k] = lower.has(k.toLowerCase()) ? REDACTED : v;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function redactBody(body, keys) {
|
|
69
|
+
if (!body) return body;
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(body);
|
|
72
|
+
for (const key of keys) {
|
|
73
|
+
if (key in parsed) parsed[key] = REDACTED;
|
|
74
|
+
}
|
|
75
|
+
return JSON.stringify(parsed, null, 2);
|
|
76
|
+
} catch {
|
|
77
|
+
return body;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function redactEntry(entry) {
|
|
81
|
+
return {
|
|
82
|
+
...entry,
|
|
83
|
+
url: redactUrl(entry.url, redactConfig.urlParams),
|
|
84
|
+
requestHeaders: redactHeaders(entry.requestHeaders, redactConfig.headers),
|
|
85
|
+
responseHeaders: redactHeaders(entry.responseHeaders, redactConfig.headers),
|
|
86
|
+
requestBody: redactBody(entry.requestBody, redactConfig.bodyKeys),
|
|
87
|
+
responseBody: redactBody(entry.responseBody, redactConfig.bodyKeys)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
var redactConfig, REDACTED;
|
|
91
|
+
var init_redact = __esm({
|
|
92
|
+
"src/redact.ts"() {
|
|
93
|
+
"use strict";
|
|
94
|
+
redactConfig = {
|
|
95
|
+
urlParams: ["api_key", "apikey", "secret", "token", "access_token", "password", "key"],
|
|
96
|
+
headers: ["authorization", "x-api-key", "x-secret", "x-auth-token"],
|
|
97
|
+
bodyKeys: ["password", "secret", "token", "api_key", "apiKey", "accessToken", "access_token"]
|
|
98
|
+
};
|
|
99
|
+
REDACTED = "[REDACTED]";
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// src/patch.ts
|
|
104
|
+
var BODY_LIMIT = 5e4;
|
|
105
|
+
function headersToObject(headers) {
|
|
106
|
+
if (!headers) return {};
|
|
107
|
+
if (headers instanceof Headers) {
|
|
108
|
+
const obj = {};
|
|
109
|
+
headers.forEach((v, k) => {
|
|
110
|
+
obj[k] = v;
|
|
111
|
+
});
|
|
112
|
+
return obj;
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
115
|
+
return headers;
|
|
116
|
+
}
|
|
117
|
+
function extractRequestBody(init) {
|
|
118
|
+
const body = init?.body;
|
|
119
|
+
if (body == null) return null;
|
|
120
|
+
if (typeof body === "string") return body.slice(0, BODY_LIMIT);
|
|
121
|
+
if (body instanceof URLSearchParams) return body.toString().slice(0, BODY_LIMIT);
|
|
122
|
+
return "[binary]";
|
|
123
|
+
}
|
|
124
|
+
var nextHeaders = null;
|
|
125
|
+
async function getSessionId() {
|
|
126
|
+
try {
|
|
127
|
+
if (!nextHeaders) {
|
|
128
|
+
const mod = await import("next/headers");
|
|
129
|
+
nextHeaders = mod.headers;
|
|
130
|
+
}
|
|
131
|
+
return (await nextHeaders()).get("x-dev-sid");
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function registerDevPanel() {
|
|
137
|
+
if (process.env.NEXT_RUNTIME !== "nodejs") return;
|
|
138
|
+
const { devLogStore: devLogStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
139
|
+
const { redactEntry: redactEntry2 } = await Promise.resolve().then(() => (init_redact(), redact_exports));
|
|
140
|
+
const originalFetch = globalThis.fetch;
|
|
141
|
+
globalThis.fetch = async function patchedFetch(input, init) {
|
|
142
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
143
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
144
|
+
const ts = Date.now();
|
|
145
|
+
const id = `${ts}-${Math.random().toString(36).slice(2, 8)}`;
|
|
146
|
+
const requestHeaders = headersToObject(init?.headers);
|
|
147
|
+
const requestBody = extractRequestBody(init);
|
|
148
|
+
const sessionId = await getSessionId();
|
|
149
|
+
const start = performance.now();
|
|
150
|
+
try {
|
|
151
|
+
const response = await originalFetch(input, init);
|
|
152
|
+
const duration = Math.round(performance.now() - start);
|
|
153
|
+
const responseHeaders = {};
|
|
154
|
+
response.headers.forEach((v, k) => {
|
|
155
|
+
responseHeaders[k] = v;
|
|
156
|
+
});
|
|
157
|
+
response.clone().text().then(
|
|
158
|
+
(text) => devLogStore2.push(redactEntry2({
|
|
159
|
+
id,
|
|
160
|
+
url,
|
|
161
|
+
method,
|
|
162
|
+
ts,
|
|
163
|
+
duration,
|
|
164
|
+
error: void 0,
|
|
165
|
+
status: response.status,
|
|
166
|
+
statusText: response.statusText,
|
|
167
|
+
requestHeaders,
|
|
168
|
+
responseHeaders,
|
|
169
|
+
requestBody,
|
|
170
|
+
responseBody: text.slice(0, BODY_LIMIT),
|
|
171
|
+
sessionId
|
|
172
|
+
})),
|
|
173
|
+
() => devLogStore2.push(redactEntry2({
|
|
174
|
+
id,
|
|
175
|
+
url,
|
|
176
|
+
method,
|
|
177
|
+
ts,
|
|
178
|
+
duration,
|
|
179
|
+
error: void 0,
|
|
180
|
+
status: response.status,
|
|
181
|
+
statusText: response.statusText,
|
|
182
|
+
requestHeaders,
|
|
183
|
+
responseHeaders,
|
|
184
|
+
requestBody,
|
|
185
|
+
responseBody: null,
|
|
186
|
+
sessionId
|
|
187
|
+
}))
|
|
188
|
+
);
|
|
189
|
+
return response;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
const duration = Math.round(performance.now() - start);
|
|
192
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
193
|
+
devLogStore2.push(redactEntry2({
|
|
194
|
+
id,
|
|
195
|
+
url,
|
|
196
|
+
method,
|
|
197
|
+
ts,
|
|
198
|
+
duration,
|
|
199
|
+
error,
|
|
200
|
+
status: null,
|
|
201
|
+
statusText: null,
|
|
202
|
+
requestHeaders,
|
|
203
|
+
responseHeaders: {},
|
|
204
|
+
requestBody,
|
|
205
|
+
responseBody: null,
|
|
206
|
+
sessionId
|
|
207
|
+
}));
|
|
208
|
+
throw err;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
registerDevPanel as register,
|
|
214
|
+
registerDevPanel
|
|
215
|
+
};
|
package/dist/route.d.mts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare const dynamic = "force-dynamic";
|
|
2
|
+
type GuardFn = (request: Request) => Response | null | undefined | void | Promise<Response | null | undefined | void>;
|
|
3
|
+
/**
|
|
4
|
+
* Returns a Next.js Route Handler GET function for the SSE stream.
|
|
5
|
+
* Use the guard option to add authentication or any other access control:
|
|
6
|
+
*
|
|
7
|
+
* export const dynamic = "force-dynamic"
|
|
8
|
+
* export const GET = createDevPanelRoute({
|
|
9
|
+
* guard: (request) => {
|
|
10
|
+
* const token = request.headers.get("authorization")
|
|
11
|
+
* if (!isValidToken(token)) return new Response("Forbidden", { status: 403 })
|
|
12
|
+
* },
|
|
13
|
+
* })
|
|
14
|
+
*
|
|
15
|
+
* For simple use with no access control:
|
|
16
|
+
* export { dynamic, GET } from "@/server-network-panel/route"
|
|
17
|
+
*/
|
|
18
|
+
declare function createDevPanelRoute(options?: {
|
|
19
|
+
guard?: GuardFn;
|
|
20
|
+
}): (request: Request) => Promise<Response>;
|
|
21
|
+
declare const GET: (request: Request) => Promise<Response>;
|
|
22
|
+
|
|
23
|
+
export { GET, createDevPanelRoute, dynamic };
|