@qzsy/vinext 0.1.80 → 0.1.82
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/index.js +3 -52
- package/dist/server/app-rsc-handler.js +1 -1
- package/dist/server/app-server-action-execution.js +12 -0
- package/dist/server/dev-response-headers.d.ts +19 -0
- package/dist/server/dev-response-headers.js +78 -0
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/request-log.d.ts +5 -14
- package/dist/server/request-log.js +7 -1
- package/dist/server/server-action-logger.d.ts +39 -0
- package/dist/server/server-action-logger.js +104 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { normalizePathSeparators, stripJsExtension, stripViteModuleQuery } from
|
|
|
5
5
|
import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts, normalizeViteResolveExtensions } from "./routing/file-matcher.js";
|
|
6
6
|
import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
|
|
7
7
|
import { VINEXT_MW_CTX_HEADER } from "./utils/protocol-headers.js";
|
|
8
|
-
import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS
|
|
8
|
+
import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS } from "./server/headers.js";
|
|
9
9
|
import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
|
|
10
10
|
import { matchesRewriteSource, proxyExternalRequest } from "./config/config-matchers.js";
|
|
11
11
|
import { isOpenRedirectShaped } from "./server/open-redirect.js";
|
|
@@ -16,7 +16,6 @@ import { generateClientEntry } from "./entries/pages-client-entry.js";
|
|
|
16
16
|
import { appRouteGraph, appRouter, invalidateAppRouteCache, matchAppRoute } from "./routing/app-router.js";
|
|
17
17
|
import { findInstrumentationClientFile, findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
|
|
18
18
|
import { isUnknownRecord } from "./utils/record.js";
|
|
19
|
-
import { logRequest, now } from "./server/request-log.js";
|
|
20
19
|
import { resolvePagesI18nRequest } from "./server/pages-i18n.js";
|
|
21
20
|
import { isNextDataPathname, parseNextDataPathname } from "./server/pages-data-route.js";
|
|
22
21
|
import { createSSRHandler } from "./server/dev-server.js";
|
|
@@ -40,6 +39,7 @@ import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, createGoogleFontsP
|
|
|
40
39
|
import { getDepOptimizeNodeEnvOptions, getViteMajorVersion, serializeViteDefine } from "./utils/vite-version.js";
|
|
41
40
|
import { createRscCompatibilityId, findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
|
|
42
41
|
import { mergeServerExternalPackages } from "./config/server-external-packages.js";
|
|
42
|
+
import { installAppRouterDevRequestLogging } from "./server/dev-response-headers.js";
|
|
43
43
|
import { precompressAssets } from "./build/precompress.js";
|
|
44
44
|
import { ensureAssetsIgnore } from "./build/assets-ignore.js";
|
|
45
45
|
import { emitNextClientRuntimeManifests } from "./build/next-client-runtime-manifests.js";
|
|
@@ -1707,56 +1707,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
1707
1707
|
if (instrumentationPath && !hasAppDir) runInstrumentation(getPagesRunner(), instrumentationPath).catch((err) => {
|
|
1708
1708
|
console.error("[vinext] Instrumentation error:", err);
|
|
1709
1709
|
});
|
|
1710
|
-
if (hasAppDir) server.middlewares
|
|
1711
|
-
const url = req.url ?? "/";
|
|
1712
|
-
const [pathname] = url.split("?");
|
|
1713
|
-
if (url.startsWith("/@") || url.startsWith("/__vite") || url.startsWith("/node_modules") || url.includes(".") && !pathname.endsWith(".html") && !pathname.endsWith(".rsc")) return next();
|
|
1714
|
-
const _reqStart = now();
|
|
1715
|
-
let _compileMs;
|
|
1716
|
-
let _renderMs;
|
|
1717
|
-
function _parseTiming(raw) {
|
|
1718
|
-
const [handlerStart, inHandlerCompileMs, renderMs] = String(raw).split(",").map((v) => Number(v));
|
|
1719
|
-
if (!Number.isNaN(handlerStart) && !Number.isNaN(inHandlerCompileMs) && inHandlerCompileMs !== -1) _compileMs = Math.max(0, Math.round(handlerStart - _reqStart)) + inHandlerCompileMs;
|
|
1720
|
-
if (!Number.isNaN(renderMs) && renderMs !== -1) _renderMs = renderMs;
|
|
1721
|
-
}
|
|
1722
|
-
const _origSetHeader = res.setHeader.bind(res);
|
|
1723
|
-
res.setHeader = function(name, value) {
|
|
1724
|
-
if (name.toLowerCase() === "x-vinext-timing") {
|
|
1725
|
-
_parseTiming(value);
|
|
1726
|
-
return res;
|
|
1727
|
-
}
|
|
1728
|
-
return _origSetHeader(name, value);
|
|
1729
|
-
};
|
|
1730
|
-
const _origWriteHead = res.writeHead.bind(res);
|
|
1731
|
-
res.writeHead = function(statusCode, ...args) {
|
|
1732
|
-
let headers;
|
|
1733
|
-
const [reasonOrHeaders, maybeHeaders] = args;
|
|
1734
|
-
if (typeof reasonOrHeaders === "string") headers = maybeHeaders;
|
|
1735
|
-
else headers = reasonOrHeaders;
|
|
1736
|
-
if (headers && typeof headers === "object" && !Array.isArray(headers)) {
|
|
1737
|
-
const timingKey = Object.keys(headers).find((k) => k.toLowerCase() === VINEXT_TIMING_HEADER);
|
|
1738
|
-
if (timingKey) {
|
|
1739
|
-
_parseTiming(headers[timingKey]);
|
|
1740
|
-
delete headers[timingKey];
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
return _origWriteHead(statusCode, ...args);
|
|
1744
|
-
};
|
|
1745
|
-
res.on("finish", () => {
|
|
1746
|
-
const logUrl = url.replace(/\.rsc(\?|$)/, "$1");
|
|
1747
|
-
const totalMs = now() - _reqStart;
|
|
1748
|
-
const resolvedRenderMs = _renderMs !== void 0 ? _renderMs : _compileMs !== void 0 ? Math.max(0, Math.round(totalMs - _compileMs)) : void 0;
|
|
1749
|
-
logRequest({
|
|
1750
|
-
method: req.method ?? "GET",
|
|
1751
|
-
url: logUrl,
|
|
1752
|
-
status: res.statusCode,
|
|
1753
|
-
totalMs,
|
|
1754
|
-
compileMs: _compileMs,
|
|
1755
|
-
renderMs: resolvedRenderMs
|
|
1756
|
-
});
|
|
1757
|
-
});
|
|
1758
|
-
next();
|
|
1759
|
-
});
|
|
1710
|
+
if (hasAppDir) installAppRouterDevRequestLogging(server.middlewares);
|
|
1760
1711
|
const handlePagesMiddleware = async (req, res, next) => {
|
|
1761
1712
|
try {
|
|
1762
1713
|
let url = req.url ?? "/";
|
|
@@ -19,11 +19,11 @@ import "./app-page-response.js";
|
|
|
19
19
|
import { parseNextHttpErrorDigest } from "./next-error-digest.js";
|
|
20
20
|
import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
21
21
|
import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
|
|
22
|
+
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
22
23
|
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
23
24
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
24
25
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
25
26
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
26
|
-
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
27
27
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
28
28
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
29
29
|
import { runWithPrerenderWorkUnit } from "./prerender-work-unit-setup.js";
|
|
@@ -8,6 +8,7 @@ import { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI } from "./app-rsc-rende
|
|
|
8
8
|
import { headersContextFromRequest, isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
|
|
9
9
|
import { getAndClearActionRevalidationKind } from "../shims/cache-request-state.js";
|
|
10
10
|
import { setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
|
|
11
|
+
import { applyServerActionLogHeader, createServerActionLogInfo, isDevServerActionLoggingEnabled } from "./server-action-logger.js";
|
|
11
12
|
import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
|
|
12
13
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
13
14
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
@@ -575,6 +576,9 @@ async function handleServerActionRscRequest(options) {
|
|
|
575
576
|
let actionThrew = false;
|
|
576
577
|
const actionWasForwarded = Boolean(options.request.headers.get(ACTION_FORWARDED_HEADER));
|
|
577
578
|
const rootParamsUsage = createRootParamsUsageController();
|
|
579
|
+
const shouldLogAction = isDevServerActionLoggingEnabled();
|
|
580
|
+
const actionLogStart = shouldLogAction ? performance.now() : 0;
|
|
581
|
+
let actionLogInfo = null;
|
|
578
582
|
const previousHeadersPhase = options.setHeadersAccessPhase("action");
|
|
579
583
|
try {
|
|
580
584
|
try {
|
|
@@ -609,6 +613,11 @@ async function handleServerActionRscRequest(options) {
|
|
|
609
613
|
}
|
|
610
614
|
}
|
|
611
615
|
} finally {
|
|
616
|
+
if (shouldLogAction) actionLogInfo = createServerActionLogInfo({
|
|
617
|
+
actionId: options.actionId,
|
|
618
|
+
args,
|
|
619
|
+
durationMs: Math.round(performance.now() - actionLogStart)
|
|
620
|
+
});
|
|
612
621
|
options.setHeadersAccessPhase(previousHeadersPhase);
|
|
613
622
|
if (actionThrew && !actionWasForwarded) rootParamsUsage.transitionToRender();
|
|
614
623
|
}
|
|
@@ -630,6 +639,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
630
639
|
for (const cookie of actionPendingCookies) redirectHeaders.append("Set-Cookie", cookie);
|
|
631
640
|
if (actionDraftCookie) redirectHeaders.append("Set-Cookie", actionDraftCookie);
|
|
632
641
|
setActionRevalidatedHeader(redirectHeaders, actionRevalidationKind);
|
|
642
|
+
applyServerActionLogHeader(redirectHeaders, actionLogInfo);
|
|
633
643
|
const redirectTarget = resolveInternalActionRedirectTarget(actionRedirectUrl, options.request.url, options.basePath ?? "");
|
|
634
644
|
if (!redirectTarget) {
|
|
635
645
|
options.clearRequestContext();
|
|
@@ -728,6 +738,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
728
738
|
for (const cookie of actionPendingCookies) actionHeaders.append("Set-Cookie", cookie);
|
|
729
739
|
if (actionDraftCookie) actionHeaders.append("Set-Cookie", actionDraftCookie);
|
|
730
740
|
setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);
|
|
741
|
+
applyServerActionLogHeader(actionHeaders, actionLogInfo);
|
|
731
742
|
return createServerActionRscResponse(rscStream, {
|
|
732
743
|
status: options.middlewareStatus ?? actionStatus,
|
|
733
744
|
headers: actionHeaders
|
|
@@ -804,6 +815,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
804
815
|
mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);
|
|
805
816
|
applyRscCompatibilityIdHeader(actionHeaders);
|
|
806
817
|
setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);
|
|
818
|
+
applyServerActionLogHeader(actionHeaders, actionLogInfo);
|
|
807
819
|
const actionResponse = createServerActionRscResponse(rscStream, {
|
|
808
820
|
status: options.middlewareStatus ?? actionStatus,
|
|
809
821
|
headers: actionHeaders
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RequestLogOptions } from "./request-log.js";
|
|
2
|
+
import { ServerResponse } from "node:http";
|
|
3
|
+
|
|
4
|
+
//#region src/server/dev-response-headers.d.ts
|
|
5
|
+
type DevResponseMetrics = {
|
|
6
|
+
compileMs?: number;
|
|
7
|
+
renderMs?: number;
|
|
8
|
+
actionLogRaw?: string;
|
|
9
|
+
};
|
|
10
|
+
declare function parseVinextTimingHeader(raw: unknown, reqStart: number): Pick<DevResponseMetrics, "compileMs" | "renderMs">;
|
|
11
|
+
/** Intercept dev-only headers on a Node response and capture their payloads. */
|
|
12
|
+
declare function interceptDevResponseHeaders(res: ServerResponse, reqStart: number, metrics: DevResponseMetrics): void;
|
|
13
|
+
declare function flushDevRequestLogs(metrics: DevResponseMetrics, options: RequestLogOptions): void;
|
|
14
|
+
/** Install App Router request + server action logging on the Vite dev server. */
|
|
15
|
+
declare function installAppRouterDevRequestLogging(middlewares: {
|
|
16
|
+
use: (handler: (req: import("node:http").IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void) => void;
|
|
17
|
+
}): void;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { DevResponseMetrics, flushDevRequestLogs, installAppRouterDevRequestLogging, interceptDevResponseHeaders, parseVinextTimingHeader };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import "./headers.js";
|
|
2
|
+
import { parseServerActionLogHeader } from "./server-action-logger.js";
|
|
3
|
+
import { logRequest, logServerAction, now } from "./request-log.js";
|
|
4
|
+
//#region src/server/dev-response-headers.ts
|
|
5
|
+
function parseVinextTimingHeader(raw, reqStart) {
|
|
6
|
+
const [handlerStart, inHandlerCompileMs, renderMs] = String(raw).split(",").map((v) => Number(v));
|
|
7
|
+
const metrics = {};
|
|
8
|
+
if (!Number.isNaN(handlerStart) && !Number.isNaN(inHandlerCompileMs) && inHandlerCompileMs !== -1) metrics.compileMs = Math.max(0, Math.round(handlerStart - reqStart)) + inHandlerCompileMs;
|
|
9
|
+
if (!Number.isNaN(renderMs) && renderMs !== -1) metrics.renderMs = renderMs;
|
|
10
|
+
return metrics;
|
|
11
|
+
}
|
|
12
|
+
function consumeDevInternalHeader(name, value, reqStart, metrics) {
|
|
13
|
+
const lowerName = name.toLowerCase();
|
|
14
|
+
if (lowerName === "x-vinext-timing") {
|
|
15
|
+
Object.assign(metrics, parseVinextTimingHeader(value, reqStart));
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (lowerName === "x-vinext-action-log") {
|
|
19
|
+
metrics.actionLogRaw = String(value);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
function stripDevInternalHeadersFromObject(headers, reqStart, metrics) {
|
|
25
|
+
for (const key of Object.keys(headers)) if (consumeDevInternalHeader(key, headers[key], reqStart, metrics)) delete headers[key];
|
|
26
|
+
}
|
|
27
|
+
/** Intercept dev-only headers on a Node response and capture their payloads. */
|
|
28
|
+
function interceptDevResponseHeaders(res, reqStart, metrics) {
|
|
29
|
+
const origSetHeader = res.setHeader.bind(res);
|
|
30
|
+
res.setHeader = function(name, value) {
|
|
31
|
+
if (consumeDevInternalHeader(String(name), value, reqStart, metrics)) return res;
|
|
32
|
+
return origSetHeader(name, value);
|
|
33
|
+
};
|
|
34
|
+
const origWriteHead = res.writeHead.bind(res);
|
|
35
|
+
res.writeHead = function(statusCode, ...args) {
|
|
36
|
+
let headers;
|
|
37
|
+
const [reasonOrHeaders, maybeHeaders] = args;
|
|
38
|
+
if (typeof reasonOrHeaders === "string") headers = maybeHeaders;
|
|
39
|
+
else headers = reasonOrHeaders;
|
|
40
|
+
if (headers && typeof headers === "object" && !Array.isArray(headers)) stripDevInternalHeadersFromObject(headers, reqStart, metrics);
|
|
41
|
+
return origWriteHead(statusCode, ...args);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function flushDevRequestLogs(metrics, options) {
|
|
45
|
+
logRequest(options);
|
|
46
|
+
const actionLog = metrics.actionLogRaw ? parseServerActionLogHeader(metrics.actionLogRaw) : null;
|
|
47
|
+
if (actionLog) logServerAction(actionLog);
|
|
48
|
+
}
|
|
49
|
+
function shouldSkipDevRequestLogUrl(url) {
|
|
50
|
+
const [pathname] = url.split("?");
|
|
51
|
+
return url.startsWith("/@") || url.startsWith("/__vite") || url.startsWith("/node_modules") || url.includes(".") && !pathname.endsWith(".html") && !pathname.endsWith(".rsc");
|
|
52
|
+
}
|
|
53
|
+
/** Install App Router request + server action logging on the Vite dev server. */
|
|
54
|
+
function installAppRouterDevRequestLogging(middlewares) {
|
|
55
|
+
middlewares.use((req, res, next) => {
|
|
56
|
+
const url = req.url ?? "/";
|
|
57
|
+
if (shouldSkipDevRequestLogUrl(url)) return next();
|
|
58
|
+
const reqStart = now();
|
|
59
|
+
const metrics = {};
|
|
60
|
+
interceptDevResponseHeaders(res, reqStart, metrics);
|
|
61
|
+
res.on("finish", () => {
|
|
62
|
+
const logUrl = url.replace(/\.rsc(\?|$)/, "$1");
|
|
63
|
+
const totalMs = now() - reqStart;
|
|
64
|
+
const resolvedRenderMs = metrics.renderMs !== void 0 ? metrics.renderMs : metrics.compileMs !== void 0 ? Math.max(0, Math.round(totalMs - metrics.compileMs)) : void 0;
|
|
65
|
+
flushDevRequestLogs(metrics, {
|
|
66
|
+
method: req.method ?? "GET",
|
|
67
|
+
url: logUrl,
|
|
68
|
+
status: res.statusCode,
|
|
69
|
+
totalMs,
|
|
70
|
+
compileMs: metrics.compileMs,
|
|
71
|
+
renderMs: resolvedRenderMs
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
next();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { flushDevRequestLogs, installAppRouterDevRequestLogging, interceptDevResponseHeaders, parseVinextTimingHeader };
|
package/dist/server/headers.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ declare const NEXTJS_CACHE_HEADER = "x-nextjs-cache";
|
|
|
19
19
|
declare const VINEXT_STATIC_FILE_HEADER = "x-vinext-static-file";
|
|
20
20
|
/** Timing metrics: `handlerStart,compileMs,renderMs`. */
|
|
21
21
|
declare const VINEXT_TIMING_HEADER = "x-vinext-timing";
|
|
22
|
+
/** Dev-only server action log payload (JSON). Stripped before the response reaches the client. */
|
|
23
|
+
declare const VINEXT_ACTION_LOG_HEADER = "x-vinext-action-log";
|
|
22
24
|
/** Internal endpoint used to evaluate App Router generateStaticParams exports. */
|
|
23
25
|
declare const VINEXT_PRERENDER_STATIC_PARAMS_PATH = "/__vinext/prerender/static-params";
|
|
24
26
|
/** Internal endpoint used to evaluate Pages Router getStaticPaths exports. */
|
|
@@ -101,4 +103,4 @@ declare const INTERNAL_HEADERS: string[];
|
|
|
101
103
|
/** Vinext-only internal headers stripped alongside Next.js protocol internals. */
|
|
102
104
|
declare const VINEXT_INTERNAL_HEADERS: string[];
|
|
103
105
|
//#endregion
|
|
104
|
-
export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
|
|
106
|
+
export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_ACTION_LOG_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
|
package/dist/server/headers.js
CHANGED
|
@@ -18,6 +18,8 @@ const NEXTJS_CACHE_HEADER = "x-nextjs-cache";
|
|
|
18
18
|
const VINEXT_STATIC_FILE_HEADER = "x-vinext-static-file";
|
|
19
19
|
/** Timing metrics: `handlerStart,compileMs,renderMs`. */
|
|
20
20
|
const VINEXT_TIMING_HEADER = "x-vinext-timing";
|
|
21
|
+
/** Dev-only server action log payload (JSON). Stripped before the response reaches the client. */
|
|
22
|
+
const VINEXT_ACTION_LOG_HEADER = "x-vinext-action-log";
|
|
21
23
|
/** Internal endpoint used to evaluate App Router generateStaticParams exports. */
|
|
22
24
|
const VINEXT_PRERENDER_STATIC_PARAMS_PATH = "/__vinext/prerender/static-params";
|
|
23
25
|
/** Internal endpoint used to evaluate Pages Router getStaticPaths exports. */
|
|
@@ -122,4 +124,4 @@ const INTERNAL_HEADERS = [
|
|
|
122
124
|
/** Vinext-only internal headers stripped alongside Next.js protocol internals. */
|
|
123
125
|
const VINEXT_INTERNAL_HEADERS = [VINEXT_PRERENDER_ROUTE_PARAMS_HEADER];
|
|
124
126
|
//#endregion
|
|
125
|
-
export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
|
|
127
|
+
export { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, INTERNAL_HEADERS, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER, MIDDLEWARE_SET_COOKIE_HEADER, NEXTJS_ACTION_NOT_FOUND_HEADER, NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ACTION_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, RSC_ACTION_HEADER, RSC_HEADER, VINEXT_ACTION_LOG_HEADER, VINEXT_CACHE_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_PAGES_STATIC_PATHS_PATH, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_STATIC_PARAMS_PATH, VINEXT_REVALIDATE_HEADER, VINEXT_RSC_MARKER_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_STATIC_FILE_HEADER, VINEXT_TIMING_HEADER };
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
+
import { ServerActionLogInfo } from "./server-action-logger.js";
|
|
2
|
+
|
|
1
3
|
//#region src/server/request-log.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Request logging for the vinext dev server.
|
|
4
|
-
*
|
|
5
|
-
* Matches Next.js's request log format:
|
|
6
|
-
* GET /path 200 in 123ms (compile: 45ms, render: 78ms)
|
|
7
|
-
*
|
|
8
|
-
* Color coding matches Next.js:
|
|
9
|
-
* - 2xx: green
|
|
10
|
-
* - 3xx: cyan
|
|
11
|
-
* - 4xx: yellow
|
|
12
|
-
* - 5xx: red
|
|
13
|
-
* - Method: bold
|
|
14
|
-
*/
|
|
15
4
|
type RequestLogOptions = {
|
|
16
5
|
method: string;
|
|
17
6
|
url: string;
|
|
@@ -20,6 +9,8 @@ type RequestLogOptions = {
|
|
|
20
9
|
compileMs?: number; /** Time spent in React rendering / HTML streaming. */
|
|
21
10
|
renderMs?: number;
|
|
22
11
|
};
|
|
12
|
+
/** Print the nested server action log line under the request log. */
|
|
13
|
+
declare function logServerAction(info: ServerActionLogInfo): void;
|
|
23
14
|
/**
|
|
24
15
|
* Print a single request log line to stdout.
|
|
25
16
|
*/
|
|
@@ -36,4 +27,4 @@ declare function logRequest({
|
|
|
36
27
|
*/
|
|
37
28
|
declare function now(): number;
|
|
38
29
|
//#endregion
|
|
39
|
-
export { logRequest, now };
|
|
30
|
+
export { RequestLogOptions, logRequest, logServerAction, now };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatActionArgs } from "./server-action-logger.js";
|
|
1
2
|
//#region src/server/request-log.ts
|
|
2
3
|
/**
|
|
3
4
|
* Request logging for the vinext dev server.
|
|
@@ -31,6 +32,11 @@ function formatDuration(ms) {
|
|
|
31
32
|
if (ms >= 1e3) return `${(ms / 1e3).toFixed(1)}s`;
|
|
32
33
|
return `${Math.round(ms)}ms`;
|
|
33
34
|
}
|
|
35
|
+
/** Print the nested server action log line under the request log. */
|
|
36
|
+
function logServerAction(info) {
|
|
37
|
+
const argsStr = formatActionArgs(info.args);
|
|
38
|
+
process.stdout.write(` └─ ƒ ${info.functionName}(${argsStr}) in ${info.duration}ms ${pretty.dim(info.location)}\n`);
|
|
39
|
+
}
|
|
34
40
|
/**
|
|
35
41
|
* Print a single request log line to stdout.
|
|
36
42
|
*/
|
|
@@ -53,4 +59,4 @@ function now() {
|
|
|
53
59
|
return performance.now();
|
|
54
60
|
}
|
|
55
61
|
//#endregion
|
|
56
|
-
export { logRequest, now };
|
|
62
|
+
export { logRequest, logServerAction, now };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/server/server-action-logger.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Dev-only Server Action logging — metadata and wire-format helpers.
|
|
4
|
+
*
|
|
5
|
+
* Terminal output lives in `request-log.ts`. Dev middleware interception lives
|
|
6
|
+
* in `dev-response-headers.ts`.
|
|
7
|
+
*
|
|
8
|
+
* Ported from Next.js:
|
|
9
|
+
* - packages/next/src/server/dev/server-action-logger.ts
|
|
10
|
+
* - packages/next/src/server/dev/log-requests.ts
|
|
11
|
+
*
|
|
12
|
+
* https://github.com/vercel/next.js/pull/88277
|
|
13
|
+
*/
|
|
14
|
+
type ServerActionLogInfo = {
|
|
15
|
+
functionName: string;
|
|
16
|
+
args: unknown[];
|
|
17
|
+
location: string;
|
|
18
|
+
duration: number;
|
|
19
|
+
};
|
|
20
|
+
declare function isDevServerActionLoggingEnabled(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve display metadata from an `x-rsc-action` / `next-action` action id.
|
|
23
|
+
*
|
|
24
|
+
* Action ids encode module path and export name:
|
|
25
|
+
* `/app/actions/actions.ts#echoAction`
|
|
26
|
+
*/
|
|
27
|
+
declare function resolveServerActionLogMeta(actionId: string | null): Pick<ServerActionLogInfo, "functionName" | "location"> | null;
|
|
28
|
+
/** Format action arguments for the dev log line. */
|
|
29
|
+
declare function formatActionArgs(args: unknown[]): string;
|
|
30
|
+
declare function serializeServerActionLogHeader(info: ServerActionLogInfo): string;
|
|
31
|
+
declare function parseServerActionLogHeader(value: string): ServerActionLogInfo | null;
|
|
32
|
+
declare function applyServerActionLogHeader(headers: Headers, info: ServerActionLogInfo | null): void;
|
|
33
|
+
declare function createServerActionLogInfo(options: {
|
|
34
|
+
actionId: string | null;
|
|
35
|
+
args: readonly unknown[];
|
|
36
|
+
durationMs: number;
|
|
37
|
+
}): ServerActionLogInfo | null;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { ServerActionLogInfo, applyServerActionLogHeader, createServerActionLogInfo, formatActionArgs, isDevServerActionLoggingEnabled, parseServerActionLogHeader, resolveServerActionLogMeta, serializeServerActionLogHeader };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { VINEXT_ACTION_LOG_HEADER } from "./headers.js";
|
|
2
|
+
//#region src/server/server-action-logger.ts
|
|
3
|
+
/**
|
|
4
|
+
* Dev-only Server Action logging — metadata and wire-format helpers.
|
|
5
|
+
*
|
|
6
|
+
* Terminal output lives in `request-log.ts`. Dev middleware interception lives
|
|
7
|
+
* in `dev-response-headers.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Ported from Next.js:
|
|
10
|
+
* - packages/next/src/server/dev/server-action-logger.ts
|
|
11
|
+
* - packages/next/src/server/dev/log-requests.ts
|
|
12
|
+
*
|
|
13
|
+
* https://github.com/vercel/next.js/pull/88277
|
|
14
|
+
*/
|
|
15
|
+
const INLINE_ACTION_PREFIXES = ["$$RSC_SERVER_ACTION_", "$$hoist_"];
|
|
16
|
+
const USE_CACHE_ACTION_PREFIX = "$$RSC_SERVER_CACHE_";
|
|
17
|
+
function isDevServerActionLoggingEnabled() {
|
|
18
|
+
return process.env.NODE_ENV !== "production";
|
|
19
|
+
}
|
|
20
|
+
function isInlineActionExport(exportedName) {
|
|
21
|
+
return INLINE_ACTION_PREFIXES.some((prefix) => exportedName.startsWith(prefix));
|
|
22
|
+
}
|
|
23
|
+
function isUseCacheActionExport(exportedName) {
|
|
24
|
+
return exportedName.startsWith(USE_CACHE_ACTION_PREFIX);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve display metadata from an `x-rsc-action` / `next-action` action id.
|
|
28
|
+
*
|
|
29
|
+
* Action ids encode module path and export name:
|
|
30
|
+
* `/app/actions/actions.ts#echoAction`
|
|
31
|
+
*/
|
|
32
|
+
function resolveServerActionLogMeta(actionId) {
|
|
33
|
+
if (!actionId) return null;
|
|
34
|
+
const hashIndex = actionId.lastIndexOf("#");
|
|
35
|
+
if (hashIndex <= 0) return null;
|
|
36
|
+
const exportedName = actionId.slice(hashIndex + 1);
|
|
37
|
+
if (isUseCacheActionExport(exportedName)) return null;
|
|
38
|
+
const location = actionId.slice(0, hashIndex).replace(/\\/g, "/").replace(/^\//, "");
|
|
39
|
+
let functionName;
|
|
40
|
+
if (isInlineActionExport(exportedName)) functionName = "";
|
|
41
|
+
else if (exportedName === "default") functionName = "default";
|
|
42
|
+
else functionName = exportedName;
|
|
43
|
+
return {
|
|
44
|
+
functionName,
|
|
45
|
+
location
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function formatArg(arg, depth = 0) {
|
|
49
|
+
if (arg === null) return "null";
|
|
50
|
+
if (arg === void 0) return "undefined";
|
|
51
|
+
if (typeof arg === "string") return JSON.stringify(arg);
|
|
52
|
+
if (typeof arg === "number" || typeof arg === "boolean" || typeof arg === "bigint") return String(arg);
|
|
53
|
+
if (typeof arg === "symbol") return String(arg);
|
|
54
|
+
if (typeof arg === "function") return "[Function]";
|
|
55
|
+
if (depth >= 2) return "[Object]";
|
|
56
|
+
if (Array.isArray(arg)) {
|
|
57
|
+
const items = arg.slice(0, 3).map((item) => formatArg(item, depth + 1));
|
|
58
|
+
if (arg.length > 3) items.push("...");
|
|
59
|
+
return `[${items.join(",")}]`;
|
|
60
|
+
}
|
|
61
|
+
if (typeof arg === "object") try {
|
|
62
|
+
const formatted = Object.entries(arg).slice(0, 3).map(([key, value]) => `${JSON.stringify(key)}:${formatArg(value, depth + 1)}`);
|
|
63
|
+
if (Object.keys(arg).length > 3) formatted.push("...");
|
|
64
|
+
return `{${formatted.join(",")}}`;
|
|
65
|
+
} catch {
|
|
66
|
+
return "[Object]";
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return JSON.stringify(arg);
|
|
70
|
+
} catch {
|
|
71
|
+
return "[unserializable]";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Format action arguments for the dev log line. */
|
|
75
|
+
function formatActionArgs(args) {
|
|
76
|
+
return args.map((arg) => formatArg(arg)).join(", ");
|
|
77
|
+
}
|
|
78
|
+
function serializeServerActionLogHeader(info) {
|
|
79
|
+
return JSON.stringify(info);
|
|
80
|
+
}
|
|
81
|
+
function parseServerActionLogHeader(value) {
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(value);
|
|
84
|
+
if (typeof parsed.functionName === "string" && Array.isArray(parsed.args) && typeof parsed.location === "string" && typeof parsed.duration === "number") return parsed;
|
|
85
|
+
} catch {}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function applyServerActionLogHeader(headers, info) {
|
|
89
|
+
if (!info) return;
|
|
90
|
+
headers.set(VINEXT_ACTION_LOG_HEADER, serializeServerActionLogHeader(info));
|
|
91
|
+
}
|
|
92
|
+
function createServerActionLogInfo(options) {
|
|
93
|
+
if (!isDevServerActionLoggingEnabled()) return null;
|
|
94
|
+
const meta = resolveServerActionLogMeta(options.actionId);
|
|
95
|
+
if (!meta) return null;
|
|
96
|
+
const args = Array.isArray(options.args) ? options.args : [options.args];
|
|
97
|
+
return {
|
|
98
|
+
...meta,
|
|
99
|
+
args: [...args],
|
|
100
|
+
duration: options.durationMs
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { applyServerActionLogHeader, createServerActionLogInfo, formatActionArgs, isDevServerActionLoggingEnabled, parseServerActionLogHeader, resolveServerActionLogMeta, serializeServerActionLogHeader };
|