@bleedingdev/modern-js-renderer-octane 3.9.3-ultramodern.6 → 3.9.3-ultramodern.8

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.
Files changed (49) hide show
  1. package/dist/cjs/entry-server.js +2 -2
  2. package/dist/cjs/i18n/I18nProvider.js +6 -14
  3. package/dist/cjs/index.js +4 -4
  4. package/dist/cjs/manifest.js +2 -2
  5. package/dist/cjs/plugin/compiler.js +2 -5
  6. package/dist/cjs/plugin/index.js +1 -1
  7. package/dist/cjs/plugin/profile.js +11 -10
  8. package/dist/cjs/router-client.js +1 -1
  9. package/dist/cjs/router-handler.js +11 -8
  10. package/dist/cjs/router-server.js +3 -11
  11. package/dist/cjs/router.js +1 -1
  12. package/dist/cjs/routes.js +11 -17
  13. package/dist/cjs/server.js +14 -6
  14. package/dist/esm/entry-server.mjs +3 -3
  15. package/dist/esm/i18n/I18nProvider.mjs +7 -15
  16. package/dist/esm/index.mjs +4 -4
  17. package/dist/esm/manifest.mjs +2 -2
  18. package/dist/esm/router-client.mjs +1 -1
  19. package/dist/esm/router-handler.mjs +11 -8
  20. package/dist/esm/router-server.mjs +0 -1
  21. package/dist/esm/router.mjs +2 -2
  22. package/dist/esm/routes.mjs +11 -17
  23. package/dist/esm/server.mjs +9 -1
  24. package/dist/esm-node/manifest.mjs +2 -2
  25. package/dist/esm-node/plugin/compiler.mjs +2 -5
  26. package/dist/esm-node/plugin/index.mjs +1 -1
  27. package/dist/esm-node/plugin/profile.mjs +11 -10
  28. package/dist/types/index.d.ts +4 -4
  29. package/dist/types/manifest.d.ts +2 -2
  30. package/dist/types/router-server.d.ts +0 -2
  31. package/dist/types/server.d.ts +3 -0
  32. package/package.json +23 -18
  33. package/src/entry-server.ts +3 -3
  34. package/src/i18n/I18nProvider.ts +11 -20
  35. package/src/index.ts +4 -4
  36. package/src/manifest.ts +2 -2
  37. package/src/plugin/compiler.ts +6 -14
  38. package/src/plugin/index.ts +3 -1
  39. package/src/plugin/profile.ts +12 -10
  40. package/src/router-client.ts +1 -1
  41. package/src/router-handler.ts +11 -8
  42. package/src/router-server.ts +0 -2
  43. package/src/router.ts +2 -2
  44. package/src/routes.ts +28 -26
  45. package/src/server.ts +16 -1
  46. package/dist/cjs/router-injection.js +0 -139
  47. package/dist/esm/router-injection.mjs +0 -101
  48. package/dist/types/router-injection.d.ts +0 -8
  49. package/src/router-injection.ts +0 -145
@@ -83,7 +83,7 @@ function createNativeServerEntry(options) {
83
83
  }
84
84
  })(async ({ router, responseHeaders })=>{
85
85
  const metadata = (0, data_namespaceObject.mergeDataResponseMetadata)(outcomes, {
86
- status: router.state.statusCode ?? 200
86
+ status: (0, external_router_server_js_namespaceObject.getSsrStatus)(router)
87
87
  });
88
88
  const policy = (0, data_namespaceObject.dataMetadataToDocumentPolicy)({
89
89
  ...metadata,
@@ -106,7 +106,7 @@ function createNativeServerEntry(options) {
106
106
  },
107
107
  document,
108
108
  federation: options.federation,
109
- injection: (0, external_router_server_js_namespaceObject.createOctaneRouterInjection)(router, session)
109
+ router
110
110
  });
111
111
  return (0, external_router_server_js_namespaceObject.createSsrStreamResponse)(router, rendered);
112
112
  });
@@ -32,21 +32,13 @@ __webpack_require__.d(__webpack_exports__, {
32
32
  });
33
33
  const external_octane_namespaceObject = require("octane");
34
34
  const external_context_js_namespaceObject = require("./context.js");
