@octanejs/vite-plugin 0.1.5 → 0.1.9
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/package.json +17 -4
- package/src/client-assets.js +81 -0
- package/src/config-entry.js +15 -0
- package/src/constants.js +1 -3
- package/src/index.js +229 -71
- package/src/load-config.js +103 -80
- package/src/project-codegen.js +10 -218
- package/src/resolve-config.js +1 -171
- package/src/routes.js +1 -133
- package/src/server/component-wrappers.js +5 -56
- package/src/server/html-stream.js +1 -0
- package/src/server/html-template.js +9 -0
- package/src/server/middleware.js +1 -127
- package/src/server/node-http.js +1 -188
- package/src/server/production.js +1 -286
- package/src/server/render-route.js +66 -41
- package/src/server/router.js +1 -123
- package/src/server/server-route.js +1 -47
- package/src/server/virtual-entry.js +1 -184
- package/types/index.d.ts +52 -260
- package/types/node.d.ts +1 -31
- package/types/production.d.ts +1 -71
- package/CHANGELOG.md +0 -254
- package/tests/_fixtures/app/index.html +0 -11
- package/tests/_fixtures/app/octane.config.ts +0 -14
- package/tests/_fixtures/app/package.json +0 -7
- package/tests/_fixtures/app/src/Layout.tsrx +0 -6
- package/tests/_fixtures/app/src/Page.tsrx +0 -17
- package/tests/_fixtures/app/vite.config.ts +0 -12
- package/tests/handler.test.ts +0 -134
- package/tests/plugin.test.ts +0 -155
- package/tests/production.test.ts +0 -157
- package/tsconfig.typecheck.json +0 -18
|
@@ -1,184 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Production server-entry generator.
|
|
4
|
-
*
|
|
5
|
-
* `generateServerEntry` emits the module the SSR sub-build (closeBundle in
|
|
6
|
-
* src/index.js) uses as its Rollup input. The generated module statically
|
|
7
|
-
* imports every RenderRoute entry/layout module (compiled in server mode by
|
|
8
|
-
* the octane plugin the sub-build inherits from the app's vite.config) plus
|
|
9
|
-
* octane.config.ts itself, wires them into `createHandler`, and:
|
|
10
|
-
*
|
|
11
|
-
* - exports `handler` — the Web fetch handler `(Request) => Promise<Response>`
|
|
12
|
-
* - exports `nodeHandler` — a Node `(req, res)` wrapper for serverless
|
|
13
|
-
* platforms (e.g. a Vercel Node function does
|
|
14
|
-
* `export { nodeHandler as default } from '../dist/server/entry.js'`)
|
|
15
|
-
* - auto-boots when run directly (`node dist/server/entry.js`): the
|
|
16
|
-
* adapter's `serve()` when configured, else the built-in Node server
|
|
17
|
-
* (static dist/client assets + the handler).
|
|
18
|
-
*
|
|
19
|
-
* It is unused in dev (dev SSR loads modules through `vite.ssrLoadModule`).
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/** @import { Route } from '@octanejs/vite-plugin' */
|
|
23
|
-
/** @import { ClientAssetEntry } from '../../types/production.d.ts' */
|
|
24
|
-
|
|
25
|
-
import { get_route_entry_path } from '../routes.js';
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @typedef {Object} ServerEntryOptions
|
|
29
|
-
* @property {Route[]} routes - Route definitions from octane.config.ts
|
|
30
|
-
* @property {string} octaneConfigPath - Absolute path to octane.config.ts
|
|
31
|
-
* @property {Record<string, ClientAssetEntry>} [clientAssetMap] - Route entry path → built client asset paths
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @param {ServerEntryOptions} options
|
|
36
|
-
* @returns {string} The generated JavaScript module source
|
|
37
|
-
*/
|
|
38
|
-
export function generateServerEntry(options) {
|
|
39
|
-
const { routes, octaneConfigPath, clientAssetMap = {} } = options;
|
|
40
|
-
|
|
41
|
-
// Unique page-entry and layout module paths (multiple routes may share both).
|
|
42
|
-
/** @type {Map<string, string>} module path → import variable name */
|
|
43
|
-
const page_imports = new Map();
|
|
44
|
-
/** @type {Map<string, string>} */
|
|
45
|
-
const layout_imports = new Map();
|
|
46
|
-
|
|
47
|
-
for (const route of routes) {
|
|
48
|
-
if (route.type !== 'render') continue;
|
|
49
|
-
const entryPath = get_route_entry_path(route.entry);
|
|
50
|
-
if (entryPath && !page_imports.has(entryPath)) {
|
|
51
|
-
page_imports.set(entryPath, `_page_${page_imports.size}`);
|
|
52
|
-
}
|
|
53
|
-
if (typeof route.layout === 'string' && !layout_imports.has(route.layout)) {
|
|
54
|
-
layout_imports.set(route.layout, `_layout_${layout_imports.size}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const import_lines = [];
|
|
59
|
-
for (const [modulePath, varName] of page_imports) {
|
|
60
|
-
import_lines.push(`import * as ${varName} from ${JSON.stringify(modulePath)};`);
|
|
61
|
-
}
|
|
62
|
-
for (const [modulePath, varName] of layout_imports) {
|
|
63
|
-
import_lines.push(`import * as ${varName} from ${JSON.stringify(modulePath)};`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// The manifest maps MODULE PATHS to module namespaces; createHandler picks
|
|
67
|
-
// the export per-route with the same `get_component_export` dev uses.
|
|
68
|
-
const component_entries = [...page_imports]
|
|
69
|
-
.map(([modulePath, varName]) => `\t${JSON.stringify(modulePath)}: ${varName},`)
|
|
70
|
-
.join('\n');
|
|
71
|
-
const layout_entries = [...layout_imports]
|
|
72
|
-
.map(([modulePath, varName]) => `\t${JSON.stringify(modulePath)}: ${varName},`)
|
|
73
|
-
.join('\n');
|
|
74
|
-
|
|
75
|
-
return `\
|
|
76
|
-
// Auto-generated by @octanejs/vite-plugin — the production server entry.
|
|
77
|
-
// Do not edit; regenerated on every build.
|
|
78
|
-
|
|
79
|
-
import { readFileSync } from 'node:fs';
|
|
80
|
-
import { createHash } from 'node:crypto';
|
|
81
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
82
|
-
import { fileURLToPath } from 'node:url';
|
|
83
|
-
import { dirname, join, resolve } from 'node:path';
|
|
84
|
-
|
|
85
|
-
import { renderToReadableStream, executeServerFunction } from 'octane/server';
|
|
86
|
-
import { prerender } from 'octane/static';
|
|
87
|
-
import { createHandler, resolveOctaneConfig } from '@octanejs/vite-plugin/production';
|
|
88
|
-
import { createNodeServer, nodeRequestToWebRequest, sendWebResponse } from '@octanejs/vite-plugin/node';
|
|
89
|
-
|
|
90
|
-
// The app config — bundled (the sub-build aliases '@octanejs/vite-plugin' to
|
|
91
|
-
// its config-surface facade, so this does not drag the compiler in).
|
|
92
|
-
import _rawOctaneConfig from ${JSON.stringify(octaneConfigPath)};
|
|
93
|
-
|
|
94
|
-
${import_lines.join('\n')}
|
|
95
|
-
|
|
96
|
-
const octaneConfig = resolveOctaneConfig(_rawOctaneConfig);
|
|
97
|
-
|
|
98
|
-
// Platform primitives: the adapter's when configured, else Node defaults.
|
|
99
|
-
// (hash mirrors the compiler's module-server hashing: sha-256 hex, 8 chars.)
|
|
100
|
-
const runtime = octaneConfig.adapter?.runtime ?? {
|
|
101
|
-
hash: (str) => createHash('sha256').update(str).digest('hex').slice(0, 8),
|
|
102
|
-
createAsyncContext: () => {
|
|
103
|
-
const als = new AsyncLocalStorage();
|
|
104
|
-
return { run: (store, fn) => als.run(store, fn), getStore: () => als.getStore() };
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
109
|
-
// The HTML template is the BUILT client index.html (hashed hydrate script and
|
|
110
|
-
// asset links already in place), moved next to this entry by the build.
|
|
111
|
-
const htmlTemplate = readFileSync(join(__dirname, './index.html'), 'utf-8');
|
|
112
|
-
|
|
113
|
-
const components = {
|
|
114
|
-
${component_entries}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const layouts = {
|
|
118
|
-
${layout_entries}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const clientAssets = ${JSON.stringify(clientAssetMap, null, '\t')};
|
|
122
|
-
|
|
123
|
-
export const handler = createHandler(
|
|
124
|
-
{
|
|
125
|
-
routes: octaneConfig.router.routes,
|
|
126
|
-
components,
|
|
127
|
-
layouts,
|
|
128
|
-
middlewares: octaneConfig.middlewares,
|
|
129
|
-
trustProxy: octaneConfig.server.trustProxy,
|
|
130
|
-
render: octaneConfig.server.render,
|
|
131
|
-
rootBoundary: octaneConfig.rootBoundary,
|
|
132
|
-
preHydrate: octaneConfig.router.preHydrate ?? null,
|
|
133
|
-
rpcModules: {},
|
|
134
|
-
runtime,
|
|
135
|
-
clientAssets,
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
renderToReadableStream,
|
|
139
|
-
prerender,
|
|
140
|
-
htmlTemplate,
|
|
141
|
-
executeServerFunction,
|
|
142
|
-
},
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Node-style (req, res) wrapper — for serverless platforms whose functions
|
|
147
|
-
* speak Node HTTP (e.g. Vercel's Node runtime).
|
|
148
|
-
*/
|
|
149
|
-
export async function nodeHandler(req, res) {
|
|
150
|
-
try {
|
|
151
|
-
const response = await handler(nodeRequestToWebRequest(req));
|
|
152
|
-
await sendWebResponse(res, response);
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error('[@octanejs/vite-plugin] Request error:', error);
|
|
155
|
-
if (!res.headersSent) {
|
|
156
|
-
res.statusCode = 500;
|
|
157
|
-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
158
|
-
}
|
|
159
|
-
res.end('Internal Server Error');
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Auto-boot when run directly (node dist/server/entry.js); stay quiet when
|
|
164
|
-
// imported by a serverless wrapper.
|
|
165
|
-
const isMainModule =
|
|
166
|
-
typeof process !== 'undefined' &&
|
|
167
|
-
process.argv[1] &&
|
|
168
|
-
fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
|
169
|
-
|
|
170
|
-
if (isMainModule) {
|
|
171
|
-
const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
|
|
172
|
-
if (isNaN(port) || port < 1 || port > 65535) {
|
|
173
|
-
console.error('[@octanejs/vite-plugin] Invalid PORT value:', process.env.PORT);
|
|
174
|
-
process.exit(1);
|
|
175
|
-
}
|
|
176
|
-
const staticDir = join(__dirname, '../client');
|
|
177
|
-
const server = octaneConfig.adapter?.serve
|
|
178
|
-
? octaneConfig.adapter.serve(handler, { static: { dir: staticDir } })
|
|
179
|
-
: createNodeServer(handler, { staticDir });
|
|
180
|
-
server.listen(port);
|
|
181
|
-
console.log('[@octanejs/vite-plugin] Production server listening on port ' + port);
|
|
182
|
-
}
|
|
183
|
-
`;
|
|
184
|
-
}
|
|
1
|
+
export { generateServerEntry, generateServerManifestEntry } from '@octanejs/app-core/codegen';
|
package/types/index.d.ts
CHANGED
|
@@ -1,278 +1,70 @@
|
|
|
1
|
-
import type { Plugin,
|
|
2
|
-
import type {
|
|
1
|
+
import type { Plugin, ViteDevServer } from 'vite';
|
|
2
|
+
import type {
|
|
3
|
+
ConfigModuleRunner,
|
|
4
|
+
ExperimentalRendererConfigOptions,
|
|
5
|
+
LoadedOctaneConfig,
|
|
6
|
+
OctaneConfigOptions,
|
|
7
|
+
ResolvedOctaneConfig,
|
|
8
|
+
} from '@octanejs/app-core';
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
// Plugin exports
|
|
6
|
-
// ============================================================================
|
|
10
|
+
export * from '@octanejs/app-core';
|
|
7
11
|
|
|
8
12
|
export interface OctanePluginOptions {
|
|
9
13
|
/** Override the client HMR default (on in serve mode, off for SSR). */
|
|
10
14
|
hmr?: boolean;
|
|
15
|
+
/** Enable component profiling in client transforms. */
|
|
16
|
+
profile?: boolean;
|
|
11
17
|
/**
|
|
12
18
|
* Path fragments the compiler's plain `.ts`/`.js` hook-slotting pass must
|
|
13
|
-
* skip
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* (e.g. `['/packages/tanstack-router/src/']`).
|
|
19
|
+
* skip. Prefer package manifest `octane.hookSlots.manual` declarations.
|
|
20
|
+
* With `requireDirective`, excluded paths are exempt from Octane ownership
|
|
21
|
+
* entirely — including `.tsrx`/`.tsx` — for projects routing those paths
|
|
22
|
+
* through a different tsrx compiler (e.g. `@tsrx/react`).
|
|
18
23
|
*/
|
|
19
24
|
exclude?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Mixed-toolchain ownership gate: when `true`, Octane compiles only
|
|
27
|
+
* project modules that declare `'use octane'` in their directive prologue.
|
|
28
|
+
* Undirected project `.tsx`/`.ts`/`.js` pass through to the host
|
|
29
|
+
* framework's own pipeline (e.g. React's JSX transform); an undirected
|
|
30
|
+
* project `.tsrx` is a build error. Installed and linked packages keep
|
|
31
|
+
* their Octane package-manifest decision. The directive is always
|
|
32
|
+
* tolerated and stripped from compiled output, even when this is off.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
requireDirective?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* @experimental Full renderer-config override. When omitted, the compiler
|
|
38
|
+
* reads `compiler.renderers` from `octane.config.ts` before transforming modules.
|
|
39
|
+
*/
|
|
40
|
+
renderers?: ExperimentalRendererConfigOptions;
|
|
20
41
|
}
|
|
21
42
|
|
|
22
|
-
/**
|
|
23
|
-
* The octane metaframework plugin. Returns an array:
|
|
24
|
-
* `[octane(), metaPlugin]` — the first compiles `.tsrx`, the second owns
|
|
25
|
-
* config / routing / dev SSR / hydrate.
|
|
26
|
-
*/
|
|
43
|
+
/** The Octane compiler plugin plus Vite app/metaframework integration. */
|
|
27
44
|
export function octane(options?: OctanePluginOptions): Plugin[];
|
|
28
45
|
|
|
29
|
-
/**
|
|
30
|
-
* Is this a request the Vite dev server owns (module / asset / internal
|
|
31
|
-
* namespace / transform query), as opposed to a page navigation? The dev SSR
|
|
32
|
-
* middleware uses it so a catch-all RenderRoute never swallows Vite requests.
|
|
33
|
-
*
|
|
34
|
-
* `fileRoots` (the Vite root + publicDir) gate the file-extension heuristic:
|
|
35
|
-
* an extension-bearing path is only Vite's when it names a real file under
|
|
36
|
-
* one of them, so page URLs like `/docs/v2.0` still SSR. Without `fileRoots`
|
|
37
|
-
* any extension counts (conservative).
|
|
38
|
-
*/
|
|
46
|
+
/** Return whether a dev request belongs to Vite rather than an app route. */
|
|
39
47
|
export function isViteOwnedUrl(url: URL, fileRoots?: string[]): boolean;
|
|
40
|
-
|
|
48
|
+
|
|
49
|
+
export interface ViteLoadConfigOptions {
|
|
50
|
+
vite?: ViteDevServer;
|
|
51
|
+
moduleRunner?: ConfigModuleRunner | ConfigModuleRunner['loadModule'];
|
|
52
|
+
requireAdapter?: boolean;
|
|
53
|
+
configFile?: string;
|
|
54
|
+
cacheDir?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getOctaneConfigPath(projectRoot: string, configFile?: string): string;
|
|
58
|
+
export function octaneConfigExists(projectRoot: string, configFile?: string): boolean;
|
|
59
|
+
export function loadOctaneConfig(
|
|
60
|
+
projectRoot: string,
|
|
61
|
+
options?: ViteLoadConfigOptions,
|
|
62
|
+
): Promise<ResolvedOctaneConfig>;
|
|
63
|
+
export function loadOctaneConfigWithMetadata(
|
|
64
|
+
projectRoot: string,
|
|
65
|
+
options?: ViteLoadConfigOptions,
|
|
66
|
+
): Promise<LoadedOctaneConfig>;
|
|
41
67
|
export function resolveOctaneConfig(
|
|
42
68
|
raw: OctaneConfigOptions,
|
|
43
69
|
options?: { requireAdapter?: boolean },
|
|
44
70
|
): ResolvedOctaneConfig;
|
|
45
|
-
export function getOctaneConfigPath(projectRoot: string): string;
|
|
46
|
-
export function octaneConfigExists(projectRoot: string): boolean;
|
|
47
|
-
export function loadOctaneConfig(
|
|
48
|
-
projectRoot: string,
|
|
49
|
-
options?: { vite?: ViteDevServer; requireAdapter?: boolean },
|
|
50
|
-
): Promise<ResolvedOctaneConfig>;
|
|
51
|
-
|
|
52
|
-
// ============================================================================
|
|
53
|
-
// Route classes
|
|
54
|
-
// ============================================================================
|
|
55
|
-
|
|
56
|
-
export class RenderRoute {
|
|
57
|
-
readonly type: 'render';
|
|
58
|
-
path: string;
|
|
59
|
-
entry: RenderRouteEntry;
|
|
60
|
-
layout?: string;
|
|
61
|
-
before: Middleware[];
|
|
62
|
-
status?: number;
|
|
63
|
-
constructor(options: RenderRouteOptions);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class ServerRoute {
|
|
67
|
-
readonly type: 'server';
|
|
68
|
-
path: string;
|
|
69
|
-
methods: string[];
|
|
70
|
-
handler: RouteHandler;
|
|
71
|
-
before: Middleware[];
|
|
72
|
-
after: Middleware[];
|
|
73
|
-
constructor(options: ServerRouteOptions);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export type Route = RenderRoute | ServerRoute;
|
|
77
|
-
|
|
78
|
-
// ============================================================================
|
|
79
|
-
// Route options
|
|
80
|
-
// ============================================================================
|
|
81
|
-
|
|
82
|
-
export interface RenderRouteOptions {
|
|
83
|
-
/** URL path pattern (e.g., '/', '/posts/:id', '/docs/*slug') */
|
|
84
|
-
path: string;
|
|
85
|
-
/** Path to the component entry file, optionally with a preferred named export */
|
|
86
|
-
entry: RenderRouteEntry;
|
|
87
|
-
/** Path to the layout component (wraps the entry) */
|
|
88
|
-
layout?: string;
|
|
89
|
-
/** Middleware to run before rendering */
|
|
90
|
-
before?: Middleware[];
|
|
91
|
-
/**
|
|
92
|
-
* HTTP status for the rendered response (default 200). Set 404 on a
|
|
93
|
-
* catch-all route so the SSR'd not-found page reports its real status.
|
|
94
|
-
*/
|
|
95
|
-
status?: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface ServerRouteOptions {
|
|
99
|
-
/** URL path pattern (e.g., '/api/hello', '/api/posts/:id') */
|
|
100
|
-
path: string;
|
|
101
|
-
/** HTTP methods to handle (default: ['GET']) */
|
|
102
|
-
methods?: string[];
|
|
103
|
-
/** Request handler that returns a Response */
|
|
104
|
-
handler: RouteHandler;
|
|
105
|
-
/** Middleware to run before the handler */
|
|
106
|
-
before?: Middleware[];
|
|
107
|
-
/** Middleware to run after the handler */
|
|
108
|
-
after?: Middleware[];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ============================================================================
|
|
112
|
-
// Context and middleware
|
|
113
|
-
// ============================================================================
|
|
114
|
-
|
|
115
|
-
export interface Context {
|
|
116
|
-
/** The incoming Request object */
|
|
117
|
-
request: Request;
|
|
118
|
-
/** URL parameters extracted from the route pattern */
|
|
119
|
-
params: Record<string, string>;
|
|
120
|
-
/** Parsed URL object */
|
|
121
|
-
url: URL;
|
|
122
|
-
/** Shared state for passing data between middlewares */
|
|
123
|
-
state: Map<string, unknown>;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export type NextFunction = () => Promise<Response>;
|
|
127
|
-
export type Middleware = (context: Context, next: NextFunction) => Response | Promise<Response>;
|
|
128
|
-
export type RouteHandler = (context: Context) => Response | Promise<Response>;
|
|
129
|
-
|
|
130
|
-
// ============================================================================
|
|
131
|
-
// Configuration
|
|
132
|
-
// ============================================================================
|
|
133
|
-
|
|
134
|
-
export type Component<T = Record<string, any>> = (
|
|
135
|
-
scope: any,
|
|
136
|
-
props: T,
|
|
137
|
-
extra?: any,
|
|
138
|
-
) => string | void;
|
|
139
|
-
|
|
140
|
-
export type RenderRouteEntry = string | readonly [exportName: string, path: string];
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Props every RenderRoute component (and layout) receives: the route params
|
|
144
|
-
* and the request `url` (pathname + search, origin-free — the client hydrate
|
|
145
|
-
* entry re-renders with the identical string).
|
|
146
|
-
*/
|
|
147
|
-
export interface RenderRouteProps {
|
|
148
|
-
params: Record<string, string>;
|
|
149
|
-
url: string;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* The app hook run by the client hydrate entry BEFORE `hydrateRoot` (config
|
|
154
|
-
* `router.preHydrate`): commit client-side state the server already resolved —
|
|
155
|
-
* typically a client router loading its match tree — so the first hydration
|
|
156
|
-
* pass adopts the same tree the server rendered.
|
|
157
|
-
*/
|
|
158
|
-
export type PreHydrateHook = (info: {
|
|
159
|
-
url: string;
|
|
160
|
-
params: Record<string, string>;
|
|
161
|
-
}) => void | Promise<void>;
|
|
162
|
-
|
|
163
|
-
export interface RootBoundaryOptions {
|
|
164
|
-
pending?: Component<Record<string, never>>;
|
|
165
|
-
catch?: Component<{ error: unknown; reset: () => void }>;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export interface OctaneConfigOptions {
|
|
169
|
-
build?: {
|
|
170
|
-
/** Output directory for the production build. @default 'dist' */
|
|
171
|
-
outDir?: string;
|
|
172
|
-
minify?: boolean;
|
|
173
|
-
target?: BuildEnvironmentOptions['target'];
|
|
174
|
-
};
|
|
175
|
-
adapter?: OctaneAdapter;
|
|
176
|
-
router?: {
|
|
177
|
-
routes: Route[];
|
|
178
|
-
/**
|
|
179
|
-
* Vite-root path (e.g. '/src/pre-hydrate.ts') of a module whose default
|
|
180
|
-
* export is a {@link PreHydrateHook}. The client hydrate entry imports it
|
|
181
|
-
* and awaits the hook before calling `hydrateRoot`.
|
|
182
|
-
*/
|
|
183
|
-
preHydrate?: string;
|
|
184
|
-
};
|
|
185
|
-
/** Global root pending/catch UI used by client and SSR render roots */
|
|
186
|
-
rootBoundary?: RootBoundaryOptions;
|
|
187
|
-
/** Global middlewares applied to all routes */
|
|
188
|
-
middlewares?: Middleware[];
|
|
189
|
-
platform?: {
|
|
190
|
-
env: Record<string, string>;
|
|
191
|
-
};
|
|
192
|
-
server?: {
|
|
193
|
-
/**
|
|
194
|
-
* Trust `X-Forwarded-Proto` / `X-Forwarded-Host` when deriving the
|
|
195
|
-
* request origin. Enable only behind a trusted reverse proxy.
|
|
196
|
-
* @default false
|
|
197
|
-
*/
|
|
198
|
-
trustProxy?: boolean;
|
|
199
|
-
/**
|
|
200
|
-
* Production SSR mode: 'streaming' (default) flushes the shell at
|
|
201
|
-
* first await and streams suspense segments out-of-order (same engine
|
|
202
|
-
* as dev SSR); 'buffered' awaits everything (`prerender`) and sends
|
|
203
|
-
* one document — for hosts that break streamed responses.
|
|
204
|
-
* @default 'streaming'
|
|
205
|
-
*/
|
|
206
|
-
render?: 'streaming' | 'buffered';
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Resolved configuration with all defaults applied.
|
|
212
|
-
*/
|
|
213
|
-
export interface ResolvedOctaneConfig {
|
|
214
|
-
build: {
|
|
215
|
-
/** @default 'dist' */
|
|
216
|
-
outDir: string;
|
|
217
|
-
minify?: boolean;
|
|
218
|
-
target?: BuildEnvironmentOptions['target'];
|
|
219
|
-
};
|
|
220
|
-
adapter?: OctaneAdapter;
|
|
221
|
-
router: {
|
|
222
|
-
routes: Route[];
|
|
223
|
-
preHydrate?: string;
|
|
224
|
-
};
|
|
225
|
-
rootBoundary: RootBoundaryOptions;
|
|
226
|
-
/** @default [] */
|
|
227
|
-
middlewares: Middleware[];
|
|
228
|
-
platform: {
|
|
229
|
-
/** @default {} */
|
|
230
|
-
env: Record<string, string>;
|
|
231
|
-
};
|
|
232
|
-
server: {
|
|
233
|
-
/** @default false */
|
|
234
|
-
trustProxy: boolean;
|
|
235
|
-
/** @default 'streaming' */
|
|
236
|
-
render: 'streaming' | 'buffered';
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* The build context @octanejs/vite-plugin passes to an adapter's `adapt()`
|
|
242
|
-
* after `vite build` produced both bundles.
|
|
243
|
-
*/
|
|
244
|
-
export interface AdaptContext {
|
|
245
|
-
/** Absolute project root (the Vite root). */
|
|
246
|
-
root: string;
|
|
247
|
-
/** The config `build.outDir` (relative to root, e.g. 'dist'). */
|
|
248
|
-
outDir: string;
|
|
249
|
-
/** Absolute path of the static client bundle ({outDir}/client). */
|
|
250
|
-
clientDir: string;
|
|
251
|
-
/** Absolute path of the server bundle ({outDir}/server, contains entry.js). */
|
|
252
|
-
serverDir: string;
|
|
253
|
-
/** Prefixed build logger. */
|
|
254
|
-
log: (message: string) => void;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* The octane.config.ts `adapter` contract. All parts are optional and
|
|
259
|
-
* independent:
|
|
260
|
-
*
|
|
261
|
-
* - `adapt(ctx)` — post-build hook: restructure dist/client + dist/server for
|
|
262
|
-
* a deployment target (e.g. @octanejs/adapter-vercel emits `.vercel/output`).
|
|
263
|
-
* - `serve(handler, opts)` — replaces the generated server entry's built-in
|
|
264
|
-
* Node boot when running `node dist/server/entry.js` / `octane-preview`.
|
|
265
|
-
* - `runtime` — platform primitives (hashing, async context) replacing the
|
|
266
|
-
* entry's Node defaults; needed on non-Node runtimes.
|
|
267
|
-
*/
|
|
268
|
-
export interface OctaneAdapter {
|
|
269
|
-
name?: string;
|
|
270
|
-
adapt?: (ctx: AdaptContext) => void | Promise<void>;
|
|
271
|
-
serve?: AdapterServeFunction;
|
|
272
|
-
runtime?: RuntimePrimitives;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export type AdapterServeFunction = (
|
|
276
|
-
handler: (request: Request, platform?: unknown) => Response | Promise<Response>,
|
|
277
|
-
options?: Record<string, unknown>,
|
|
278
|
-
) => { listen: (port?: number) => unknown; close: () => void };
|
package/types/node.d.ts
CHANGED
|
@@ -1,31 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** Convert a Node.js IncomingMessage to a Web Request. */
|
|
4
|
-
export function nodeRequestToWebRequest(nodeRequest: IncomingMessage): Request;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Pipe a Web Response to a Node.js ServerResponse, streaming chunk-by-chunk
|
|
8
|
-
* (a streaming SSR body flushes as it renders).
|
|
9
|
-
*/
|
|
10
|
-
export function sendWebResponse(nodeResponse: ServerResponse, webResponse: Response): Promise<void>;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Serve a static file from `staticDir` when the request path maps to one.
|
|
14
|
-
* `/assets/*` (hash-named build output) gets immutable caching; other files
|
|
15
|
-
* revalidate. Returns true when the request was handled.
|
|
16
|
-
*/
|
|
17
|
-
export function serveStaticFile(
|
|
18
|
-
req: IncomingMessage,
|
|
19
|
-
res: ServerResponse,
|
|
20
|
-
staticDir: string,
|
|
21
|
-
): boolean;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Minimal production HTTP server: static files from `staticDir` first (the
|
|
25
|
-
* built client assets), then the fetch-style SSR handler. The default boot for
|
|
26
|
-
* `node dist/server/entry.js` when octane.config.ts has no adapter.
|
|
27
|
-
*/
|
|
28
|
-
export function createNodeServer(
|
|
29
|
-
handler: (request: Request) => Response | Promise<Response>,
|
|
30
|
-
options?: { staticDir?: string },
|
|
31
|
-
): { listen: (port?: number) => Server; close: () => void };
|
|
1
|
+
export * from '@octanejs/app-core/node';
|
package/types/production.d.ts
CHANGED
|
@@ -1,71 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type {
|
|
3
|
-
Route,
|
|
4
|
-
Middleware,
|
|
5
|
-
ResolvedOctaneConfig,
|
|
6
|
-
OctaneConfigOptions,
|
|
7
|
-
RootBoundaryOptions,
|
|
8
|
-
} from '@octanejs/vite-plugin';
|
|
9
|
-
import type { RenderResult, StreamOptions, RenderOptions } from 'octane/server';
|
|
10
|
-
|
|
11
|
-
export function resolveOctaneConfig(
|
|
12
|
-
raw: OctaneConfigOptions,
|
|
13
|
-
options?: { requireAdapter?: boolean },
|
|
14
|
-
): ResolvedOctaneConfig;
|
|
15
|
-
|
|
16
|
-
export interface ClientAssetEntry {
|
|
17
|
-
/** Path to the built JS file (relative to the client output dir) */
|
|
18
|
-
js: string;
|
|
19
|
-
/** Paths to the built CSS files (relative to the client output dir) */
|
|
20
|
-
css: string[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ServerManifest {
|
|
24
|
-
routes: Route[];
|
|
25
|
-
/** RenderRoute entry module path → module namespace (export picked per-route) */
|
|
26
|
-
components: Record<string, Record<string, unknown>>;
|
|
27
|
-
/** Layout module path → module namespace */
|
|
28
|
-
layouts: Record<string, Record<string, unknown>>;
|
|
29
|
-
middlewares: Middleware[];
|
|
30
|
-
/** Trust X-Forwarded-* headers when deriving origin for RPC fetch */
|
|
31
|
-
trustProxy?: boolean;
|
|
32
|
-
/** 'streaming' (default) renders via renderToReadableStream; 'buffered' awaits everything via prerender */
|
|
33
|
-
render?: 'streaming' | 'buffered';
|
|
34
|
-
rootBoundary?: RootBoundaryOptions;
|
|
35
|
-
/** config `router.preHydrate`, serialized into #__octane_data for the client entry */
|
|
36
|
-
preHydrate?: string | null;
|
|
37
|
-
/** Map of entry path → `module server` namespace for RPC support */
|
|
38
|
-
rpcModules?: Record<string, Record<string, Function>>;
|
|
39
|
-
/** Platform primitives (adapter's, or the generated entry's Node defaults) */
|
|
40
|
-
runtime?: RuntimePrimitives;
|
|
41
|
-
/** Route entry module path → built client asset paths (preload tags) */
|
|
42
|
-
clientAssets?: Record<string, ClientAssetEntry>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface HandlerOptions {
|
|
46
|
-
/** `renderToReadableStream` from 'octane/server' (the streaming engine dev SSR uses) */
|
|
47
|
-
renderToReadableStream: (
|
|
48
|
-
component: Function,
|
|
49
|
-
props?: unknown,
|
|
50
|
-
options?: StreamOptions,
|
|
51
|
-
) => Promise<ReadableStream<Uint8Array>>;
|
|
52
|
-
/** `prerender` from 'octane/static' (the buffered await-everything fallback) */
|
|
53
|
-
prerender: (
|
|
54
|
-
component: Function,
|
|
55
|
-
props?: unknown,
|
|
56
|
-
options?: RenderOptions,
|
|
57
|
-
) => Promise<RenderResult>;
|
|
58
|
-
/** The BUILT dist client index.html (moved to dist/server by the build) */
|
|
59
|
-
htmlTemplate: string;
|
|
60
|
-
/** RPC executor from 'octane/server' */
|
|
61
|
-
executeServerFunction: (fn: Function, body: string) => Promise<string>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Production fetch-handler factory. Mirrors the dev middleware's render path
|
|
66
|
-
* byte-for-byte in everything hydration can see (see server/production.js).
|
|
67
|
-
*/
|
|
68
|
-
export function createHandler(
|
|
69
|
-
manifest: ServerManifest,
|
|
70
|
-
options: HandlerOptions,
|
|
71
|
-
): (request: Request) => Promise<Response>;
|
|
1
|
+
export * from '@octanejs/app-core/production';
|