@octanejs/app-core 0.0.1

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.
@@ -0,0 +1,436 @@
1
+ // @ts-check
2
+ /**
3
+ * Production server-entry generator.
4
+ *
5
+ * `generateServerEntry` emits the module an integration uses as its server
6
+ * bundle input. The generated module statically
7
+ * imports every RenderRoute entry/layout module (compiled in server mode by
8
+ * the active bundler integration) 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, where the active integration loads modules directly.
20
+ */
21
+
22
+ /** @import { Route, RootBoundaryOptions } from '@octanejs/app-core' */
23
+ /** @import { ClientAssetEntry } from '../../types/production.d.ts' */
24
+
25
+ import { get_route_entry_export_name, 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 {RootBoundaryOptions} [rootBoundary] - Importable app-wide boundary entries
32
+ * @property {string[]} [rpcModulePaths] - Project-root module IDs containing `module server`
33
+ * @property {Record<string, ClientAssetEntry>} [clientAssetMap] - Route entry path → built client asset paths
34
+ * @property {string} [clientAssetMapFile] - JSON asset map, resolved beside the built server entry at runtime
35
+ * @property {Record<string, string>} [moduleImports] - Stable module ID → bundler import specifier
36
+ * @property {((id: string) => string)} [resolveImport] - Fallback module-specifier mapper
37
+ * @property {string} [configImportPath] - Bundler import specifier for octane.config.ts
38
+ * @property {'handler' | 'manifest'} [mode] - Emit a bootable handler or a template-free manifest module
39
+ * @property {string} [serverRuntimeModuleId] - Renderer server runtime module ID
40
+ * @property {string} [staticRuntimeModuleId] - Renderer static runtime module ID
41
+ * @property {string} [productionModuleId] - App-core production runtime module ID
42
+ * @property {string} [configModuleId] - App-core config runtime module ID
43
+ * @property {string} [nodeModuleId] - App-core Node bridge module ID
44
+ * @property {string} [generatedBy] - Integration name used in generated comments
45
+ */
46
+
47
+ /**
48
+ * @param {ServerEntryOptions} options
49
+ * @returns {string} The generated JavaScript module source
50
+ */
51
+ export function generateServerEntry(options) {
52
+ const {
53
+ routes,
54
+ octaneConfigPath,
55
+ rootBoundary = {},
56
+ rpcModulePaths = [],
57
+ clientAssetMap = {},
58
+ clientAssetMapFile,
59
+ moduleImports = {},
60
+ resolveImport,
61
+ configImportPath,
62
+ mode = 'handler',
63
+ serverRuntimeModuleId = 'octane/server',
64
+ staticRuntimeModuleId = 'octane/static',
65
+ productionModuleId = '@octanejs/app-core/production',
66
+ configModuleId = '@octanejs/app-core/config',
67
+ nodeModuleId = '@octanejs/app-core/node',
68
+ generatedBy = '@octanejs/app-core',
69
+ } = options;
70
+ const import_specifier = (/** @type {string} */ id) =>
71
+ moduleImports[id] ?? resolveImport?.(id) ?? id;
72
+ const resolvedConfigImport =
73
+ configImportPath ?? moduleImports[octaneConfigPath] ?? octaneConfigPath;
74
+
75
+ // Unique page-entry and layout module paths (multiple routes may share both).
76
+ /** @type {Map<string, string>} module path → import variable name */
77
+ const page_imports = new Map();
78
+ /** @type {Map<string, string>} */
79
+ const layout_imports = new Map();
80
+ /** @type {Map<string, string>} */
81
+ const rpc_imports = new Map();
82
+ /** @type {Map<string, string>} */
83
+ const boundary_imports = new Map();
84
+
85
+ for (const route of routes) {
86
+ if (route.type !== 'render') continue;
87
+ const entryPath = get_route_entry_path(route.entry);
88
+ if (entryPath && !page_imports.has(entryPath)) {
89
+ page_imports.set(entryPath, `_page_${page_imports.size}`);
90
+ }
91
+ if (typeof route.layout === 'string' && !layout_imports.has(route.layout)) {
92
+ layout_imports.set(route.layout, `_layout_${layout_imports.size}`);
93
+ }
94
+ }
95
+
96
+ for (const entry of [rootBoundary.pending, rootBoundary.catch]) {
97
+ const modulePath = get_route_entry_path(entry);
98
+ if (modulePath && !boundary_imports.has(modulePath)) {
99
+ boundary_imports.set(modulePath, `_boundary_${boundary_imports.size}`);
100
+ }
101
+ }
102
+
103
+ for (const modulePath of rpcModulePaths) {
104
+ if (!page_imports.has(modulePath)) {
105
+ rpc_imports.set(modulePath, `_rpc_${rpc_imports.size}`);
106
+ }
107
+ }
108
+
109
+ const import_lines = [];
110
+ for (const [modulePath, varName] of page_imports) {
111
+ import_lines.push(
112
+ `import * as ${varName} from ${JSON.stringify(import_specifier(modulePath))};`,
113
+ );
114
+ }
115
+ for (const [modulePath, varName] of layout_imports) {
116
+ import_lines.push(
117
+ `import * as ${varName} from ${JSON.stringify(import_specifier(modulePath))};`,
118
+ );
119
+ }
120
+ for (const [modulePath, varName] of boundary_imports) {
121
+ if (!page_imports.has(modulePath) && !layout_imports.has(modulePath)) {
122
+ import_lines.push(
123
+ `import * as ${varName} from ${JSON.stringify(import_specifier(modulePath))};`,
124
+ );
125
+ }
126
+ }
127
+ for (const [modulePath, varName] of rpc_imports) {
128
+ if (!boundary_imports.has(modulePath) && !layout_imports.has(modulePath)) {
129
+ import_lines.push(
130
+ `import * as ${varName} from ${JSON.stringify(import_specifier(modulePath))};`,
131
+ );
132
+ }
133
+ }
134
+
135
+ // The manifest maps MODULE PATHS to module namespaces; createHandler picks
136
+ // the export per-route with the same `get_component_export` dev uses.
137
+ const component_entries = [...page_imports]
138
+ .map(([modulePath, varName]) => `\t${JSON.stringify(modulePath)}: ${varName},`)
139
+ .join('\n');
140
+ const layout_entries = [...layout_imports]
141
+ .map(([modulePath, varName]) => `\t${JSON.stringify(modulePath)}: ${varName},`)
142
+ .join('\n');
143
+
144
+ const import_var_for = (/** @type {string} */ modulePath) =>
145
+ page_imports.get(modulePath) ??
146
+ layout_imports.get(modulePath) ??
147
+ boundary_imports.get(modulePath) ??
148
+ rpc_imports.get(modulePath);
149
+ const boundary_value = (/** @type {unknown} */ entry) => {
150
+ const modulePath = get_route_entry_path(/** @type {any} */ (entry));
151
+ if (!modulePath) return 'null';
152
+ const varName = import_var_for(modulePath);
153
+ const exportName = get_route_entry_export_name(/** @type {any} */ (entry));
154
+ return `getComponentExport(${varName}, ${JSON.stringify(exportName ?? null)})`;
155
+ };
156
+ const rpc_entries = rpcModulePaths
157
+ .map((modulePath) => {
158
+ const varName = import_var_for(modulePath);
159
+ return `\t${JSON.stringify(modulePath)}: ${varName}._$_server_$_,`;
160
+ })
161
+ .join('\n');
162
+
163
+ if (mode === 'manifest') {
164
+ const assetFileImports = clientAssetMapFile
165
+ ? `import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n`
166
+ : '';
167
+ const assetDirectory = clientAssetMapFile
168
+ ? `const __dirname = dirname(fileURLToPath(import.meta.url));\n`
169
+ : '';
170
+ const clientAssets = clientAssetMapFile
171
+ ? `JSON.parse(readFileSync(join(__dirname, ${JSON.stringify(clientAssetMapFile)}), 'utf-8'))`
172
+ : JSON.stringify(clientAssetMap, null, '\t');
173
+
174
+ return `\
175
+ // Auto-generated by ${generatedBy} — the template-free server manifest entry.
176
+ // Do not edit; regenerated by the active app integration.
177
+
178
+ ${assetFileImports}import { createHash } from 'node:crypto';
179
+ import { AsyncLocalStorage } from 'node:async_hooks';
180
+ import {
181
+ renderToReadableStream,
182
+ executeServerFunction,
183
+ Suspense,
184
+ ErrorBoundary,
185
+ createElement,
186
+ } from ${JSON.stringify(serverRuntimeModuleId)};
187
+ import { prerender } from ${JSON.stringify(staticRuntimeModuleId)};
188
+ import { resolveOctaneConfig } from ${JSON.stringify(configModuleId)};
189
+ import _rawOctaneConfig from ${JSON.stringify(resolvedConfigImport)};
190
+
191
+ ${import_lines.join('\n')}
192
+
193
+ export const octaneConfig = resolveOctaneConfig(_rawOctaneConfig);
194
+
195
+ const runtime = octaneConfig.adapter?.runtime ?? {
196
+ hash: (str) => createHash('sha256').update(str).digest('hex').slice(0, 8),
197
+ createAsyncContext: () => {
198
+ const als = new AsyncLocalStorage();
199
+ return { run: (store, fn) => als.run(store, fn), getStore: () => als.getStore() };
200
+ },
201
+ };
202
+
203
+ const components = {
204
+ ${component_entries}
205
+ };
206
+
207
+ const layouts = {
208
+ ${layout_entries}
209
+ };
210
+
211
+ function getComponentExport(module, exportName) {
212
+ if (exportName) return typeof module[exportName] === 'function' ? module[exportName] : null;
213
+ if (typeof module.default === 'function') return module.default;
214
+ return Object.entries(module).find(([key, value]) =>
215
+ typeof value === 'function' && /^[A-Z]/.test(key))?.[1] ?? null;
216
+ }
217
+
218
+ const rootBoundary = {
219
+ pending: ${boundary_value(rootBoundary.pending)},
220
+ catch: ${boundary_value(rootBoundary.catch)},
221
+ };
222
+
223
+ const rootBoundaryEntries = ${JSON.stringify(
224
+ {
225
+ pending: serialize_entry(rootBoundary.pending),
226
+ catch: serialize_entry(rootBoundary.catch),
227
+ },
228
+ null,
229
+ '\t',
230
+ )};
231
+
232
+ const rpcModules = {
233
+ ${rpc_entries}
234
+ };
235
+
236
+ ${assetDirectory}const clientAssets = ${clientAssets};
237
+
238
+ export const manifest = {
239
+ routes: octaneConfig.router.routes,
240
+ components,
241
+ layouts,
242
+ middlewares: octaneConfig.middlewares,
243
+ trustProxy: octaneConfig.server.trustProxy,
244
+ render: octaneConfig.server.render,
245
+ rootBoundary,
246
+ rootBoundaryEntries,
247
+ preHydrate: octaneConfig.router.preHydrate ?? null,
248
+ rpcModules,
249
+ runtime,
250
+ clientAssets,
251
+ };
252
+
253
+ export const rendererDeps = {
254
+ renderToReadableStream,
255
+ prerender,
256
+ executeServerFunction,
257
+ Suspense,
258
+ ErrorBoundary,
259
+ createElement,
260
+ };
261
+ `;
262
+ }
263
+
264
+ return `\
265
+ // Auto-generated by ${generatedBy} — the production server entry.
266
+ // Do not edit; regenerated on every build.
267
+
268
+ import { readFileSync } from 'node:fs';
269
+ import { createHash } from 'node:crypto';
270
+ import { AsyncLocalStorage } from 'node:async_hooks';
271
+ import { fileURLToPath } from 'node:url';
272
+ import { dirname, join, resolve } from 'node:path';
273
+
274
+ import {
275
+ renderToReadableStream,
276
+ executeServerFunction,
277
+ Suspense,
278
+ ErrorBoundary,
279
+ createElement,
280
+ } from ${JSON.stringify(serverRuntimeModuleId)};
281
+ import { prerender } from ${JSON.stringify(staticRuntimeModuleId)};
282
+ import { createHandler, resolveOctaneConfig } from ${JSON.stringify(productionModuleId)};
283
+ import { createNodeServer, nodeRequestToWebRequest, sendWebResponse } from ${JSON.stringify(nodeModuleId)};
284
+
285
+ // The app config is bundled by the active server integration.
286
+ import _rawOctaneConfig from ${JSON.stringify(resolvedConfigImport)};
287
+
288
+ ${import_lines.join('\n')}
289
+
290
+ const octaneConfig = resolveOctaneConfig(_rawOctaneConfig);
291
+
292
+ // Platform primitives: the adapter's when configured, else Node defaults.
293
+ // (hash mirrors the compiler's module-server hashing: sha-256 hex, 8 chars.)
294
+ const runtime = octaneConfig.adapter?.runtime ?? {
295
+ hash: (str) => createHash('sha256').update(str).digest('hex').slice(0, 8),
296
+ createAsyncContext: () => {
297
+ const als = new AsyncLocalStorage();
298
+ return { run: (store, fn) => als.run(store, fn), getStore: () => als.getStore() };
299
+ },
300
+ };
301
+
302
+ const __dirname = dirname(fileURLToPath(import.meta.url));
303
+ // The HTML template is the BUILT client index.html (hashed hydrate script and
304
+ // asset links already in place), moved next to this entry by the build.
305
+ const htmlTemplate = readFileSync(join(__dirname, './index.html'), 'utf-8');
306
+
307
+ const components = {
308
+ ${component_entries}
309
+ };
310
+
311
+ const layouts = {
312
+ ${layout_entries}
313
+ };
314
+
315
+ function getComponentExport(module, exportName) {
316
+ if (exportName) return typeof module[exportName] === 'function' ? module[exportName] : null;
317
+ if (typeof module.default === 'function') return module.default;
318
+ return Object.entries(module).find(([key, value]) =>
319
+ typeof value === 'function' && /^[A-Z]/.test(key))?.[1] ?? null;
320
+ }
321
+
322
+ const rootBoundary = {
323
+ pending: ${boundary_value(rootBoundary.pending)},
324
+ catch: ${boundary_value(rootBoundary.catch)},
325
+ };
326
+
327
+ const rootBoundaryEntries = ${JSON.stringify(
328
+ {
329
+ pending: serialize_entry(rootBoundary.pending),
330
+ catch: serialize_entry(rootBoundary.catch),
331
+ },
332
+ null,
333
+ '\t',
334
+ )};
335
+
336
+ const rpcModules = {
337
+ ${rpc_entries}
338
+ };
339
+
340
+ const clientAssets = ${
341
+ clientAssetMapFile
342
+ ? `JSON.parse(readFileSync(join(__dirname, ${JSON.stringify(clientAssetMapFile)}), 'utf-8'))`
343
+ : JSON.stringify(clientAssetMap, null, '\t')
344
+ };
345
+
346
+ export const handler = createHandler(
347
+ {
348
+ routes: octaneConfig.router.routes,
349
+ components,
350
+ layouts,
351
+ middlewares: octaneConfig.middlewares,
352
+ trustProxy: octaneConfig.server.trustProxy,
353
+ render: octaneConfig.server.render,
354
+ rootBoundary,
355
+ rootBoundaryEntries,
356
+ preHydrate: octaneConfig.router.preHydrate ?? null,
357
+ rpcModules,
358
+ runtime,
359
+ clientAssets,
360
+ },
361
+ {
362
+ renderToReadableStream,
363
+ prerender,
364
+ htmlTemplate,
365
+ executeServerFunction,
366
+ Suspense,
367
+ ErrorBoundary,
368
+ createElement,
369
+ },
370
+ );
371
+
372
+ /**
373
+ * Node-style (req, res) wrapper — for serverless platforms whose functions
374
+ * speak Node HTTP (e.g. Vercel's Node runtime).
375
+ */
376
+ export async function nodeHandler(req, res) {
377
+ try {
378
+ const response = await handler(nodeRequestToWebRequest(req));
379
+ await sendWebResponse(res, response);
380
+ } catch (error) {
381
+ console.error('[octane] Request error:', error);
382
+ if (!res.headersSent) {
383
+ res.statusCode = 500;
384
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
385
+ }
386
+ res.end('Internal Server Error');
387
+ }
388
+ }
389
+
390
+ // Auto-boot when run directly (node dist/server/entry.js); stay quiet when
391
+ // imported by a serverless wrapper.
392
+ const isMainModule =
393
+ typeof process !== 'undefined' &&
394
+ process.argv[1] &&
395
+ fileURLToPath(import.meta.url) === resolve(process.argv[1]);
396
+
397
+ if (isMainModule) {
398
+ const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
399
+ if (isNaN(port) || port < 1 || port > 65535) {
400
+ console.error('[octane] Invalid PORT value:', process.env.PORT);
401
+ process.exit(1);
402
+ }
403
+ const staticDir = join(__dirname, '../client');
404
+ const server = octaneConfig.adapter?.serve
405
+ ? octaneConfig.adapter.serve(handler, { static: { dir: staticDir } })
406
+ : createNodeServer(handler, { staticDir });
407
+ server.listen(port);
408
+ console.log('[octane] Production server listening on port ' + port);
409
+ }
410
+ `;
411
+ }
412
+
413
+ /**
414
+ * Generate the template-free module consumed by integration dev middleware.
415
+ * The loaded bundle exports `manifest` and `rendererDeps`; the integration
416
+ * supplies its current transformed HTML to `createHandler` per request/build.
417
+ *
418
+ * @param {ServerEntryOptions} options
419
+ * @returns {string}
420
+ */
421
+ export function generateServerManifestEntry(options) {
422
+ return generateServerEntry({ ...options, mode: 'manifest' });
423
+ }
424
+
425
+ /**
426
+ * @param {unknown} entry
427
+ * @returns {{ path: string, exportName: string | null } | null}
428
+ */
429
+ function serialize_entry(entry) {
430
+ const path = get_route_entry_path(/** @type {any} */ (entry));
431
+ if (!path) return null;
432
+ return {
433
+ path,
434
+ exportName: get_route_entry_export_name(/** @type {any} */ (entry)) ?? null,
435
+ };
436
+ }
@@ -0,0 +1,47 @@
1
+ // @ts-check
2
+ /**
3
+ * @typedef {import('@octanejs/app-core').Context} Context
4
+ * @typedef {import('@octanejs/app-core').ServerRoute} ServerRoute
5
+ * @typedef {import('@octanejs/app-core').Middleware} Middleware
6
+ */
7
+
8
+ import { runMiddlewareChain } from './middleware.js';
9
+
10
+ /**
11
+ * Handle a ServerRoute (API endpoint)
12
+ *
13
+ * @param {ServerRoute} route
14
+ * @param {Context} context
15
+ * @param {Middleware[]} globalMiddlewares
16
+ * @returns {Promise<Response>}
17
+ */
18
+ export async function handleServerRoute(route, context, globalMiddlewares) {
19
+ try {
20
+ // The handler wrapped as a function returning Promise<Response>
21
+ const handler = async () => {
22
+ return route.handler(context);
23
+ };
24
+
25
+ // Run the middleware chain: global → before → handler → after
26
+ const response = await runMiddlewareChain(
27
+ context,
28
+ globalMiddlewares,
29
+ route.before,
30
+ handler,
31
+ route.after,
32
+ );
33
+
34
+ return response;
35
+ } catch (error) {
36
+ console.error('[octane] API route error:', error);
37
+
38
+ // Return error response
39
+ const message = error instanceof Error ? error.message : 'Internal Server Error';
40
+ return new Response(JSON.stringify({ error: message }), {
41
+ status: 500,
42
+ headers: {
43
+ 'Content-Type': 'application/json',
44
+ },
45
+ });
46
+ }
47
+ }
@@ -0,0 +1,67 @@
1
+ import type { RootBoundaryOptions, Route } from '@octanejs/app-core';
2
+ import type { ClientAssetEntry } from '@octanejs/app-core/production';
3
+
4
+ export const RESOLVED_ADAPTER_BROWSER_STUB_ID: '\0octane:adapter-browser-stub';
5
+ export const SERVER_ONLY_ADAPTER_IDS: Set<string>;
6
+ export function create_adapter_browser_stub_source(): string;
7
+
8
+ export interface GeneratedProjectOptions {
9
+ root: string;
10
+ cacheDir?: string;
11
+ generatedDir?: string;
12
+ }
13
+
14
+ export function get_project_generated_dir(options: GeneratedProjectOptions): string;
15
+ export function write_project_generated_file(
16
+ options: GeneratedProjectOptions,
17
+ name: string,
18
+ source: string,
19
+ ): string;
20
+
21
+ export interface StaticClientEntry {
22
+ /** Stable ID serialized in hydration data. */
23
+ id: string;
24
+ /** Bundler-resolvable import specifier emitted in generated source. */
25
+ specifier: string;
26
+ }
27
+
28
+ export interface ClientEntryOptions {
29
+ configPath?: string;
30
+ staticEntries?: Array<string | StaticClientEntry>;
31
+ resolveImport?: (id: string) => string;
32
+ runtimeModuleId?: string;
33
+ generatedBy?: string;
34
+ }
35
+
36
+ export function create_client_entry_source(options?: ClientEntryOptions): string;
37
+
38
+ export interface ServerEntryOptions {
39
+ routes: Route[];
40
+ octaneConfigPath: string;
41
+ rootBoundary?: RootBoundaryOptions;
42
+ rpcModulePaths?: string[];
43
+ clientAssetMap?: Record<string, ClientAssetEntry>;
44
+ /** JSON file resolved beside the built server entry at module evaluation. */
45
+ clientAssetMapFile?: string;
46
+ /** Stable application module ID to emitted bundler import specifier. */
47
+ moduleImports?: Record<string, string>;
48
+ resolveImport?: (id: string) => string;
49
+ configImportPath?: string;
50
+ mode?: 'handler' | 'manifest';
51
+ serverRuntimeModuleId?: string;
52
+ staticRuntimeModuleId?: string;
53
+ productionModuleId?: string;
54
+ configModuleId?: string;
55
+ nodeModuleId?: string;
56
+ generatedBy?: string;
57
+ }
58
+
59
+ /** Generate a production fetch-handler + optional Node auto-boot entry. */
60
+ export function generateServerEntry(options: ServerEntryOptions): string;
61
+ /** Generate a template-free bundle exporting `manifest` and `rendererDeps`. */
62
+ export function generateServerManifestEntry(options: ServerEntryOptions): string;
63
+
64
+ /** Convert an absolute file under `root` to a stable project-root module ID. */
65
+ export function normalize_module_reference(filename: string, root: string): string;
66
+ /** Compatibility alias retained for the Vite integration. */
67
+ export function to_vite_root_import(filename: string, root: string): string;
@@ -0,0 +1,26 @@
1
+ import type {
2
+ LoadedOctaneConfig,
3
+ LoadConfigOptions,
4
+ OctaneConfigOptions,
5
+ ResolvedOctaneConfig,
6
+ } from '@octanejs/app-core';
7
+
8
+ export { resolveOctaneConfig } from '@octanejs/app-core';
9
+ export function getOctaneConfigPath(projectRoot: string, configFile?: string): string;
10
+ export function octaneConfigExists(projectRoot: string, configFile?: string): boolean;
11
+ export function loadOctaneConfig(
12
+ projectRoot: string,
13
+ options?: LoadConfigOptions,
14
+ ): Promise<ResolvedOctaneConfig>;
15
+ export function loadOctaneConfigWithMetadata(
16
+ projectRoot: string,
17
+ options?: LoadConfigOptions,
18
+ ): Promise<LoadedOctaneConfig>;
19
+
20
+ export type {
21
+ ConfigModuleRunner,
22
+ LoadedOctaneConfig,
23
+ LoadConfigOptions,
24
+ OctaneConfigOptions,
25
+ ResolvedOctaneConfig,
26
+ } from '@octanejs/app-core';
@@ -0,0 +1,26 @@
1
+ export {
2
+ DEFAULT_OUTDIR,
3
+ ENTRY_FILENAME,
4
+ OCTANE_NONCE_STATE_KEY,
5
+ RenderRoute,
6
+ ServerRoute,
7
+ defineConfig,
8
+ resolveOctaneConfig,
9
+ } from '@octanejs/app-core';
10
+ export type {
11
+ AdaptContext,
12
+ AdapterServeFunction,
13
+ BuildTarget,
14
+ Context,
15
+ Middleware,
16
+ OctaneAdapter,
17
+ OctaneConfigOptions,
18
+ PreHydrateHook,
19
+ RenderRouteEntry,
20
+ RenderRouteOptions,
21
+ RenderRouteProps,
22
+ ResolvedOctaneConfig,
23
+ RootBoundaryOptions,
24
+ Route,
25
+ ServerRouteOptions,
26
+ } from '@octanejs/app-core';
@@ -0,0 +1,14 @@
1
+ import type { Context } from '@octanejs/app-core';
2
+
3
+ export const HYDRATION_NONCE_PLACEHOLDER: '__OCTANE_REQUEST_NONCE__';
4
+ export function composeHtmlStream(
5
+ prefix: string,
6
+ renderStream: ReadableStream<Uint8Array>,
7
+ suffix: string,
8
+ ): ReadableStream<Uint8Array>;
9
+ export function validateSsrTemplate(html: string): void;
10
+ export function injectHydrationEntry(html: string, source: string, nonce?: string | null): string;
11
+ export function splitSsrTemplate(html: string): [prefix: string, suffix: string];
12
+ export function applyHydrationNonce(html: string, nonce?: string | null): string;
13
+ export function nonceAttribute(nonce?: string | null): string;
14
+ export function getContextNonce(context: Context): string | null;