@octanejs/app-core 0.0.52 → 0.0.53
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 +3 -3
- package/src/html.js +1 -0
- package/src/server/production.js +7 -16
- package/src/server/route-data.js +25 -0
- package/types/html.d.ts +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/app-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.53",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -79,10 +79,10 @@
|
|
|
79
79
|
"esbuild": "^0.28.1"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
|
-
"octane": "^0.3.
|
|
82
|
+
"octane": "^0.3.1"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/node": "^24.13.3",
|
|
86
|
-
"octane": "0.3.
|
|
86
|
+
"octane": "0.3.1"
|
|
87
87
|
}
|
|
88
88
|
}
|
package/src/html.js
CHANGED
package/src/server/production.js
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* BUILT dist/client/index.html (hashed hydrate script already in place, so
|
|
19
19
|
* nothing is injected per-request), per-route `<link rel=stylesheet/modulepreload>`
|
|
20
20
|
* tags from the client manifest join the head, and render errors produce a
|
|
21
|
-
* plain 500 (no dev stack page).
|
|
22
|
-
* changes.
|
|
21
|
+
* plain 500 (no dev stack page). Both handlers use the shared route-data
|
|
22
|
+
* serializer when the hydration payload shape changes.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { createRouter } from './router.js';
|
|
@@ -31,6 +31,7 @@ import { runServerRequest } from './signal-owners.js';
|
|
|
31
31
|
import { rpcIdCollision } from './rpc-registry.js';
|
|
32
32
|
import { handleServerRoute } from './server-route.js';
|
|
33
33
|
import { composeHtmlStream } from './html-stream.js';
|
|
34
|
+
import { serializeRouteData } from './route-data.js';
|
|
34
35
|
import {
|
|
35
36
|
applyHydrationNonce,
|
|
36
37
|
getContextNonce,
|
|
@@ -253,7 +254,7 @@ function prepareIndependentHydration(manifest) {
|
|
|
253
254
|
* Snapshot completed build authority once per handler, never from request data.
|
|
254
255
|
* Legacy custom handlers without a client build retain their existing path.
|
|
255
256
|
* @param {ServerManifest} manifest
|
|
256
|
-
* @returns {
|
|
257
|
+
* @returns {import('@octanejs/app-core/production').ClientBuildManifest | undefined}
|
|
257
258
|
*/
|
|
258
259
|
function prepareClientBuild(manifest) {
|
|
259
260
|
const build = manifest.clientBuild;
|
|
@@ -505,8 +506,7 @@ export function createHandler(manifest, deps) {
|
|
|
505
506
|
deps,
|
|
506
507
|
);
|
|
507
508
|
|
|
508
|
-
//
|
|
509
|
-
// the data script is byte-identical between dev and production.
|
|
509
|
+
// Share payload ordering and script escaping with the dev handler.
|
|
510
510
|
const streamedSignals =
|
|
511
511
|
clientBuild == null
|
|
512
512
|
? undefined
|
|
@@ -514,7 +514,7 @@ export function createHandler(manifest, deps) {
|
|
|
514
514
|
buildId: clientBuild.buildId,
|
|
515
515
|
documentId: crypto.randomUUID(),
|
|
516
516
|
};
|
|
517
|
-
const routeData =
|
|
517
|
+
const routeData = serializeRouteData({
|
|
518
518
|
entry: entryPath,
|
|
519
519
|
exportName: exportName ?? null,
|
|
520
520
|
layout: route.layout ?? null,
|
|
@@ -526,7 +526,7 @@ export function createHandler(manifest, deps) {
|
|
|
526
526
|
clientBuild,
|
|
527
527
|
streamedSignals,
|
|
528
528
|
});
|
|
529
|
-
const dataScript = `<script id="__octane_data" type="application/json"${nonceAttribute(nonce)}>${
|
|
529
|
+
const dataScript = `<script id="__octane_data" type="application/json"${nonceAttribute(nonce)}>${routeData}</script>`;
|
|
530
530
|
|
|
531
531
|
// The page, layout, and configured root fallbacks can all contribute
|
|
532
532
|
// server HTML before hydration. Their asset records also include CSS for
|
|
@@ -620,12 +620,3 @@ export function createHandler(manifest, deps) {
|
|
|
620
620
|
|
|
621
621
|
return handler;
|
|
622
622
|
}
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* Escape script content to prevent XSS in the inline JSON data block.
|
|
626
|
-
* @param {string} str
|
|
627
|
-
* @returns {string}
|
|
628
|
-
*/
|
|
629
|
-
function escapeScript(str) {
|
|
630
|
-
return str.replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
|
|
631
|
-
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Serialize the common dev/production hydration payload in a stable order.
|
|
5
|
+
* Build and document identities are supplied by the caller, never generated or
|
|
6
|
+
* cached here. Escape HTML delimiters before embedding JSON in an inline script.
|
|
7
|
+
* @param {import('@octanejs/app-core/html').RouteHydrationData} data
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export function serializeRouteData(data) {
|
|
11
|
+
return JSON.stringify({
|
|
12
|
+
entry: data.entry,
|
|
13
|
+
exportName: data.exportName ?? null,
|
|
14
|
+
layout: data.layout ?? null,
|
|
15
|
+
routeIndex: data.routeIndex,
|
|
16
|
+
params: data.params,
|
|
17
|
+
url: data.url,
|
|
18
|
+
preHydrate: data.preHydrate ?? null,
|
|
19
|
+
rootBoundary: data.rootBoundary ?? { pending: null, catch: null },
|
|
20
|
+
clientBuild: data.clientBuild,
|
|
21
|
+
streamedSignals: data.streamedSignals,
|
|
22
|
+
})
|
|
23
|
+
.replace(/</g, '\\u003c')
|
|
24
|
+
.replace(/>/g, '\\u003e');
|
|
25
|
+
}
|
package/types/html.d.ts
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import type { Context } from '@octanejs/app-core';
|
|
2
|
+
import type { ClientBuildManifest, ServerManifest } from '@octanejs/app-core/production';
|
|
3
|
+
|
|
4
|
+
/** Request-local inputs to the script-safe dev/production hydration payload. */
|
|
5
|
+
export interface RouteHydrationData {
|
|
6
|
+
entry: string | undefined;
|
|
7
|
+
exportName?: string | null;
|
|
8
|
+
layout?: string | null;
|
|
9
|
+
routeIndex?: number;
|
|
10
|
+
params: Record<string, string>;
|
|
11
|
+
url: string;
|
|
12
|
+
preHydrate?: string | null;
|
|
13
|
+
rootBoundary?: ServerManifest['rootBoundaryEntries'];
|
|
14
|
+
clientBuild?: ClientBuildManifest;
|
|
15
|
+
streamedSignals?: { buildId: string; documentId: string };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function serializeRouteData(data: RouteHydrationData): string;
|
|
2
19
|
|
|
3
20
|
export const HYDRATION_NONCE_PLACEHOLDER: '__OCTANE_REQUEST_NONCE__';
|
|
4
21
|
export function composeHtmlStream(
|