35
- const languageStateSlot = Symbol((0, external_octane_namespaceObject.hookSlots)(1));
36
- const languageSubscriptionSlot = Symbol((0, external_octane_namespaceObject.hookSlots)(1));
35
+ const languageStoreSlot = Symbol((0, external_octane_namespaceObject.hookSlots)(1));
37
36
  function I18nProvider(props) {
38
- const [language, setLanguage] = (0, external_octane_namespaceObject.useState)(()=>props.instance.language, languageStateSlot);
39
- (0, external_octane_namespaceObject.useEffect)(()=>{
40
- const instance = props.instance;
41
- setLanguage(instance.language);
42
- const handleLanguageChanged = (lng)=>setLanguage(lng);
43
- instance.on?.('languageChanged', handleLanguageChanged);
44
- return ()=>{
45
- instance.off?.('languageChanged', handleLanguageChanged);
46
- };
47
- }, [
48
- props.instance
49
- ], languageSubscriptionSlot);
37
+ const instance = props.instance;
38
+ const language = (0, external_octane_namespaceObject.useSyncExternalStore)((notify)=>{
39
+ instance.on?.('languageChanged', notify);
40
+ return ()=>instance.off?.('languageChanged', notify);
41
+ }, ()=>instance.language, ()=>instance.language, languageStoreSlot);
50
42
  const value = {
51
43
  instance: props.instance,
52
44
  languages: props.languages,
package/dist/cjs/index.js CHANGED
@@ -29,10 +29,10 @@ var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  const OCTANE_RUNTIME_PROFILE = Object.freeze({
31
31
  renderer: 'octane',
32
- runtime: '0.7.1+ultramodern.1331985ea3b0',
33
- router: '0.1.60+ultramodern.0b9f76ee3003',
34
- routerCore: '1.171.15',
35
- history: '1.162.0'
32
+ runtime: '0.13.8',
33
+ router: '0.2.10',
34
+ routerCore: '1.171.34',
35
+ history: '1.162.4'
36
36
  });
37
37
  __webpack_require__.d(__webpack_exports__, {}, {
38
38
  OCTANE_RUNTIME_PROFILE: OCTANE_RUNTIME_PROFILE
@@ -36,8 +36,8 @@ __webpack_require__.d(__webpack_exports__, {
36
36
  });
37
37
  const identity_namespaceObject = require("@modern-js/renderer-core/identity");
38
38
  const external_bootstrap_js_namespaceObject = require("./bootstrap.js");
39
- const OCTANE_RUNTIME_VERSION = '0.7.1+ultramodern.1331985ea3b0';
40
- const OCTANE_COMPILER_VERSION = '0.1.55';
39
+ const OCTANE_RUNTIME_VERSION = '0.13.8';
40
+ const OCTANE_COMPILER_VERSION = '0.2.4';
41
41
  function octaneModuleManifestFileName(entryName) {
42
42
  return (0, identity_namespaceObject.nativeModuleManifestFilename)('octane', entryName);
43
43
  }
@@ -67,7 +67,8 @@ function createOctaneCompilerPlugin(options) {
67
67
  const directory = pluginSourceDirectory();
68
68
  const require1 = (0, external_node_module_namespaceObject.createRequire)(external_node_path_default().join(directory, 'index.cjs'));
69
69
  const { OctaneCompilerManifestPlugin } = require1('./compiler-manifest.cjs');
70
- const { inferRspackEnvironment, OctaneRspackPlugin } = require1('@octanejs/rspack-plugin');
70
+ const appRequire = (0, external_node_module_namespaceObject.createRequire)(external_node_path_default().join(api.context.rootPath, 'package.json'));
71
+ const { inferRspackEnvironment, OctaneRspackPlugin } = appRequire('@octanejs/rspack-plugin');
71
72
  api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
72
73
  source: {
73
74
  include: [
@@ -77,10 +78,6 @@ function createOctaneCompilerPlugin(options) {
77
78
  }));
78
79
  api.modifyRspackConfig((config, { environment: rsbuildEnvironment })=>{
79
80
  const environment = rsbuildEnvironment.name === options.workerEnvironmentName ? 'server' : inferRspackEnvironment(config.target);
80
- config.resolve ??= {};
81
- const extensions = (config.resolve.extensions ?? []).filter((extension)=>'.tsrx' !== extension);
82
- extensions.splice(Math.max(extensions.indexOf('.ts'), extensions.indexOf('.tsx')) + 1, 0, '.tsrx');
83
- config.resolve.extensions = extensions;
84
81
  config.plugins ??= [];
85
82
  config.plugins.push(new OctaneRspackPlugin({
86
83
  root: api.context.rootPath,
@@ -128,7 +128,7 @@ const rendererAdapter = (0, adapter_namespaceObject.defineRendererAdapter)({
128
128
  ],
129
129
  dependencies: (0, adapter_namespaceObject.nativeRendererDependencies)(profile),
130
130
  devDependencies: {
131
- [profile.compiler.name]: profile.compiler.version,
131
+ [profile.compiler.name]: profile.dependencies[profile.compiler.name] ?? profile.compiler.version,
132
132
  typescript: typescriptVersion
133
133
  },
134
134
  typecheckCommand: 'octane-tsc --noEmit --project tsconfig.json',
@@ -31,7 +31,7 @@ const octaneProfile = {
31
31
  renderer: 'octane',
32
32
  status: 'preview',
33
33
  protocolVersion: 1,
34
- minimumNode: '26.10.0',
34
+ minimumNode: '26.12.0',
35
35
  hmr: {
36
36
  editedBoundary: 'may-reset',
37
37
  unaffectedComponents: 'preserved',
@@ -41,17 +41,17 @@ const octaneProfile = {
41
41
  },
42
42
  compiler: {
43
43
  name: '@octanejs/rspack-plugin',
44
- version: '0.1.55'
44
+ version: '0.2.4'
45
45
  },
46
46
  hydration: {
47
47
  name: 'octane',
48
- version: '0.7.1+ultramodern.1331985ea3b0'
48
+ version: '0.13.8'
49
49
  },
50
50
  router: {
51
51
  name: '@octanejs/tanstack-router',
52
- version: '0.1.60+ultramodern.0b9f76ee3003',
52
+ version: '0.2.10',
53
53
  coreName: '@tanstack/router-core',
54
- coreVersion: '1.171.15'
54
+ coreVersion: '1.171.34'
55
55
  },
56
56
  sourceExtensions: [
57
57
  '.tsx',
@@ -61,12 +61,13 @@ const octaneProfile = {
61
61
  ],
62
62
  jsxImportSource: 'octane',
63
63
  dependencies: {
64
- octane: 'https://github.com/bleedingdev/octane/releases/download/octane%400.7.1%2Bultramodern.1331985ea3b0/octane-0.7.1%2Bultramodern.1331985ea3b0.tgz',
65
- '@octanejs/tanstack-router': 'https://github.com/bleedingdev/octane/releases/download/%40octanejs%2Ftanstack-router%400.1.60%2Bultramodern.0b9f76ee3003/octanejs-tanstack-router-0.1.60%2Bultramodern.0b9f76ee3003.tgz',
66
- '@octanejs/rspack-plugin': '0.1.55',
64
+ '@tsrx/oxc': '0.20.0',
65
+ octane: 'https://github.com/BleedingDev/octane/releases/download/ultramodern-octane-d5988dd93614/octane-0.13.8.tgz',
66
+ '@octanejs/tanstack-router': 'https://github.com/BleedingDev/octane/releases/download/ultramodern-octane-d5988dd93614/octanejs-tanstack-router-0.2.10.tgz',
67
+ '@octanejs/rspack-plugin': 'https://github.com/BleedingDev/octane/releases/download/ultramodern-octane-d5988dd93614/octanejs-rspack-plugin-0.2.4.tgz',
67
68
  '@modern-js/renderer-octane': '3.8.3',
68
- seroval: '1.6.8',
69
- 'seroval-plugins': '1.6.8'
69
+ seroval: '1.6.9',
70
+ 'seroval-plugins': '1.6.9'
70
71
  },
71
72
  capabilities: {
72
73
  worker: true,
@@ -64,7 +64,7 @@ function isReactiveMatchIds(value) {
64
64
  }
65
65
  function waitForCommittedMatches(router, signal) {
66
66
  signal?.throwIfAborted();
67
- const matchesId = router.stores.matchesId;
67
+ const matchesId = router.stores.ids;
68
68
  if (matchesId.get().length > 0) return Promise.resolve();
69
69
  if (!isReactiveMatchIds(matchesId)) throw new Error('Octane router hydration requires its native reactive match store');
70
70
  return new Promise((resolve, reject)=>{
@@ -84,8 +84,8 @@ function requestHeaders(router) {
84
84
  if (field?.get || field?.set) throw new TypeError('Native Octane response headers must be owned values');
85
85
  appendHeaders(headers, field?.value);
86
86
  }
87
- const redirect = router.stores.redirect.get();
88
- if (redirect) appendHeaders(headers, redirect.headers);
87
+ const result = router._serverResult;
88
+ if (result?.type === 'redirect') appendHeaders(headers, result.redirect.headers);
89
89
  return headers;
90
90
  }
91
91
  function createOctaneRequestHandler({ createRouter, request, session, getRouterManifest, serialization }) {
@@ -106,7 +106,6 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
106
106
  ...serialization?.forbiddenValues ?? []
107
107
  ]
108
108
  });
109
- session.registerCleanup(()=>router.cancelMatches());
110
109
  const { url } = (0, server_namespaceObject.getNormalizedURL)(request.url, 'http://localhost');
111
110
  const href = url.href.replace(url.origin, '');
112
111
  router.update({
@@ -118,11 +117,13 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
118
117
  }),
119
118
  origin: router.options.origin ?? (0, server_namespaceObject.getOrigin)(request)
120
119
  });
121
- await withAbort(router.load(), session.signal);
120
+ await withAbort(router.load({
121
+ _signal: session.signal
122
+ }), session.signal);
122
123
  guard.assertActive();
123
- const redirect = router.stores.redirect.get();
124
- if (redirect) {
125
- const resolved = router.resolveRedirect(redirect);
124
+ const loadResult = router._serverResult;
125
+ if (loadResult?.type === 'redirect') {
126
+ const resolved = loadResult.redirect;
126
127
  const headers = requestHeaders(router);
127
128
  return new Response(null, {
128
129
  status: resolved.status,
@@ -133,7 +134,9 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
133
134
  guard.assertMatches();
134
135
  const serverSsr = router.serverSsr;
135
136
  if (!serverSsr) throw new Error('Native Octane router SSR state is required');
136
- await withAbort(serverSsr.dehydrate(), session.signal);
137
+ await withAbort(serverSsr.dehydrate({
138
+ signal: session.signal
139
+ }), session.signal);
137
140
  guard.assertActive();
138
141
  const responseHeaders = requestHeaders(router);
139
142
  const rendered = Promise.resolve(callback({
@@ -3,9 +3,6 @@ var __webpack_modules__ = {
3
3
  "./router-handler" (module) {
4
4
  module.exports = require("./router-handler.js");
5
5
  },
6
- "./router-injection" (module) {
7
- module.exports = require("./router-injection.js");
8
- },
9
6
  "./router-server-snapshot" (module) {
10
7
  module.exports = require("./router-server-snapshot.js");
11
8
  },
@@ -74,13 +71,11 @@ var __webpack_exports__ = {};
74
71
  "createOctaneRequestHandler",
75
72
  "prepareOctaneRouterSerialization",
76
73
  "default",
77
- "OctaneRouterServer",
78
- "createOctaneRouterInjection"
74
+ "OctaneRouterServer"
79
75
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_octanejs_tanstack_router_ssr_server__rspack_import_2[__rspack_import_key];
80
76
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
81
77
  var _router_handler__rspack_import_3 = __webpack_require__("./router-handler");
82
- var _router_injection__rspack_import_4 = __webpack_require__("./router-injection");
83
- var _router_server_snapshot__rspack_import_5 = __webpack_require__("./router-server-snapshot");
78
+ var _router_server_snapshot__rspack_import_4 = __webpack_require__("./router-server-snapshot");
84
79
  function OctaneRouterServer({ router }) {
85
80
  return (0, octane_server__rspack_import_1.createElement)(_octanejs_tanstack_router__rspack_import_0.RouterProvider, {
86
81
  router
@@ -89,18 +84,15 @@ var __webpack_exports__ = {};
89
84
  __webpack_require__.d(__webpack_exports__, {
90
85
  OctaneRouterServer: ()=>OctaneRouterServer,
91
86
  createOctaneRequestHandler: ()=>_router_handler__rspack_import_3.createOctaneRequestHandler,
92
- createOctaneRouterInjection: ()=>_router_injection__rspack_import_4.createOctaneRouterInjection,
93
- prepareOctaneRouterSerialization: ()=>_router_server_snapshot__rspack_import_5.prepareOctaneRouterSerialization
87
+ prepareOctaneRouterSerialization: ()=>_router_server_snapshot__rspack_import_4.prepareOctaneRouterSerialization
94
88
  });
95
89
  })();
96
90
  exports.OctaneRouterServer = __webpack_exports__.OctaneRouterServer;
97
91
  exports.createOctaneRequestHandler = __webpack_exports__.createOctaneRequestHandler;
98
- exports.createOctaneRouterInjection = __webpack_exports__.createOctaneRouterInjection;
99
92
  exports.prepareOctaneRouterSerialization = __webpack_exports__.prepareOctaneRouterSerialization;
100
93
  for(var __rspack_i in __webpack_exports__)if (-1 === [
101
94
  "OctaneRouterServer",
102
95
  "createOctaneRequestHandler",
103
- "createOctaneRouterInjection",
104
96
  "prepareOctaneRouterSerialization"
105
97
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
106
98
  Object.defineProperty(exports, '__esModule', {
@@ -150,7 +150,7 @@ var __webpack_exports__ = {};
150
150
  const identity = useApplicationIdentity();
151
151
  const routeId = useApplicationRouteId();
152
152
  const owner = (0, octane__rspack_import_2.useRef)(null, actionSlot(slot, 'owner'));
153
- (0, octane__rspack_import_2.useEffect)(()=>{
153
+ (0, octane__rspack_import_2.useLayoutEffect)(()=>{
154
154
  const controller = new AbortController();
155
155
  owner.current = controller;
156
156
  return ()=>controller.abort(new DOMException('The route action owner unmounted', 'AbortError'));
@@ -47,21 +47,12 @@ function resolveRouteData(routeId, outcome) {
47
47
  function isReactiveNativeMatch(value) {
48
48
  return 'object' == typeof value && null !== value && 'function' == typeof Reflect.get(value, 'get') && 'function' == typeof Reflect.get(value, 'subscribe');
49
49
  }
50
- function observeRouteCompletion(router, controller, signal, completion) {
50
+ function observeRouteCompletion(router, routeId, controller, signal, completion) {
51
51
  completion.catch((error)=>{
52
52
  if (signal.aborted) return;
53
- const match = [
54
- ...router.stores.pendingMatches.get(),
55
- ...router.stores.matches.get(),
56
- ...router.stores.cachedMatches.get()
57
- ].find((candidate)=>candidate.abortController === controller);
58
- if (!match) return;
59
- const store = [
60
- router.stores.pendingMatchStores.get(match.id),
61
- router.stores.matchStores.get(match.id),
62
- router.stores.cachedMatchStores.get(match.id)
63
- ].find((candidate)=>candidate?.get().abortController === controller);
64
- if (!store) return;
53
+ const route = Object.values(router.routesById).find((candidate)=>candidate.options.staticData?.ultramodernRouteId === routeId);
54
+ if (!route) return;
55
+ const store = router.stores.getMatchStore(route.id);
65
56
  let subscription;
66
57
  let settled = false;
67
58
  const cleanup = ()=>{
@@ -72,9 +63,10 @@ function observeRouteCompletion(router, controller, signal, completion) {
72
63
  settled = true;
73
64
  cleanup();
74
65
  };
75
- const publish = ()=>{
66
+ const publish = async ()=>{
76
67
  if (settled) return;
77
68
  const current = store.get();
69
+ if (!current) return;
78
70
  if (current.abortController !== controller || signal.aborted || 'pending' !== current.status && 'success' !== current.status) return void onAbort();
79
71
  if ('success' !== current.status || current.isFetching) return;
80
72
  settled = true;
@@ -82,17 +74,19 @@ function observeRouteCompletion(router, controller, signal, completion) {
82
74
  const route = router.routesById[current.routeId];
83
75
  let failure = error;
84
76
  try {
77
+ await route?.options.errorComponent?.preload?.();
78
+ if (signal.aborted || store.get()?.abortController !== controller) return;
85
79
  route?.options.onError?.(failure);
86
80
  } catch (onErrorFailure) {
87
81
  failure = onErrorFailure;
88
82
  }
89
83
  if (signal.aborted) return;
90
- router.updateMatch(match.id, (previous)=>previous.abortController !== controller || 'success' !== previous.status || previous.isFetching ? previous : {
84
+ router.stores.setMatches(router.stores.matches.get().map((previous)=>previous.routeId !== route.id || previous.abortController !== controller || 'success' !== previous.status || previous.isFetching ? previous : {
91
85
  ...previous,
92
86
  error: failure,
93
87
  status: 'error',
94
88
  isFetching: false
95
- });
89
+ }));
96
90
  };
97
91
  signal.addEventListener('abort', onAbort, {
98
92
  once: true
@@ -136,7 +130,7 @@ function createFileSystemRouteTree(routes, modules, options = {}) {
136
130
  await Promise.resolve();
137
131
  signal.throwIfAborted();
138
132
  if (failed) throw failure;
139
- observeRouteCompletion(router, match.abortController, signal, outcome.completion);
133
+ observeRouteCompletion(router, route.id, match.abortController, signal, outcome.completion);
140
134
  }
141
135
  options.onOutcome?.(route.id, outcome);
142
136
  return resolveRouteData(route.id, outcome);
@@ -33,7 +33,8 @@ __webpack_require__.d(__webpack_exports__, {
33
33
  });
34
34
  const document_namespaceObject = require("@modern-js/renderer-core/document");
35
35
  const session_namespaceObject = require("@modern-js/renderer-core/session");
36
- const server_namespaceObject = require("octane/server");
36
+ const server_namespaceObject = require("@octanejs/tanstack-router/ssr/server");
37
+ const external_octane_server_namespaceObject = require("octane/server");
37
38
  const external_bootstrap_js_namespaceObject = require("./bootstrap.js");
38
39
  const external_federation_context_js_namespaceObject = require("./federation-context.js");
39
40
  function prepareOctaneDocument(session, document, hydrating) {
@@ -99,7 +100,7 @@ async function renderOctaneApplication(input) {
99
100
  const { session, document } = input;
100
101
  try {
101
102
  const { rootId, lang, bootstrap, headAssets, entryScripts } = prepareOctaneDocument(session, document, true);
102
- const earlyBootstrap = (0, server_namespaceObject.earlySignalBootstrapScript)(void 0 === document.nonce ? {} : {
103
+ const earlyBootstrap = (0, external_octane_server_namespaceObject.earlySignalBootstrapScript)(void 0 === document.nonce ? {} : {
103
104
  nonce: document.nonce
104
105
  });
105
106
  await resolveDocumentResponse(input);
@@ -107,11 +108,11 @@ async function renderOctaneApplication(input) {
107
108
  session.startRendering();
108
109
  let head = '';
109
110
  const federation = input.federation ? (0, external_federation_context_js_namespaceObject.createFederationScope)(input.federation, true, document.nonce) : void 0;
110
- const App = federation ? ()=>(0, server_namespaceObject.createElement)(external_federation_context_js_namespaceObject.FederationRoot, {
111
+ const App = federation ? ()=>(0, external_octane_server_namespaceObject.createElement)(external_federation_context_js_namespaceObject.FederationRoot, {
111
112
  scope: federation,
112
- children: 'function' == typeof input.App ? (0, server_namespaceObject.createElement)(input.App, input.props) : input.App
113
+ children: 'function' == typeof input.App ? (0, external_octane_server_namespaceObject.createElement)(input.App, input.props) : input.App
113
114
  }) : input.App;
114
- const nativeStream = await (0, server_namespaceObject.renderToReadableStream)(App, input.props, {
115
+ const nativeStream = await (0, external_octane_server_namespaceObject.renderToReadableStream)(App, input.props, {
115
116
  signal: session.signal,
116
117
  ...void 0 === document.nonce ? {} : {
117
118
  nonce: document.nonce
@@ -207,7 +208,14 @@ async function renderOctaneApplication(input) {
207
208
  }, {
208
209
  highWaterMark: 0
209
210
  });
210
- return session.respond(body);
211
+ return session.respond(input.router ? (0, server_namespaceObject.transformReadableStreamWithRouter)(input.router, body, {
212
+ signal: session.signal,
213
+ rendererSafePoint: "script-close",
214
+ timeoutMs: input.routerSerializationTimeoutMs,
215
+ onAbort: (reason)=>{
216
+ session.fail(reason);
217
+ }
218
+ }) : body);
211
219
  } catch (error) {
212
220
  await session.fail(error);
213
221
  throw error;
@@ -3,7 +3,7 @@ import { createNativeServerEntry } from "@modern-js/renderer-core/entry-server";
3
3
  import { createNativeRouter } from "@modern-js/renderer-core/router";
4
4
  import { componentView, localizedRouterRoot, octaneRouterFactory } from "./entry-application.mjs";
5
5
  import { validateOctaneModuleManifest } from "./manifest.mjs";
6
- import { OctaneRouterServer, createOctaneRequestHandler, createOctaneRouterInjection, createSsrStreamResponse } from "./router-server.mjs";
6
+ import { OctaneRouterServer, createOctaneRequestHandler, createSsrStreamResponse, getSsrStatus } from "./router-server.mjs";
7
7
  import { renderOctaneApplication, renderOctaneCSRDocument } from "./server.mjs";
8
8
  const OCTANE_DOCUMENT_FIELDS = new Set([
9
9
  'content-language',
@@ -50,7 +50,7 @@ function entry_server_createNativeServerEntry(options) {
50
50
  }
51
51
  })(async ({ router, responseHeaders })=>{
52
52
  const metadata = mergeDataResponseMetadata(outcomes, {
53
- status: router.state.statusCode ?? 200
53
+ status: getSsrStatus(router)
54
54
  });
55
55
  const policy = dataMetadataToDocumentPolicy({
56
56
  ...metadata,
@@ -73,7 +73,7 @@ function entry_server_createNativeServerEntry(options) {
73
73
  },
74
74
  document,
75
75
  federation: options.federation,
76
- injection: createOctaneRouterInjection(router, session)
76
+ router
77
77
  });
78
78
  return createSsrStreamResponse(router, rendered);
79
79
  });
@@ -1,20 +1,12 @@
1
- import { createElement, hookSlots, useEffect, useState } from "octane";
1
+ import { createElement, hookSlots, useSyncExternalStore } from "octane";
2
2
  import { I18nContext } from "./context.mjs";
3
- const languageStateSlot = Symbol(hookSlots(1));
4
- const languageSubscriptionSlot = Symbol(hookSlots(1));
3
+ const languageStoreSlot = Symbol(hookSlots(1));
5
4
  function I18nProvider(props) {
6
- const [language, setLanguage] = useState(()=>props.instance.language, languageStateSlot);
7
- useEffect(()=>{
8
- const instance = props.instance;
9
- setLanguage(instance.language);
10
- const handleLanguageChanged = (lng)=>setLanguage(lng);
11
- instance.on?.('languageChanged', handleLanguageChanged);
12
- return ()=>{
13
- instance.off?.('languageChanged', handleLanguageChanged);
14
- };
15
- }, [
16
- props.instance
17
- ], languageSubscriptionSlot);
5
+ const instance = props.instance;
6
+ const language = useSyncExternalStore((notify)=>{
7
+ instance.on?.('languageChanged', notify);
8
+ return ()=>instance.off?.('languageChanged', notify);
9
+ }, ()=>instance.language, ()=>instance.language, languageStoreSlot);
18
10
  const value = {
19
11
  instance: props.instance,
20
12
  languages: props.languages,
@@ -1,8 +1,8 @@
1
1
  const OCTANE_RUNTIME_PROFILE = Object.freeze({
2
2
  renderer: 'octane',
3
- runtime: '0.7.1+ultramodern.1331985ea3b0',
4
- router: '0.1.60+ultramodern.0b9f76ee3003',
5
- routerCore: '1.171.15',
6
- history: '1.162.0'
3
+ runtime: '0.13.8',
4
+ router: '0.2.10',
5
+ routerCore: '1.171.34',
6
+ history: '1.162.4'
7
7
  });
8
8
  export { OCTANE_RUNTIME_PROFILE };
@@ -1,7 +1,7 @@
1
1
  import { nativeModuleManifestFilename, readRendererIdentity } from "@modern-js/renderer-core/identity";
2
2
  import { assertNativeHydrationBuildId, assertOctaneIdentity } from "./bootstrap.mjs";
3
- const OCTANE_RUNTIME_VERSION = '0.7.1+ultramodern.1331985ea3b0';
4
- const OCTANE_COMPILER_VERSION = '0.1.55';
3
+ const OCTANE_RUNTIME_VERSION = '0.13.8';
4
+ const OCTANE_COMPILER_VERSION = '0.2.4';
5
5
  function octaneModuleManifestFileName(entryName) {
6
6
  return nativeModuleManifestFilename('octane', entryName);
7
7
  }
@@ -31,7 +31,7 @@ function isReactiveMatchIds(value) {
31
31
  }
32
32
  function waitForCommittedMatches(router, signal) {
33
33
  signal?.throwIfAborted();
34
- const matchesId = router.stores.matchesId;
34
+ const matchesId = router.stores.ids;
35
35
  if (matchesId.get().length > 0) return Promise.resolve();
36
36
  if (!isReactiveMatchIds(matchesId)) throw new Error('Octane router hydration requires its native reactive match store');
37
37
  return new Promise((resolve, reject)=>{
@@ -52,8 +52,8 @@ function requestHeaders(router) {
52
52
  if (field?.get || field?.set) throw new TypeError('Native Octane response headers must be owned values');
53
53
  appendHeaders(headers, field?.value);
54
54
  }
55
- const redirect = router.stores.redirect.get();
56
- if (redirect) appendHeaders(headers, redirect.headers);
55
+ const result = router._serverResult;
56
+ if (result?.type === 'redirect') appendHeaders(headers, result.redirect.headers);
57
57
  return headers;
58
58
  }
59
59
  function createOctaneRequestHandler({ createRouter, request, session, getRouterManifest, serialization }) {
@@ -74,7 +74,6 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
74
74
  ...serialization?.forbiddenValues ?? []
75
75
  ]
76
76
  });
77
- session.registerCleanup(()=>router.cancelMatches());
78
77
  const { url } = getNormalizedURL(request.url, 'http://localhost');
79
78
  const href = url.href.replace(url.origin, '');
80
79
  router.update({
@@ -86,11 +85,13 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
86
85
  }),
87
86
  origin: router.options.origin ?? getOrigin(request)
88
87
  });
89
- await withAbort(router.load(), session.signal);
88
+ await withAbort(router.load({
89
+ _signal: session.signal
90
+ }), session.signal);
90
91
  guard.assertActive();
91
- const redirect = router.stores.redirect.get();
92
- if (redirect) {
93
- const resolved = router.resolveRedirect(redirect);
92
+ const loadResult = router._serverResult;
93
+ if (loadResult?.type === 'redirect') {
94
+ const resolved = loadResult.redirect;
94
95
  const headers = requestHeaders(router);
95
96
  return new Response(null, {
96
97
  status: resolved.status,
@@ -101,7 +102,9 @@ function createOctaneRequestHandler({ createRouter, request, session, getRouterM
101
102
  guard.assertMatches();
102
103
  const serverSsr = router.serverSsr;
103
104
  if (!serverSsr) throw new Error('Native Octane router SSR state is required');
104
- await withAbort(serverSsr.dehydrate(), session.signal);
105
+ await withAbort(serverSsr.dehydrate({
106
+ signal: session.signal
107
+ }), session.signal);
105
108
  guard.assertActive();
106
109
  const responseHeaders = requestHeaders(router);
107
110
  const rendered = Promise.resolve(callback({
@@ -7,6 +7,5 @@ function OctaneRouterServer({ router }) {
7
7
  });
8
8
  }
9
9
  export { createOctaneRequestHandler } from "./router-handler.mjs";
10
- export { createOctaneRouterInjection } from "./router-injection.mjs";
11
10
  export { prepareOctaneRouterSerialization } from "./router-server-snapshot.mjs";
12
11
  export { OctaneRouterServer };
@@ -1,6 +1,6 @@
1
1
  import { createDataClient } from "@modern-js/renderer-core/data";
2
2
  import { RouterProvider, createRouter, redirect, useMatch, useRouter } from "@octanejs/tanstack-router";
3
- import { createSubSlot, useCallback, useEffect, useRef } from "octane";
3
+ import { createSubSlot, useCallback, useLayoutEffect, useRef } from "octane";
4
4
  import { assertOctaneIdentity } from "./bootstrap.mjs";
5
5
  import { RouteDataError, createFileSystemRouteTree, matchApplicationRouteIds, matchApplicationRoutes, resolveRouteData, selectApplicationDataRoute } from "./routes.mjs";
6
6
  export * from "@octanejs/tanstack-router";
@@ -69,7 +69,7 @@ function useOctaneRouteAction(...args) {
69
69
  const identity = useApplicationIdentity();
70
70
  const routeId = useApplicationRouteId();
71
71
  const owner = useRef(null, actionSlot(slot, 'owner'));
72
- useEffect(()=>{
72
+ useLayoutEffect(()=>{
73
73
  const controller = new AbortController();
74
74
  owner.current = controller;
75
75
  return ()=>controller.abort(new DOMException('The route action owner unmounted', 'AbortError'));
@@ -10,21 +10,12 @@ function routes_resolveRouteData(routeId, outcome) {
10
10
  function isReactiveNativeMatch(value) {
11
11
  return 'object' == typeof value && null !== value && 'function' == typeof Reflect.get(value, 'get') && 'function' == typeof Reflect.get(value, 'subscribe');
12
12
  }
13
- function observeRouteCompletion(router, controller, signal, completion) {
13
+ function observeRouteCompletion(router, routeId, controller, signal, completion) {
14
14
  completion.catch((error)=>{
15
15
  if (signal.aborted) return;
16
- const match = [
17
- ...router.stores.pendingMatches.get(),
18
- ...router.stores.matches.get(),
19
- ...router.stores.cachedMatches.get()
20
- ].find((candidate)=>candidate.abortController === controller);
21
- if (!match) return;
22
- const store = [
23
- router.stores.pendingMatchStores.get(match.id),
24
- router.stores.matchStores.get(match.id),
25
- router.stores.cachedMatchStores.get(match.id)
26
- ].find((candidate)=>candidate?.get().abortController === controller);
27
- if (!store) return;
16
+ const route = Object.values(router.routesById).find((candidate)=>candidate.options.staticData?.ultramodernRouteId === routeId);
17
+ if (!route) return;
18
+ const store = router.stores.getMatchStore(route.id);
28
19
  let subscription;
29
20
  let settled = false;
30
21
  const cleanup = ()=>{
@@ -35,9 +26,10 @@ function observeRouteCompletion(router, controller, signal, completion) {
35
26
  settled = true;
36
27
  cleanup();
37
28
  };
38
- const publish = ()=>{
29
+ const publish = async ()=>{
39
30
  if (settled) return;
40
31
  const current = store.get();
32
+ if (!current) return;
41
33
  if (current.abortController !== controller || signal.aborted || 'pending' !== current.status && 'success' !== current.status) return void onAbort();
42
34
  if ('success' !== current.status || current.isFetching) return;
43
35
  settled = true;
@@ -45,17 +37,19 @@ function observeRouteCompletion(router, controller, signal, completion) {
45
37
  const route = router.routesById[current.routeId];
46
38
  let failure = error;
47
39
  try {
40
+ await route?.options.errorComponent?.preload?.();
41
+ if (signal.aborted || store.get()?.abortController !== controller) return;
48
42
  route?.options.onError?.(failure);
49
43
  } catch (onErrorFailure) {
50
44
  failure = onErrorFailure;
51
45
  }
52
46
  if (signal.aborted) return;
53
- router.updateMatch(match.id, (previous)=>previous.abortController !== controller || 'success' !== previous.status || previous.isFetching ? previous : {
47
+ router.stores.setMatches(router.stores.matches.get().map((previous)=>previous.routeId !== route.id || previous.abortController !== controller || 'success' !== previous.status || previous.isFetching ? previous : {
54
48
  ...previous,
55
49
  error: failure,
56
50
  status: 'error',
57
51
  isFetching: false
58
- });
52
+ }));
59
53
  };
60
54
  signal.addEventListener('abort', onAbort, {
61
55
  once: true
@@ -99,7 +93,7 @@ function createFileSystemRouteTree(routes, modules, options = {}) {
99
93
  await Promise.resolve();
100
94
  signal.throwIfAborted();
101
95
  if (failed) throw failure;
102
- observeRouteCompletion(router, match.abortController, signal, outcome.completion);
96
+ observeRouteCompletion(router, route.id, match.abortController, signal, outcome.completion);
103
97
  }
104
98
  options.onOutcome?.(route.id, outcome);
105
99
  return routes_resolveRouteData(route.id, outcome);