@inertiajs/core 3.0.2 → 3.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/dist/index.js +158 -91
- package/dist/index.js.map +3 -3
- package/dist/server.js +2 -2
- package/dist/server.js.map +2 -2
- package/package.json +4 -4
- package/types/index.d.ts +2 -1
- package/types/initialVisit.d.ts +1 -0
- package/types/layout.d.ts +1 -0
- package/types/partialReload.d.ts +6 -0
- package/types/response.d.ts +1 -0
- package/types/server.d.ts +1 -0
- package/types/types.d.ts +10 -4
package/dist/server.js
CHANGED
|
@@ -239,7 +239,7 @@ var readableToString = (readable) => new Promise((resolve, reject) => {
|
|
|
239
239
|
});
|
|
240
240
|
var server_default = (render, options) => {
|
|
241
241
|
const opts = typeof options === "number" ? { port: options } : options;
|
|
242
|
-
const { port = 13714, cluster: useCluster = false, formatErrors = true } = opts ?? {};
|
|
242
|
+
const { port = 13714, host = "0.0.0.0", cluster: useCluster = false, formatErrors = true } = opts ?? {};
|
|
243
243
|
const log = (message) => {
|
|
244
244
|
console.log(
|
|
245
245
|
useCluster && !cluster.isPrimary ? `[${cluster.worker?.id ?? "N/A"} / ${cluster.worker?.process?.pid ?? "N/A"}] ${message}` : message
|
|
@@ -303,7 +303,7 @@ var server_default = (render, options) => {
|
|
|
303
303
|
response.write(JSON.stringify(result));
|
|
304
304
|
}
|
|
305
305
|
response.end();
|
|
306
|
-
}).listen(port, () => log("Inertia SSR server started."));
|
|
306
|
+
}).listen({ port, host }, () => log("Inertia SSR server started."));
|
|
307
307
|
log(`Starting SSR server on port ${port}...`);
|
|
308
308
|
return render;
|
|
309
309
|
};
|
package/dist/server.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/server.ts", "../src/ssrErrors.ts"],
|
|
4
|
-
"sourcesContent": ["import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping'\nimport { createServer, IncomingMessage, ServerResponse } from 'http'\nimport cluster from 'node:cluster'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { availableParallelism } from 'node:os'\nimport path from 'node:path'\nimport * as process from 'process'\nimport { classifySSRError, formatConsoleError, setSourceMapResolver } from './ssrErrors'\nimport { InertiaAppResponse, Page } from './types'\n\n// Cache parsed sourcemaps for performance\nconst sourceMaps = new Map<string, TraceMap>()\n\nsetSourceMapResolver((file: string, line: number, column: number) => {\n // Only resolve for bundled SSR files\n if (!file.includes('/ssr/') || !file.endsWith('.js')) {\n return null\n }\n\n const mapFile = file + '.map'\n\n if (!existsSync(mapFile)) {\n return null\n }\n\n let traceMap = sourceMaps.get(mapFile)\n\n if (!traceMap) {\n try {\n const mapContent = readFileSync(mapFile, 'utf-8')\n traceMap = new TraceMap(mapContent)\n sourceMaps.set(mapFile, traceMap)\n } catch {\n return null\n }\n }\n\n const original = originalPositionFor(traceMap, { line, column })\n\n if (original.source) {\n // Resolve the source path relative to the sourcemap location\n const mapDir = path.dirname(mapFile)\n const resolvedPath = path.resolve(mapDir, original.source)\n\n return {\n file: resolvedPath,\n line: original.line ?? line,\n column: original.column ?? column,\n }\n }\n\n return null\n})\n\ntype AppCallback = (page: Page) => InertiaAppResponse\ntype RouteHandler = (request: IncomingMessage, response: ServerResponse) => Promise<unknown>\ntype ServerOptions = {\n port?: number\n cluster?: boolean\n formatErrors?: boolean\n}\ntype Port = number\n\nconst readableToString: (readable: IncomingMessage) => Promise<string> = (readable) =>\n new Promise((resolve, reject) => {\n let data = ''\n readable.on('data', (chunk) => (data += chunk))\n readable.on('end', () => resolve(data))\n readable.on('error', (err) => reject(err))\n })\n\nexport default (render: AppCallback, options?: Port | ServerOptions): AppCallback => {\n const opts = typeof options === 'number' ? { port: options } : options\n const { port = 13714, cluster: useCluster = false, formatErrors = true } = opts ?? {}\n\n const log = (message: string) => {\n console.log(\n useCluster && !cluster.isPrimary\n ? `[${cluster.worker?.id ?? 'N/A'} / ${cluster.worker?.process?.pid ?? 'N/A'}] ${message}`\n : message,\n )\n }\n\n if (useCluster && cluster.isPrimary) {\n log('Primary Inertia SSR server process started...')\n\n for (let i = 0; i < availableParallelism(); i++) {\n cluster.fork()\n }\n\n cluster.on('message', (_worker, message) => {\n if (message === 'shutdown') {\n for (const id in cluster.workers) {\n cluster.workers[id]?.kill()\n }\n\n process.exit()\n }\n })\n\n return render\n }\n\n const handleRender = async (request: IncomingMessage, response: ServerResponse) => {\n const page: Page = JSON.parse(await readableToString(request))\n\n // Suppress framework warnings during render (they clutter the output)\n const originalWarn = console.warn\n\n if (formatErrors) {\n console.warn = () => {}\n }\n\n try {\n const result = await render(page)\n\n response.writeHead(200, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(result))\n } catch (e) {\n const error = e as Error\n\n if (!formatErrors) {\n throw error\n }\n\n const classified = classifySSRError(error, page.component, page.url)\n console.error(formatConsoleError(classified))\n\n response.writeHead(500, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(classified))\n } finally {\n console.warn = originalWarn\n }\n }\n\n const routes: Record<string, RouteHandler> = {\n '/health': async () => ({ status: 'OK', timestamp: Date.now() }),\n '/shutdown': async () => {\n if (cluster.isWorker) {\n process.send?.('shutdown')\n }\n\n process.exit()\n },\n '/render': handleRender,\n '/404': async () => ({ status: 'NOT_FOUND', timestamp: Date.now() }),\n }\n\n createServer(async (request, response) => {\n const dispatchRoute = routes[request.url as string] ?? routes['/404']\n const result = await dispatchRoute(request, response)\n\n if (!response.headersSent) {\n response.writeHead(200, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(result))\n }\n\n response.end()\n }).listen(port, () => log('Inertia SSR server started.'))\n\n log(`Starting SSR server on port ${port}...`)\n\n // Return the render callback so it can be exported for Vite SSR dev mode\n return render\n}\n", "/**\n * SSR Error Classification\n *\n * This module detects common SSR errors and provides helpful hints\n * to developers on how to fix them. The most common issue is using\n * browser-specific APIs (like window, document) that don't exist\n * in the Node.js server environment.\n */\n\nexport type SSRErrorType = 'browser-api' | 'component-resolution' | 'render' | 'unknown'\n\ntype SourceMapResolver = (\n file: string,\n line: number,\n column: number,\n) => { file: string; line: number; column: number } | null\n\nlet sourceMapResolver: SourceMapResolver | null = null\n\nexport function setSourceMapResolver(resolver: SourceMapResolver | null): void {\n sourceMapResolver = resolver\n}\n\nexport interface ClassifiedSSRError {\n error: string\n type: SSRErrorType\n component?: string\n url?: string\n browserApi?: string\n hint: string\n stack?: string\n sourceLocation?: string\n timestamp: string\n}\n\nconst BROWSER_APIS: Record<string, string> = {\n // Global objects\n window: 'The global window object',\n document: 'The DOM document object',\n navigator: 'The navigator object',\n location: 'The location object',\n history: 'The browser history API',\n screen: 'The screen object',\n localStorage: 'Browser local storage',\n sessionStorage: 'Browser session storage',\n\n // Viewport properties (accessed via window.X)\n innerWidth: 'Browser viewport width',\n innerHeight: 'Browser viewport height',\n outerWidth: 'Browser window width',\n outerHeight: 'Browser window height',\n scrollX: 'Horizontal scroll position',\n scrollY: 'Vertical scroll position',\n devicePixelRatio: 'The device pixel ratio',\n matchMedia: 'The matchMedia function',\n\n // Observers (commonly instantiated at module level)\n IntersectionObserver: 'The IntersectionObserver API',\n ResizeObserver: 'The ResizeObserver API',\n MutationObserver: 'The MutationObserver API',\n\n // Timing functions (commonly called at module level)\n requestAnimationFrame: 'The requestAnimationFrame function',\n requestIdleCallback: 'The requestIdleCallback function',\n\n // Constructors that might be used at module level\n Image: 'The Image constructor',\n Audio: 'The Audio constructor',\n Worker: 'The Worker constructor',\n BroadcastChannel: 'The BroadcastChannel constructor',\n\n // Network (older Node.js versions)\n fetch: 'The fetch API',\n XMLHttpRequest: 'The XMLHttpRequest API',\n}\n\nfunction detectBrowserApi(error: Error): string | null {\n const message = error.message.toLowerCase()\n\n for (const api of Object.keys(BROWSER_APIS)) {\n const patterns = [\n `${api.toLowerCase()} is not defined`,\n `'${api.toLowerCase()}' is not defined`,\n `\"${api.toLowerCase()}\" is not defined`,\n `cannot read properties of undefined (reading '${api.toLowerCase()}')`,\n `cannot read property '${api.toLowerCase()}'`,\n ]\n\n if (patterns.some((pattern) => message.includes(pattern))) {\n return api\n }\n }\n\n return null\n}\n\nfunction isComponentResolutionError(error: Error): boolean {\n const message = error.message.toLowerCase()\n\n return (\n message.includes('cannot find module') ||\n message.includes('failed to resolve') ||\n message.includes('module not found') ||\n message.includes('could not resolve')\n )\n}\n\nconst LIFECYCLE_HOOKS = 'onMounted/useEffect/onMount'\n\nfunction getBrowserApiHint(api: string): string {\n const apiDescription = BROWSER_APIS[api] || `The \"${api}\" object`\n\n if (['localStorage', 'sessionStorage'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Check \"typeof ${api} !== 'undefined'\" before using it, ` +\n `or move the code to a ${LIFECYCLE_HOOKS} lifecycle hook.`\n )\n }\n\n if (['window', 'document'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Wrap browser-specific code in a ${LIFECYCLE_HOOKS} lifecycle hook, ` +\n `or check \"typeof ${api} !== 'undefined'\" before using it.`\n )\n }\n\n if (['IntersectionObserver', 'ResizeObserver', 'MutationObserver'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Create observers inside a ${LIFECYCLE_HOOKS} lifecycle hook, not at the module level.`\n )\n }\n\n if (['fetch', 'XMLHttpRequest'].includes(api)) {\n return (\n `${apiDescription} may not be available in all Node.js versions. ` +\n `For SSR, ensure data fetching happens on the server (in your controller) ` +\n `and is passed as props, or use a ${LIFECYCLE_HOOKS} hook for client-side fetching.`\n )\n }\n\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Move this code to a ${LIFECYCLE_HOOKS} lifecycle hook, or guard it with ` +\n `\"typeof ${api} !== 'undefined'\".`\n )\n}\n\nfunction getComponentResolutionHint(component?: string): string {\n const componentPart = component ? ` \"${component}\"` : ''\n\n return (\n `Could not resolve component${componentPart}. ` +\n `Check that the file exists and the path is correct. ` +\n `Ensure the component name matches the file name exactly (case-sensitive).`\n )\n}\n\nfunction getRenderErrorHint(): string {\n return (\n 'An error occurred while rendering the component. ' +\n 'Check the component for browser-specific code that runs during initialization. ' +\n 'Move any code that accesses browser APIs to a lifecycle hook.'\n )\n}\n\nfunction extractSourceLocation(stack?: string): string | undefined {\n if (!stack) {\n return undefined\n }\n\n for (const line of stack.split('\\n')) {\n if (!line.includes('at ')) {\n continue\n }\n\n if (line.includes('node_modules') || line.includes('node:')) {\n continue\n }\n\n let match = line.match(/\\(([^)]+):(\\d+):(\\d+)\\)/)\n\n if (!match) {\n match = line.match(/at\\s+(?:file:\\/\\/)?(.+):(\\d+):(\\d+)\\s*$/)\n }\n\n if (match) {\n const file = match[1].replace(/^file:\\/\\//, '')\n const lineNum = parseInt(match[2], 10)\n const colNum = parseInt(match[3], 10)\n\n if (sourceMapResolver) {\n const resolved = sourceMapResolver(file, lineNum, colNum)\n\n if (resolved) {\n return `${resolved.file}:${resolved.line}:${resolved.column}`\n }\n }\n\n return `${file}:${lineNum}:${colNum}`\n }\n }\n\n return undefined\n}\n\nexport function classifySSRError(error: Error, component?: string, url?: string): ClassifiedSSRError {\n const timestamp = new Date().toISOString()\n const base = {\n error: error.message,\n component,\n url,\n stack: error.stack,\n sourceLocation: extractSourceLocation(error.stack),\n timestamp,\n }\n\n const browserApi = detectBrowserApi(error)\n\n if (browserApi) {\n return {\n ...base,\n type: 'browser-api',\n browserApi,\n hint: getBrowserApiHint(browserApi),\n }\n }\n\n if (isComponentResolutionError(error)) {\n return {\n ...base,\n type: 'component-resolution',\n hint: getComponentResolutionHint(component),\n }\n }\n\n return {\n ...base,\n type: 'render',\n hint: getRenderErrorHint(),\n }\n}\n\nconst colors = {\n reset: '\\x1b[0m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n bgRed: '\\x1b[41m',\n white: '\\x1b[37m',\n}\n\nfunction makeRelative(path: string, root?: string): string {\n const base = root ?? process.cwd()\n\n if (path.startsWith(base + '/')) {\n return path.slice(base.length + 1)\n }\n\n return path\n}\n\nexport function formatConsoleError(\n classified: ClassifiedSSRError,\n root?: string,\n formatErrors: boolean = true,\n suppressedWarnings: string[] = [],\n): string {\n if (!formatErrors) {\n const component = classified.component ? `[${classified.component}]` : ''\n return `SSR Error ${component}: ${classified.error}`\n }\n\n const componentPart = classified.component ? ` ${colors.cyan}${classified.component}${colors.reset}` : ''\n\n const lines = [\n '',\n ` ${colors.bgRed}${colors.white}${colors.bold} SSR ERROR ${colors.reset}${componentPart}`,\n '',\n ` ${classified.error}`,\n ]\n\n if (classified.sourceLocation) {\n const relativePath = makeRelative(classified.sourceLocation, root)\n lines.push(` ${colors.dim}Source: ${relativePath}${colors.reset}`)\n }\n\n if (classified.url) {\n lines.push(` ${colors.dim}URL: ${classified.url}${colors.reset}`)\n }\n\n lines.push('', ` ${colors.yellow}Hint${colors.reset} ${classified.hint}`, '')\n\n if (classified.stack) {\n lines.push(` ${colors.dim}${classified.stack.split('\\n').join('\\n ')}${colors.reset}`, '')\n }\n\n if (suppressedWarnings.length > 0) {\n lines.push(` ${colors.dim}Suppressed ${suppressedWarnings.length} framework warning(s).${colors.reset}`, '')\n }\n\n return lines.join('\\n')\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping'\nimport { createServer, IncomingMessage, ServerResponse } from 'http'\nimport cluster from 'node:cluster'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { availableParallelism } from 'node:os'\nimport path from 'node:path'\nimport * as process from 'process'\nimport { classifySSRError, formatConsoleError, setSourceMapResolver } from './ssrErrors'\nimport { InertiaAppResponse, Page } from './types'\n\n// Cache parsed sourcemaps for performance\nconst sourceMaps = new Map<string, TraceMap>()\n\nsetSourceMapResolver((file: string, line: number, column: number) => {\n // Only resolve for bundled SSR files\n if (!file.includes('/ssr/') || !file.endsWith('.js')) {\n return null\n }\n\n const mapFile = file + '.map'\n\n if (!existsSync(mapFile)) {\n return null\n }\n\n let traceMap = sourceMaps.get(mapFile)\n\n if (!traceMap) {\n try {\n const mapContent = readFileSync(mapFile, 'utf-8')\n traceMap = new TraceMap(mapContent)\n sourceMaps.set(mapFile, traceMap)\n } catch {\n return null\n }\n }\n\n const original = originalPositionFor(traceMap, { line, column })\n\n if (original.source) {\n // Resolve the source path relative to the sourcemap location\n const mapDir = path.dirname(mapFile)\n const resolvedPath = path.resolve(mapDir, original.source)\n\n return {\n file: resolvedPath,\n line: original.line ?? line,\n column: original.column ?? column,\n }\n }\n\n return null\n})\n\ntype AppCallback = (page: Page) => InertiaAppResponse\ntype RouteHandler = (request: IncomingMessage, response: ServerResponse) => Promise<unknown>\ntype ServerOptions = {\n port?: number\n host?: string\n cluster?: boolean\n formatErrors?: boolean\n}\ntype Port = number\n\nconst readableToString: (readable: IncomingMessage) => Promise<string> = (readable) =>\n new Promise((resolve, reject) => {\n let data = ''\n readable.on('data', (chunk) => (data += chunk))\n readable.on('end', () => resolve(data))\n readable.on('error', (err) => reject(err))\n })\n\nexport default (render: AppCallback, options?: Port | ServerOptions): AppCallback => {\n const opts = typeof options === 'number' ? { port: options } : options\n const { port = 13714, host = '0.0.0.0', cluster: useCluster = false, formatErrors = true } = opts ?? {}\n\n const log = (message: string) => {\n console.log(\n useCluster && !cluster.isPrimary\n ? `[${cluster.worker?.id ?? 'N/A'} / ${cluster.worker?.process?.pid ?? 'N/A'}] ${message}`\n : message,\n )\n }\n\n if (useCluster && cluster.isPrimary) {\n log('Primary Inertia SSR server process started...')\n\n for (let i = 0; i < availableParallelism(); i++) {\n cluster.fork()\n }\n\n cluster.on('message', (_worker, message) => {\n if (message === 'shutdown') {\n for (const id in cluster.workers) {\n cluster.workers[id]?.kill()\n }\n\n process.exit()\n }\n })\n\n return render\n }\n\n const handleRender = async (request: IncomingMessage, response: ServerResponse) => {\n const page: Page = JSON.parse(await readableToString(request))\n\n // Suppress framework warnings during render (they clutter the output)\n const originalWarn = console.warn\n\n if (formatErrors) {\n console.warn = () => {}\n }\n\n try {\n const result = await render(page)\n\n response.writeHead(200, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(result))\n } catch (e) {\n const error = e as Error\n\n if (!formatErrors) {\n throw error\n }\n\n const classified = classifySSRError(error, page.component, page.url)\n console.error(formatConsoleError(classified))\n\n response.writeHead(500, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(classified))\n } finally {\n console.warn = originalWarn\n }\n }\n\n const routes: Record<string, RouteHandler> = {\n '/health': async () => ({ status: 'OK', timestamp: Date.now() }),\n '/shutdown': async () => {\n if (cluster.isWorker) {\n process.send?.('shutdown')\n }\n\n process.exit()\n },\n '/render': handleRender,\n '/404': async () => ({ status: 'NOT_FOUND', timestamp: Date.now() }),\n }\n\n createServer(async (request, response) => {\n const dispatchRoute = routes[request.url as string] ?? routes['/404']\n const result = await dispatchRoute(request, response)\n\n if (!response.headersSent) {\n response.writeHead(200, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n response.write(JSON.stringify(result))\n }\n\n response.end()\n }).listen({ port, host }, () => log('Inertia SSR server started.'))\n\n log(`Starting SSR server on port ${port}...`)\n\n // Return the render callback so it can be exported for Vite SSR dev mode\n return render\n}\n", "/**\n * SSR Error Classification\n *\n * This module detects common SSR errors and provides helpful hints\n * to developers on how to fix them. The most common issue is using\n * browser-specific APIs (like window, document) that don't exist\n * in the Node.js server environment.\n */\n\nexport type SSRErrorType = 'browser-api' | 'component-resolution' | 'render' | 'unknown'\n\ntype SourceMapResolver = (\n file: string,\n line: number,\n column: number,\n) => { file: string; line: number; column: number } | null\n\nlet sourceMapResolver: SourceMapResolver | null = null\n\nexport function setSourceMapResolver(resolver: SourceMapResolver | null): void {\n sourceMapResolver = resolver\n}\n\nexport interface ClassifiedSSRError {\n error: string\n type: SSRErrorType\n component?: string\n url?: string\n browserApi?: string\n hint: string\n stack?: string\n sourceLocation?: string\n timestamp: string\n}\n\nconst BROWSER_APIS: Record<string, string> = {\n // Global objects\n window: 'The global window object',\n document: 'The DOM document object',\n navigator: 'The navigator object',\n location: 'The location object',\n history: 'The browser history API',\n screen: 'The screen object',\n localStorage: 'Browser local storage',\n sessionStorage: 'Browser session storage',\n\n // Viewport properties (accessed via window.X)\n innerWidth: 'Browser viewport width',\n innerHeight: 'Browser viewport height',\n outerWidth: 'Browser window width',\n outerHeight: 'Browser window height',\n scrollX: 'Horizontal scroll position',\n scrollY: 'Vertical scroll position',\n devicePixelRatio: 'The device pixel ratio',\n matchMedia: 'The matchMedia function',\n\n // Observers (commonly instantiated at module level)\n IntersectionObserver: 'The IntersectionObserver API',\n ResizeObserver: 'The ResizeObserver API',\n MutationObserver: 'The MutationObserver API',\n\n // Timing functions (commonly called at module level)\n requestAnimationFrame: 'The requestAnimationFrame function',\n requestIdleCallback: 'The requestIdleCallback function',\n\n // Constructors that might be used at module level\n Image: 'The Image constructor',\n Audio: 'The Audio constructor',\n Worker: 'The Worker constructor',\n BroadcastChannel: 'The BroadcastChannel constructor',\n\n // Network (older Node.js versions)\n fetch: 'The fetch API',\n XMLHttpRequest: 'The XMLHttpRequest API',\n}\n\nfunction detectBrowserApi(error: Error): string | null {\n const message = error.message.toLowerCase()\n\n for (const api of Object.keys(BROWSER_APIS)) {\n const patterns = [\n `${api.toLowerCase()} is not defined`,\n `'${api.toLowerCase()}' is not defined`,\n `\"${api.toLowerCase()}\" is not defined`,\n `cannot read properties of undefined (reading '${api.toLowerCase()}')`,\n `cannot read property '${api.toLowerCase()}'`,\n ]\n\n if (patterns.some((pattern) => message.includes(pattern))) {\n return api\n }\n }\n\n return null\n}\n\nfunction isComponentResolutionError(error: Error): boolean {\n const message = error.message.toLowerCase()\n\n return (\n message.includes('cannot find module') ||\n message.includes('failed to resolve') ||\n message.includes('module not found') ||\n message.includes('could not resolve')\n )\n}\n\nconst LIFECYCLE_HOOKS = 'onMounted/useEffect/onMount'\n\nfunction getBrowserApiHint(api: string): string {\n const apiDescription = BROWSER_APIS[api] || `The \"${api}\" object`\n\n if (['localStorage', 'sessionStorage'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Check \"typeof ${api} !== 'undefined'\" before using it, ` +\n `or move the code to a ${LIFECYCLE_HOOKS} lifecycle hook.`\n )\n }\n\n if (['window', 'document'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Wrap browser-specific code in a ${LIFECYCLE_HOOKS} lifecycle hook, ` +\n `or check \"typeof ${api} !== 'undefined'\" before using it.`\n )\n }\n\n if (['IntersectionObserver', 'ResizeObserver', 'MutationObserver'].includes(api)) {\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Create observers inside a ${LIFECYCLE_HOOKS} lifecycle hook, not at the module level.`\n )\n }\n\n if (['fetch', 'XMLHttpRequest'].includes(api)) {\n return (\n `${apiDescription} may not be available in all Node.js versions. ` +\n `For SSR, ensure data fetching happens on the server (in your controller) ` +\n `and is passed as props, or use a ${LIFECYCLE_HOOKS} hook for client-side fetching.`\n )\n }\n\n return (\n `${apiDescription} doesn't exist in Node.js. ` +\n `Move this code to a ${LIFECYCLE_HOOKS} lifecycle hook, or guard it with ` +\n `\"typeof ${api} !== 'undefined'\".`\n )\n}\n\nfunction getComponentResolutionHint(component?: string): string {\n const componentPart = component ? ` \"${component}\"` : ''\n\n return (\n `Could not resolve component${componentPart}. ` +\n `Check that the file exists and the path is correct. ` +\n `Ensure the component name matches the file name exactly (case-sensitive).`\n )\n}\n\nfunction getRenderErrorHint(): string {\n return (\n 'An error occurred while rendering the component. ' +\n 'Check the component for browser-specific code that runs during initialization. ' +\n 'Move any code that accesses browser APIs to a lifecycle hook.'\n )\n}\n\nfunction extractSourceLocation(stack?: string): string | undefined {\n if (!stack) {\n return undefined\n }\n\n for (const line of stack.split('\\n')) {\n if (!line.includes('at ')) {\n continue\n }\n\n if (line.includes('node_modules') || line.includes('node:')) {\n continue\n }\n\n let match = line.match(/\\(([^)]+):(\\d+):(\\d+)\\)/)\n\n if (!match) {\n match = line.match(/at\\s+(?:file:\\/\\/)?(.+):(\\d+):(\\d+)\\s*$/)\n }\n\n if (match) {\n const file = match[1].replace(/^file:\\/\\//, '')\n const lineNum = parseInt(match[2], 10)\n const colNum = parseInt(match[3], 10)\n\n if (sourceMapResolver) {\n const resolved = sourceMapResolver(file, lineNum, colNum)\n\n if (resolved) {\n return `${resolved.file}:${resolved.line}:${resolved.column}`\n }\n }\n\n return `${file}:${lineNum}:${colNum}`\n }\n }\n\n return undefined\n}\n\nexport function classifySSRError(error: Error, component?: string, url?: string): ClassifiedSSRError {\n const timestamp = new Date().toISOString()\n const base = {\n error: error.message,\n component,\n url,\n stack: error.stack,\n sourceLocation: extractSourceLocation(error.stack),\n timestamp,\n }\n\n const browserApi = detectBrowserApi(error)\n\n if (browserApi) {\n return {\n ...base,\n type: 'browser-api',\n browserApi,\n hint: getBrowserApiHint(browserApi),\n }\n }\n\n if (isComponentResolutionError(error)) {\n return {\n ...base,\n type: 'component-resolution',\n hint: getComponentResolutionHint(component),\n }\n }\n\n return {\n ...base,\n type: 'render',\n hint: getRenderErrorHint(),\n }\n}\n\nconst colors = {\n reset: '\\x1b[0m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n bgRed: '\\x1b[41m',\n white: '\\x1b[37m',\n}\n\nfunction makeRelative(path: string, root?: string): string {\n const base = root ?? process.cwd()\n\n if (path.startsWith(base + '/')) {\n return path.slice(base.length + 1)\n }\n\n return path\n}\n\nexport function formatConsoleError(\n classified: ClassifiedSSRError,\n root?: string,\n formatErrors: boolean = true,\n suppressedWarnings: string[] = [],\n): string {\n if (!formatErrors) {\n const component = classified.component ? `[${classified.component}]` : ''\n return `SSR Error ${component}: ${classified.error}`\n }\n\n const componentPart = classified.component ? ` ${colors.cyan}${classified.component}${colors.reset}` : ''\n\n const lines = [\n '',\n ` ${colors.bgRed}${colors.white}${colors.bold} SSR ERROR ${colors.reset}${componentPart}`,\n '',\n ` ${classified.error}`,\n ]\n\n if (classified.sourceLocation) {\n const relativePath = makeRelative(classified.sourceLocation, root)\n lines.push(` ${colors.dim}Source: ${relativePath}${colors.reset}`)\n }\n\n if (classified.url) {\n lines.push(` ${colors.dim}URL: ${classified.url}${colors.reset}`)\n }\n\n lines.push('', ` ${colors.yellow}Hint${colors.reset} ${classified.hint}`, '')\n\n if (classified.stack) {\n lines.push(` ${colors.dim}${classified.stack.split('\\n').join('\\n ')}${colors.reset}`, '')\n }\n\n if (suppressedWarnings.length > 0) {\n lines.push(` ${colors.dim}Suppressed ${suppressedWarnings.length} framework warning(s).${colors.reset}`, '')\n }\n\n return lines.join('\\n')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["process", "path"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inertiajs/core",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A framework for creating server-driven single page apps.",
|
|
6
6
|
"contributors": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"laravel-precognition": "^2.0.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"axios": "^1.
|
|
57
|
+
"axios": "^1.15.2"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"axios": {
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@types/node": "^24.10.13",
|
|
66
|
-
"axios": "^1.
|
|
66
|
+
"axios": "^1.15.2",
|
|
67
67
|
"es-check": "^9.6.4",
|
|
68
68
|
"esbuild": "^0.27.3",
|
|
69
69
|
"esbuild-node-externals": "^1.20.1",
|
|
70
70
|
"typescript": "^5.9.3",
|
|
71
|
-
"vitest": "^
|
|
71
|
+
"vitest": "^4.1.2"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "pnpm clean && ./build.js && tsc",
|
package/types/index.d.ts
CHANGED
|
@@ -11,8 +11,9 @@ export { default as createHeadManager } from './head';
|
|
|
11
11
|
export { http } from './http';
|
|
12
12
|
export { HttpCancelledError, HttpError, HttpNetworkError, HttpResponseError } from './httpErrors';
|
|
13
13
|
export { default as useInfiniteScroll } from './infiniteScroll';
|
|
14
|
-
export { createLayoutPropsStore, isPropsObject, normalizeLayouts, type LayoutCallbackReturn, type LayoutDefinition, type LayoutPropsStore, } from './layout';
|
|
14
|
+
export { createLayoutPropsStore, isPropsObject, isPropsObjectOrCallback, normalizeLayouts, type LayoutCallbackReturn, type LayoutDefinition, type LayoutPropsStore, } from './layout';
|
|
15
15
|
export { shouldIntercept, shouldNavigate } from './navigationEvents';
|
|
16
|
+
export { isPathOrSubPath, partialReloadRequestsProp, partialReloadRequestsSomeProps } from './partialReload';
|
|
16
17
|
export { progress, default as setupProgress } from './progress';
|
|
17
18
|
export { FormComponentResetSymbol, resetFormFields } from './resetFormFields';
|
|
18
19
|
export { buildSSRBody } from './ssrUtils';
|
package/types/initialVisit.d.ts
CHANGED
package/types/layout.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface LayoutPropsStore {
|
|
|
24
24
|
export declare function createLayoutPropsStore(): LayoutPropsStore;
|
|
25
25
|
type ComponentCheck<T> = (value: unknown) => value is T;
|
|
26
26
|
export declare function isPropsObject<T>(value: unknown, isComponent: ComponentCheck<T>): boolean;
|
|
27
|
+
export declare function isPropsObjectOrCallback<T>(value: unknown, isComponent: ComponentCheck<T>): boolean;
|
|
27
28
|
/**
|
|
28
29
|
* Normalizes layout definitions into a consistent structure.
|
|
29
30
|
*/
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ActiveVisit } from './types';
|
|
2
|
+
type VisitFilter = Pick<ActiveVisit, 'only' | 'except'>;
|
|
3
|
+
export declare const isPathOrSubPath: (path: string, candidate: string) => boolean;
|
|
4
|
+
export declare const partialReloadRequestsProp: (visit: VisitFilter, prop: string) => boolean;
|
|
5
|
+
export declare const partialReloadRequestsSomeProps: (visit: VisitFilter, props: string[]) => boolean;
|
|
6
|
+
export {};
|
package/types/response.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare class Response {
|
|
|
33
33
|
protected preserveOptimisticProps(pageResponse: Page): void;
|
|
34
34
|
protected preserveEqualProps(pageResponse: Page): void;
|
|
35
35
|
protected mergeProps(pageResponse: Page): void;
|
|
36
|
+
protected mergeRescuedProps(pageResponse: Page): string[];
|
|
36
37
|
/**
|
|
37
38
|
* By default, the Laravel adapter shares validation errors via Inertia::always(),
|
|
38
39
|
* so responses always include errors, even when empty. Components like
|
package/types/server.d.ts
CHANGED
package/types/types.d.ts
CHANGED
|
@@ -140,6 +140,7 @@ export interface Page<SharedProps extends PageProps = PageProps> {
|
|
|
140
140
|
encryptHistory?: boolean;
|
|
141
141
|
deferredProps?: Record<string, NonNullable<VisitOptions['only']>>;
|
|
142
142
|
initialDeferredProps?: Record<string, NonNullable<VisitOptions['only']>>;
|
|
143
|
+
rescuedProps: string[];
|
|
143
144
|
mergeProps?: string[];
|
|
144
145
|
prependProps?: string[];
|
|
145
146
|
deepMergeProps?: string[];
|
|
@@ -395,6 +396,7 @@ interface BaseCreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupR
|
|
|
395
396
|
layout?: (name: string, page: Page) => unknown;
|
|
396
397
|
setup: (options: TSetupOptions) => TSetupReturn;
|
|
397
398
|
title?: HeadManagerTitleCallback;
|
|
399
|
+
nonce?: string;
|
|
398
400
|
defaults?: FirstLevelOptional<InertiaAppConfig & TAdditionalInertiaAppConfig>;
|
|
399
401
|
/** HTTP client or options to use for requests. Defaults to XhrHttpClient. */
|
|
400
402
|
http?: HttpClient | HttpClientOptions;
|
|
@@ -425,6 +427,7 @@ export interface CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSet
|
|
|
425
427
|
setup?: (options: TSetupOptions) => TSetupReturn;
|
|
426
428
|
title?: HeadManagerTitleCallback;
|
|
427
429
|
progress?: ProgressOptions | false;
|
|
430
|
+
nonce?: string;
|
|
428
431
|
defaults?: FirstLevelOptional<InertiaAppConfig & TAdditionalInertiaAppConfig>;
|
|
429
432
|
/** HTTP client or options to use for requests. Defaults to XhrHttpClient. */
|
|
430
433
|
http?: HttpClient | HttpClientOptions;
|
|
@@ -455,6 +458,7 @@ export type InertiaAppConfig = {
|
|
|
455
458
|
cacheFor: CacheForOption | CacheForOption[];
|
|
456
459
|
hoverDelay: number;
|
|
457
460
|
};
|
|
461
|
+
nonce?: string;
|
|
458
462
|
visitOptions?: (href: string, options: VisitOptions) => VisitOptions;
|
|
459
463
|
};
|
|
460
464
|
export interface LinkComponentBaseProps extends Partial<Pick<Visit<RequestPayload>, 'component' | 'data' | 'method' | 'replace' | 'preserveScroll' | 'preserveState' | 'preserveUrl' | 'only' | 'except' | 'headers' | 'queryStringArrayFormat' | 'async' | 'viewTransition'> & VisitCallbacks & {
|
|
@@ -528,10 +532,10 @@ export type FormComponentProps<TForm = Record<string, FormDataConvertible>> = Pa
|
|
|
528
532
|
transform?: (data: TForm) => Record<string, FormDataConvertible>;
|
|
529
533
|
optimistic?: FormComponentOptimisticCallback<Page<SharedPageProps>['props'], TForm>;
|
|
530
534
|
options?: FormComponentOptions;
|
|
531
|
-
onSubmitComplete?: (props: FormComponentOnSubmitCompleteArguments) => void;
|
|
535
|
+
onSubmitComplete?: (props: FormComponentOnSubmitCompleteArguments<TForm & object>) => void;
|
|
532
536
|
disableWhileProcessing?: boolean;
|
|
533
|
-
resetOnSuccess?: boolean |
|
|
534
|
-
resetOnError?: boolean |
|
|
537
|
+
resetOnSuccess?: boolean | NoInfer<FormDataKeys<TForm>>[];
|
|
538
|
+
resetOnError?: boolean | NoInfer<FormDataKeys<TForm>>[];
|
|
535
539
|
setDefaultsOnSuccess?: boolean;
|
|
536
540
|
validateFiles?: boolean;
|
|
537
541
|
validationTimeout?: number;
|
|
@@ -649,8 +653,10 @@ export type UseHttpOptions<TResponse = unknown> = {
|
|
|
649
653
|
onBefore?: () => boolean | void;
|
|
650
654
|
onStart?: () => void;
|
|
651
655
|
onProgress?: (progress: HttpProgressEvent) => void;
|
|
652
|
-
onSuccess?: (response: TResponse) => void;
|
|
656
|
+
onSuccess?: (response: TResponse, httpResponse: HttpResponse) => void;
|
|
653
657
|
onError?: (errors: Errors) => void;
|
|
658
|
+
onHttpException?: (response: HttpResponse) => boolean | void;
|
|
659
|
+
onNetworkError?: (error: Error) => boolean | void;
|
|
654
660
|
onFinish?: () => void;
|
|
655
661
|
onCancel?: () => void;
|
|
656
662
|
onCancelToken?: (cancelToken: CancelToken) => void;
|