@stone-js/use-react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,13 +1,11 @@
1
- import { isNotEmpty, isEmpty, InitializationError, isMetaClassModule, isMetaFactoryModule, isFunctionModule, isObjectLikeModule, isFunction, Logger, hasMetadata, getMetadata, isMatchedAdapter, mergeBlueprints, stoneBlueprint, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, addBlueprint } from '@stone-js/core';
1
+ import { isNotEmpty, isEmpty, InitializationError, isMetaClassModule, isMetaFactoryModule, isFunctionModule, isObjectLikeModule, isFunction, mergeBlueprints, stoneBlueprint, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, hasMetadata, getMetadata, isMatchedAdapter, Logger, addBlueprint } from '@stone-js/core';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { renderToString } from 'react-dom/server';
4
- import { createContext, StrictMode, useContext, useState, useEffect } from 'react';
4
+ import { createContext, StrictMode, useState, useEffect, useContext } from 'react';
5
5
  import { createRoot, hydrateRoot } from 'react-dom/client';
6
- import { OutgoingHttpResponse, RedirectResponse, MetaStaticFileMiddleware, MetaCompressionMiddleware } from '@stone-js/http-core';
7
- import { OutgoingBrowserResponse, RedirectBrowserResponse } from '@stone-js/browser-core';
8
6
  import { Config } from '@stone-js/config';
9
- import { GET, NAVIGATION_EVENT, NODE_CONSOLE_PLATFORM, Router, RouteEvent } from '@stone-js/router';
10
- import { BROWSER_PLATFORM } from '@stone-js/browser-adapter';
7
+ import { GET, NODE_CONSOLE_PLATFORM, Router, RouteEvent } from '@stone-js/router';
8
+ import { OutgoingHttpResponse, RedirectResponse, MetaStaticFileMiddleware, MetaCompressionMiddleware } from '@stone-js/http-core';
11
9
 
12
10
  /**
13
11
  * Stone DOM Attribute.
@@ -486,7 +484,7 @@ const htmlTemplate = (blueprint) => {
486
484
  * @returns True if the application is running on the server side, false otherwise.
487
485
  */
488
486
  function isSSR() {
489
- return import.meta.env.SSR || typeof window === 'undefined';
487
+ return typeof window === 'undefined';
490
488
  }
491
489
  /**
492
490
  * Execute the handler.
@@ -552,11 +550,11 @@ function getBrowserContent(app, component, layout, snapshot, head) {
552
550
  * @param container - The service container.
553
551
  * @param event - The incoming browser event.
554
552
  * @param head - The head context.
555
- * @returns A promise that resolves when the content is hydrated.
553
+ * @returns The server response content as a string.
556
554
  */
557
- async function getServerContent(component, data, container, event, head) {
555
+ function getServerContent(component, data, container, event, head) {
558
556
  const html = renderToString(component).concat('\n<!--app-html-->');
559
- const template = await htmlTemplate(container.make('blueprint'));
557
+ const template = htmlTemplate(container.make('blueprint'));
560
558
  const snapshot = snapshotResponse(event, container, data).concat('\n<!--app-head-->');
561
559
  return applyHeadContextToHtmlString(head ?? {}, template)
562
560
  .replace('<!--app-html-->', html)
@@ -712,49 +710,6 @@ class ReactRuntime {
712
710
  */
713
711
  const MetaReactRuntime = { module: ReactRuntime, isClass: true, alias: 'reactRuntime', singleton: true };
714
712
 
715
- /**
716
- * Class representing an UseReactBrowserErrorHandler.
717
- *
718
- * Adapter level error handler for React applications.
719
- */
720
- class UseReactBrowserErrorHandler {
721
- logger;
722
- blueprint;
723
- /**
724
- * Create an UseReactBrowserErrorHandler.
725
- *
726
- * @param options - UseReactBrowserErrorHandler options.
727
- */
728
- constructor({ blueprint }) {
729
- this.blueprint = blueprint;
730
- this.logger = Logger.getInstance();
731
- }
732
- /**
733
- * Handle an error.
734
- *
735
- * @param error - The error to handle.
736
- * @param context - The context of the adapter.
737
- * @returns The raw response.
738
- */
739
- async handle(error, context) {
740
- this.logger.error(error.message, { error });
741
- return context
742
- .rawResponseBuilder
743
- .add('render', async () => await this.renderError(error, context));
744
- }
745
- /**
746
- * Get the error body.
747
- *
748
- * @param error - The error to handle.
749
- * @returns The error body.
750
- */
751
- async renderError(error, context) {
752
- const app = await buildAdapterErrorComponent(this.blueprint, context, error.statusCode ?? 500, error);
753
- // Render the component
754
- renderReactApp(app, this.blueprint);
755
- }
756
- }
757
-
758
713
  /**
759
714
  * A useReact event handler for processing incoming events
760
715
  * For single event handler.
@@ -797,6 +752,34 @@ class UseReactEventHandler {
797
752
  }
798
753
  }
799
754
 
755
+ /**
756
+ * Class representing an UseReactUseReactKernelErrorHandler.
757
+ *
758
+ * Kernel level error handler for React applications.
759
+ */
760
+ class UseReactKernelErrorHandler {
761
+ blueprint;
762
+ /**
763
+ * Create an UseReactUseReactKernelErrorHandler.
764
+ *
765
+ * @param options - UseReactUseReactKernelErrorHandler options.
766
+ */
767
+ constructor({ blueprint }) {
768
+ this.blueprint = blueprint;
769
+ }
770
+ /**
771
+ * Handle an error.
772
+ *
773
+ * @param error - The error to handle.
774
+ * @returns The outgoing http response.
775
+ */
776
+ handle(error) {
777
+ const metavalue = this.blueprint.get(`stone.useReact.errorPages.${String(error?.name)}`) ??
778
+ this.blueprint.get('stone.useReact.errorPages.default', {});
779
+ return { content: { ...metavalue, error }, statusCode: error?.statusCode ?? 500 };
780
+ }
781
+ }
782
+
800
783
  /**
801
784
  * Prepare the page to render.
802
785
  *
@@ -819,7 +802,7 @@ async function preparePage(event, response, container, snapshot) {
819
802
  const component = await buildPageComponent(event, container, componentType, data, response.statusCode);
820
803
  const appComponent = await buildAppComponent(event, container, componentType, layout, data, response.statusCode);
821
804
  response.setContent(isSSR()
822
- ? await getServerContent(appComponent, snapshotData, container, event, head)
805
+ ? getServerContent(appComponent, snapshotData, container, event, head)
823
806
  : getBrowserContent(appComponent, component, layout, snapshot, head));
824
807
  }
825
808
  /**
@@ -845,7 +828,7 @@ async function prepareErrorPage(event, response, container, snapshot) {
845
828
  const component = await buildPageComponent(event, container, componentType, data, response.statusCode, error);
846
829
  const appComponent = await buildAppComponent(event, container, componentType, layout, data, response.statusCode, error);
847
830
  response.setContent(isSSR()
848
- ? await getServerContent(appComponent, snapshotData, container, event, head)
831
+ ? getServerContent(appComponent, snapshotData, container, event, head)
849
832
  : getBrowserContent(appComponent, component, layout, snapshot, head));
850
833
  }
851
834
  /**
@@ -888,108 +871,6 @@ async function onPreparingResponse({ event, response, container }) {
888
871
  }
889
872
  }
890
873
 
891
- /**
892
- * Class representing an UseReactUseReactKernelErrorHandler.
893
- *
894
- * Kernel level error handler for React applications.
895
- */
896
- class UseReactKernelErrorHandler {
897
- blueprint;
898
- /**
899
- * Create an UseReactUseReactKernelErrorHandler.
900
- *
901
- * @param options - UseReactUseReactKernelErrorHandler options.
902
- */
903
- constructor({ blueprint }) {
904
- this.blueprint = blueprint;
905
- }
906
- /**
907
- * Handle an error.
908
- *
909
- * @param error - The error to handle.
910
- * @returns The outgoing http response.
911
- */
912
- handle(error) {
913
- const metavalue = this.blueprint.get(`stone.useReact.errorPages.${String(error?.name)}`) ??
914
- this.blueprint.get('stone.useReact.errorPages.default', {});
915
- return { content: { ...metavalue, error }, statusCode: error?.statusCode ?? 500 };
916
- }
917
- }
918
-
919
- /**
920
- * Create an UseReact response.
921
- *
922
- * @param options - The options for creating the response.
923
- * @returns The React response.
924
- */
925
- const reactResponse = async (options) => {
926
- if (isNotEmpty(options) &&
927
- (isNotEmpty(options.url) ||
928
- (isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
929
- return await reactRedirectResponse(options);
930
- }
931
- return import.meta.env.SSR
932
- ? OutgoingHttpResponse.create(options)
933
- : OutgoingBrowserResponse.create(options);
934
- };
935
- /**
936
- * Create an UseReact redirect response.
937
- *
938
- * @param options - The options for creating the response.
939
- * @returns The React redirect response.
940
- */
941
- const reactRedirectResponse = async (options) => {
942
- return import.meta.env.SSR
943
- ? RedirectResponse.create({ statusCode: 302, ...options })
944
- : RedirectBrowserResponse.create({ statusCode: 302, ...options });
945
- };
946
-
947
- /**
948
- * Class representing an UseReactServerErrorHandler.
949
- *
950
- * Adapter level error handler for React applications.
951
- */
952
- class UseReactServerErrorHandler {
953
- logger;
954
- blueprint;
955
- /**
956
- * Create an UseReactServerErrorHandler.
957
- *
958
- * @param options - UseReactServerErrorHandler options.
959
- */
960
- constructor({ blueprint }) {
961
- this.blueprint = blueprint;
962
- this.logger = Logger.getInstance();
963
- }
964
- /**
965
- * Handle an error.
966
- *
967
- * @param error - The error to handle.
968
- * @param context - The context of the adapter.
969
- * @returns The raw response.
970
- */
971
- async handle(error, context) {
972
- this.logger.error(error.message, { error });
973
- return context
974
- .rawResponseBuilder
975
- .add('statusCode', error.statusCode ?? 500)
976
- .add('headers', new Headers({ 'Content-Type': 'text/html' }))
977
- .add('body', await this.getErrorBody(error, context));
978
- }
979
- /**
980
- * Get the error body.
981
- *
982
- * @param error - The error to handle.
983
- * @returns The error body.
984
- */
985
- async getErrorBody(error, context) {
986
- const statusCode = error.statusCode ?? 500;
987
- const template = await htmlTemplate(this.blueprint);
988
- const ClientApp = await buildAdapterErrorComponent(this.blueprint, context, statusCode, error);
989
- return template.replace('<!--app-html-->', renderToString(ClientApp));
990
- }
991
- }
992
-
993
874
  /**
994
875
  * Use React Service Provider.
995
876
  */
@@ -1058,6 +939,60 @@ function defineAdapterErrorPage(module, options) {
1058
939
  };
1059
940
  }
1060
941
 
942
+ /**
943
+ * Default blueprint for a React-based Stone.js application.
944
+ *
945
+ * - Defines middleware, lifecycle hooks, and the default HTML template path.
946
+ */
947
+ const internalUseReactBlueprint = {
948
+ stone: {
949
+ useReact: {},
950
+ services: [MetaReactRuntime],
951
+ providers: [MetaUseReactServiceProvider]
952
+ }
953
+ };
954
+
955
+ /**
956
+ * Defines a Stone React app using a factory-based or class-based main handler.
957
+ *
958
+ * @param moduleOrOptions - A factory function or class constructor for the main page.
959
+ * @param optionsOrBlueprints - Optional application-level configuration.
960
+ * @param maybeBlueprints - Additional blueprints to merge.
961
+ * @returns A fully merged Stone blueprint.
962
+ */
963
+ function defineStoneReactApp(moduleOrOptions = {}, optionsOrBlueprints, maybeBlueprints) {
964
+ let module;
965
+ let options = {};
966
+ let blueprints = [];
967
+ // Pattern: defineStoneReactApp(handler, options?, blueprints?)
968
+ if (isFunctionModule(moduleOrOptions)) {
969
+ module = moduleOrOptions;
970
+ if (isObjectLikeModule(optionsOrBlueprints)) {
971
+ options = optionsOrBlueprints;
972
+ blueprints = Array.isArray(maybeBlueprints) ? maybeBlueprints : [];
973
+ }
974
+ }
975
+ else if (isObjectLikeModule(moduleOrOptions)) { // Pattern: defineStoneReactApp(options, blueprints?)
976
+ options = moduleOrOptions;
977
+ blueprints = Array.isArray(optionsOrBlueprints) ? optionsOrBlueprints : [];
978
+ }
979
+ const stonePart = {
980
+ ...options,
981
+ useReact: {
982
+ ...options.useReact
983
+ }
984
+ };
985
+ if (isNotEmpty(module)) {
986
+ stonePart.useReact.componentEventHandler = {
987
+ module,
988
+ isComponent: true,
989
+ isClass: options.isClass,
990
+ isFactory: options.isClass !== true
991
+ };
992
+ }
993
+ return mergeBlueprints(stoneBlueprint, internalUseReactBlueprint, ...blueprints, { stone: stonePart });
994
+ }
995
+
1061
996
  /**
1062
997
  * Utility function to define a page.
1063
998
  *
@@ -1164,136 +1099,194 @@ const REACT_ADAPTER_ERROR_PAGE_KEY = Symbol.for('ReactAdapterErrorPage');
1164
1099
  const STONE_REACT_APP_KEY = Symbol.for('StoneReactApp');
1165
1100
 
1166
1101
  /**
1167
- * Adapter Middleware for handling outgoing responses and rendering them in the browser.
1102
+ * A class decorator for defining a class as a React Handler layout.
1103
+ *
1104
+ * @param options - Configuration options for the layout definition.
1105
+ * @returns A method decorator to be applied to a class method.
1106
+ *
1107
+ * @example
1108
+ * ```typescript
1109
+ * import { AdapterErrorPage } from '@stone-js/use-react';
1110
+ *
1111
+ * @AdapterErrorPage({ error: 'UserNotFoundError' })
1112
+ * class UserAdapterErrorPage {
1113
+ * render({ error }) {
1114
+ * return <h1>User name: {error.message}</h1>;
1115
+ * }
1116
+ * }
1117
+ * ```
1168
1118
  */
1169
- class BrowserResponseMiddleware {
1170
- isRendered;
1171
- blueprint;
1172
- /**
1173
- * Create a BrowserResponseMiddleware.
1174
- *
1175
- * @param {blueprint} options - Options for creating the BrowserResponseMiddleware.
1176
- */
1177
- constructor({ blueprint }) {
1178
- this.blueprint = blueprint;
1179
- this.isRendered = blueprint.has('stone.useReact.reactRoot');
1180
- }
1181
- /**
1182
- * Handles the outgoing response, processes it, and invokes the next middleware in the pipeline.
1183
- *
1184
- * @param context - The adapter context containing the raw event, execution context, and other data.
1185
- * @param next - The next middleware to be invoked in the pipeline.
1186
- * @returns A promise resolving to the processed context.
1187
- * @throws {NodeHttpAdapterError} If required components are missing in the context.
1188
- */
1189
- async handle(context, next) {
1190
- const rawResponseBuilder = await next(context);
1191
- this.ensureValidContext(context, rawResponseBuilder);
1192
- return rawResponseBuilder.add('render', async () => await this.renderComponent(context.outgoingResponse));
1193
- }
1194
- /**
1195
- * Ensures the context and response builder have the required components.
1196
- */
1197
- ensureValidContext(context, rawResponseBuilder) {
1198
- if (context.rawEvent === undefined ||
1199
- context.incomingEvent === undefined ||
1200
- context.outgoingResponse === undefined ||
1201
- rawResponseBuilder?.add === undefined) {
1202
- throw new UseReactError('The context is missing required components.');
1203
- }
1204
- }
1205
- /**
1206
- * Renders the provided React content.
1207
- *
1208
- * @param response - The response object.
1209
- */
1210
- async renderComponent(response) {
1211
- if (isEmpty(response)) {
1212
- throw new UseReactError('No response provided for rendering.');
1213
- }
1214
- const content = response.content;
1215
- const targetUrl = response.targetUrl;
1216
- if (isNotEmpty(targetUrl)) {
1217
- return this.handleRedirect(targetUrl);
1218
- }
1219
- if (isNotEmpty(content?.head)) {
1220
- applyHeadContextToDom(document, content.head);
1221
- }
1222
- if (content?.ssr === true && !this.isRendered && isNotEmpty(content?.app)) {
1223
- return this.hydrateReactApp(content.app);
1224
- }
1225
- if (isNotEmpty(content?.app) && (!this.isRendered || content?.fullRender === true)) {
1226
- return this.renderReactApp(content.app);
1227
- }
1228
- if (isNotEmpty(content?.component)) {
1229
- return await this.dispatchComponentToOutlet(content.component);
1230
- }
1231
- throw new UseReactError('Invalid content provided for rendering.');
1232
- }
1233
- /**
1234
- * Handles navigation redirection.
1235
- *
1236
- * @param path - The path to redirect to.
1237
- */
1238
- handleRedirect(path) {
1239
- window.history.pushState({ path }, '', path);
1240
- window.dispatchEvent(new Event(NAVIGATION_EVENT));
1241
- }
1242
- /**
1243
- * Hydrates the React app when SSR is enabled.
1244
- *
1245
- * @param app - The React app to hydrate.
1246
- */
1247
- hydrateReactApp(app) {
1248
- hydrateReactApp(app, this.blueprint);
1249
- }
1250
- /**
1251
- * Renders the React app.
1252
- *
1253
- * @param app - The React app to render.
1254
- */
1255
- renderReactApp(app) {
1256
- renderReactApp(app, this.blueprint);
1257
- }
1258
- /**
1259
- * Dispatches a component to the layout outlet when no layout is defined.
1260
- *
1261
- * @param component - The component to dispatch.
1262
- */
1263
- async dispatchComponentToOutlet(component) {
1264
- window.dispatchEvent(new CustomEvent(STONE_PAGE_EVENT_OUTLET, { detail: component }));
1265
- }
1266
- }
1119
+ const AdapterErrorPage = (options) => {
1120
+ return classDecoratorLegacyWrapper((_target, context) => {
1121
+ setMetadata(context, REACT_ADAPTER_ERROR_PAGE_KEY, { ...options, isClass: true });
1122
+ });
1123
+ };
1124
+
1267
1125
  /**
1268
- * Meta Middleware for processing browser responses.
1126
+ * A class decorator for defining a class as a React Handler layout.
1127
+ *
1128
+ * @param options - Configuration options for the layout definition.
1129
+ * @returns A method decorator to be applied to a class method.
1130
+ *
1131
+ * @example
1132
+ * ```typescript
1133
+ * import { ErrorPage } from '@stone-js/use-react';
1134
+ *
1135
+ * @ErrorPage({ error: 'UserNotFoundError' })
1136
+ * class UserErrorPage {
1137
+ * render({ error }) {
1138
+ * return <h1>User name: {error.message}</h1>;
1139
+ * }
1140
+ * }
1141
+ * ```
1269
1142
  */
1270
- const MetaBrowserResponseMiddleware = { module: BrowserResponseMiddleware, isClass: true };
1143
+ const ErrorPage = (options) => {
1144
+ return classDecoratorLegacyWrapper((_target, context) => {
1145
+ setMetadata(context, REACT_ERROR_PAGE_KEY, { ...options, isClass: true });
1146
+ });
1147
+ };
1271
1148
 
1272
1149
  /**
1273
- * Blueprint middleware to dynamically set lifecycle hooks for react.
1150
+ * A class decorator for defining a class as a React Page route action.
1151
+ * Uses the `Match` decorator internally to register the route with the HTTP `GET` method.
1274
1152
  *
1275
- * @param context - The configuration context containing modules and blueprint.
1276
- * @param next - The next pipeline function to continue processing.
1277
- * @returns The updated blueprint or a promise resolving to it.
1153
+ * @param options - Configuration options for the route definition, excluding the `methods` property.
1154
+ * @returns A method decorator to be applied to a class method.
1278
1155
  *
1279
1156
  * @example
1280
1157
  * ```typescript
1281
- * SetUseReactHooksMiddleware(context, next)
1158
+ * import { Page } from '@stone-js/use-react';
1159
+ *
1160
+ * @Page('/user-profile')
1161
+ * class UserPage {
1162
+ * handle({ event }): Record<string, string> {
1163
+ * return { name: 'Jane Doe' };
1164
+ * }
1165
+ *
1166
+ * render({ data }) {
1167
+ * return <h1>User name: {data.name}</h1>;
1168
+ * }
1169
+ * }
1282
1170
  * ```
1283
1171
  */
1284
- const SetUseReactHooksMiddleware = (context, next) => {
1285
- if (context.blueprint.get('stone.adapter.platform') !== NODE_CONSOLE_PLATFORM) {
1286
- context
1287
- .blueprint
1288
- .add('stone.lifecycleHooks.onPreparingResponse', [onPreparingResponse]);
1289
- }
1290
- return next(context);
1172
+ const Page = (path, options = {}) => {
1173
+ return classDecoratorLegacyWrapper((target, context) => {
1174
+ setMetadata(context, REACT_PAGE_KEY, {
1175
+ ...options,
1176
+ path,
1177
+ method: GET,
1178
+ methods: [],
1179
+ handler: { isClass: true, isComponent: true, layout: options.layout, module: target }
1180
+ });
1181
+ });
1182
+ };
1183
+
1184
+ /**
1185
+ * A class decorator for defining a class as a React Page layout.
1186
+ *
1187
+ * @param options - Configuration options for the layout definition.
1188
+ * @returns A method decorator to be applied to a class method.
1189
+ *
1190
+ * @example
1191
+ * ```typescript
1192
+ * import { PageLayout } from '@stone-js/use-react';
1193
+ *
1194
+ * @PageLayout({ name: 'UserPageLayout' })
1195
+ * class UserPageLayout {
1196
+ * render({ data }) {
1197
+ * return <h1>User name: {data.name}</h1>;
1198
+ * }
1199
+ * }
1200
+ * ```
1201
+ */
1202
+ const PageLayout = (options) => {
1203
+ return classDecoratorLegacyWrapper((_target, context) => {
1204
+ setMetadata(context, REACT_PAGE_LAYOUT_KEY, { ...options, isClass: true });
1205
+ });
1206
+ };
1207
+
1208
+ /**
1209
+ * Hook decorator to mark a method as a lifecycle hook
1210
+ * And automatically add it to the global lifecycle hook registry.
1211
+ *
1212
+ * @example
1213
+ * ```typescript
1214
+ * class MyClass {
1215
+ * // ...
1216
+ * @Hook('onPreparingPage')
1217
+ * onPreparingPage () {}
1218
+ * }
1219
+ * ```
1220
+ *
1221
+ * @param name - The name of the lifecycle hook.
1222
+ * @returns A class decorator function that sets the metadata using the provided options.
1223
+ */
1224
+ const Hook = (name) => {
1225
+ return methodDecoratorLegacyWrapper((_target, context) => {
1226
+ addMetadata(context, LIFECYCLE_HOOK_KEY, { name, method: context.name });
1227
+ });
1228
+ };
1229
+
1230
+ /**
1231
+ * Decorator to set the status code of the response.
1232
+ *
1233
+ * @param statusCode - The status code of the response.
1234
+ * @param headers - The headers for the response.
1235
+ * @returns A method decorator.
1236
+ *
1237
+ * @example
1238
+ * ```typescript
1239
+ * import { Page, PageStatus } from '@stone-js/use-react';
1240
+ *
1241
+ * @Page('/user-profile')
1242
+ * class UserPage {
1243
+ * @PageStatus()
1244
+ * handle() {
1245
+ * return { name: 'John Doe' };
1246
+ * }
1247
+ * }
1248
+ * ```
1249
+ */
1250
+ const PageStatus = (statusCode = 200, headers = {}) => {
1251
+ return methodDecoratorLegacyWrapper((target, _context) => {
1252
+ return async function (...args) {
1253
+ const content = await target.apply(this, args);
1254
+ return { content, statusCode, headers };
1255
+ };
1256
+ });
1291
1257
  };
1258
+
1292
1259
  /**
1293
- * Blueprint middleware to set BrowserResponseMiddleware for the Browser adapter.
1260
+ * Decorator to create a snapshot of the current data.
1261
+ *
1262
+ * @param name - The name of the snapshot.
1263
+ * @returns A method decorator.
1264
+ *
1265
+ * @example
1266
+ * ```typescript
1267
+ * import { Service } from '@stone-js/core';
1268
+ * import { Snapshot } from '@stone-js/use-react';
1294
1269
  *
1295
- * The MetaBrowserResponseMiddleware is an adapter middleware and is useful
1296
- * for handling outgoing responses and rendering them in the browser.
1270
+ * @Service({ alias: 'userService' })
1271
+ * class UserService {
1272
+ * @Snapshot()
1273
+ * showProfile() {
1274
+ * return { name: 'John Doe' };
1275
+ * }
1276
+ * }
1277
+ * ```
1278
+ */
1279
+ const Snapshot = (name) => {
1280
+ return methodDecoratorLegacyWrapper((target, context) => {
1281
+ return async function (...args) {
1282
+ name = name ?? `${String(Object.getPrototypeOf(this).constructor.name)}.${String(context.name)}`;
1283
+ return await ReactRuntime.instance?.snapshot(name, () => target.apply(this, args));
1284
+ };
1285
+ });
1286
+ };
1287
+
1288
+ /**
1289
+ * Blueprint middleware to dynamically set lifecycle hooks for react.
1297
1290
  *
1298
1291
  * @param context - The configuration context containing modules and blueprint.
1299
1292
  * @param next - The next pipeline function to continue processing.
@@ -1301,14 +1294,18 @@ const SetUseReactHooksMiddleware = (context, next) => {
1301
1294
  *
1302
1295
  * @example
1303
1296
  * ```typescript
1304
- * SetBrowserResponseMiddlewareMiddleware(context, next)
1297
+ * SetUseReactHooksMiddleware(context, next)
1305
1298
  * ```
1306
1299
  */
1307
- const SetBrowserResponseMiddlewareMiddleware = async (context, next) => {
1308
- if (context.blueprint.get('stone.adapter.platform') === BROWSER_PLATFORM) {
1309
- context.blueprint.add('stone.adapter.middleware', [MetaBrowserResponseMiddleware]);
1300
+ const SetUseReactHooksMiddleware = (context, next) => {
1301
+ const currentPlatform = context.blueprint.get('stone.adapter.platform', '');
1302
+ const ignorePlatforms = context.blueprint.get('stone.useReact.ignorePlatforms', []);
1303
+ if (!ignorePlatforms.includes(currentPlatform)) {
1304
+ context
1305
+ .blueprint
1306
+ .add('stone.lifecycleHooks.onPreparingResponse', [onPreparingResponse]);
1310
1307
  }
1311
- return await next(context);
1308
+ return next(context);
1312
1309
  };
1313
1310
  /**
1314
1311
  * Blueprint middleware to process and register kernel error page definitions from modules.
@@ -1347,80 +1344,6 @@ const SetReactKernelErrorPageMiddleware = (context, next) => {
1347
1344
  });
1348
1345
  return next(context);
1349
1346
  };
1350
- /**
1351
- * Blueprint middleware to process and register adapter error page definitions from modules.
1352
- *
1353
- * @param context - The configuration context containing modules and blueprint.
1354
- * @param next - The next pipeline function to continue processing.
1355
- * @returns The updated blueprint or a promise resolving to it.
1356
- *
1357
- * @example
1358
- * ```typescript
1359
- * SetReactAdapterErrorPageMiddleware(context, next)
1360
- * ```
1361
- */
1362
- const SetReactAdapterErrorPageMiddleware = (context, next) => {
1363
- const UseReactAdapterErrorHandler = import.meta.env.SSR
1364
- ? UseReactServerErrorHandler
1365
- : UseReactBrowserErrorHandler;
1366
- context
1367
- .blueprint
1368
- .set('stone.adapter.errorHandlers.default', { module: UseReactAdapterErrorHandler, isClass: true });
1369
- context
1370
- .modules
1371
- .filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
1372
- .forEach(module => {
1373
- const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
1374
- if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
1375
- Array(error).flat().forEach(name => {
1376
- context
1377
- .blueprint
1378
- .set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
1379
- });
1380
- }
1381
- });
1382
- // Process both eager and lazy loaded error pages
1383
- Object
1384
- .keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
1385
- .forEach((name) => {
1386
- context
1387
- .blueprint
1388
- .set(`stone.adapter.errorHandlers.${name}`, { module: UseReactAdapterErrorHandler, isClass: true });
1389
- });
1390
- return next(context);
1391
- };
1392
- /**
1393
- * Blueprint middleware to set StaticFileMiddleware for SSR adapter.
1394
- *
1395
- * @param context - The configuration context containing modules and blueprint.
1396
- * @param next - The next pipeline function to continue processing.
1397
- * @returns The updated blueprint or a promise resolving to it.
1398
- *
1399
- * @example
1400
- * ```typescript
1401
- * SetSSRStaticFileMiddleware(context, next)
1402
- * ```
1403
- */
1404
- const SetSSRStaticFileMiddleware = async (context, next) => {
1405
- import.meta.env.SSR && context.blueprint.add('stone.kernel.middleware', [MetaStaticFileMiddleware]);
1406
- return await next(context);
1407
- };
1408
- /**
1409
- * Blueprint middleware to set CompressionMiddleware for SSR adapter.
1410
- *
1411
- * @param context - The configuration context containing modules and blueprint.
1412
- * @param next - The next pipeline function to continue processing.
1413
- * @returns The updated blueprint or a promise resolving to it.
1414
- *
1415
- * @example
1416
- * ```typescript
1417
- * SetSSRCompressionMiddleware(context, next)
1418
- * ```
1419
- */
1420
- const SetSSRCompressionMiddleware = async (context, next) => {
1421
- import.meta.env.SSR && context.blueprint.add('stone.kernel.middleware', [MetaCompressionMiddleware]);
1422
- return await next(context);
1423
- };
1424
1347
  /**
1425
1348
  * Blueprint middleware to process and register route definitions from modules.
1426
1349
  *
@@ -1492,267 +1415,187 @@ async function SetUseReactEventHandlerMiddleware(context, next) {
1492
1415
  }
1493
1416
  return blueprint;
1494
1417
  }
1418
+
1495
1419
  /**
1496
- * Configuration for react processing middleware.
1420
+ * Sets the error handler for the React adapter and registers error pages.
1497
1421
  *
1498
- * This array defines a list of middleware pipes, each with a `pipe` function and a `priority`.
1499
- * These pipes are executed in the order of their priority values, with lower values running first.
1422
+ * @param errorHandler - The error handler to set for the React adapter.
1423
+ * @param context - The blueprint context containing modules and blueprint.
1424
+ * @returns The updated blueprint context with the error handler and error pages set.
1500
1425
  */
1501
- const metaUseReactBlueprintMiddleware = [
1502
- { module: SetSSRStaticFileMiddleware, priority: 10 },
1503
- { module: SetUseReactHooksMiddleware, priority: 10 },
1504
- { module: SetSSRCompressionMiddleware, priority: 10 },
1505
- { module: SetReactPageLayoutMiddleware, priority: 10 },
1506
- { module: SetUseReactEventHandlerMiddleware, priority: 2 },
1507
- { module: SetReactKernelErrorPageMiddleware, priority: 10 },
1508
- { module: SetReactAdapterErrorPageMiddleware, priority: 10 },
1509
- { module: SetReactRouteDefinitionsMiddleware, priority: 10 },
1510
- { module: SetBrowserResponseMiddlewareMiddleware, priority: 10 }
1511
- ];
1426
+ function setUseReactAdapterErrorHandler(errorHandler, context) {
1427
+ context
1428
+ .blueprint
1429
+ .set('stone.adapter.errorHandlers.default', { module: errorHandler, isClass: true });
1430
+ context
1431
+ .modules
1432
+ .filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
1433
+ .forEach(module => {
1434
+ const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
1435
+ if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
1436
+ Array(error).flat().forEach(name => {
1437
+ context
1438
+ .blueprint
1439
+ .set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
1440
+ });
1441
+ }
1442
+ });
1443
+ // Process both eager and lazy loaded error pages
1444
+ Object
1445
+ .keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
1446
+ .forEach((name) => {
1447
+ context
1448
+ .blueprint
1449
+ .set(`stone.adapter.errorHandlers.${name}`, { module: errorHandler, isClass: true });
1450
+ });
1451
+ return context;
1452
+ }
1512
1453
 
1513
1454
  /**
1514
- * Default blueprint for a React-based Stone.js application.
1455
+ * Create an UseReact response.
1515
1456
  *
1516
- * - Defines middleware, lifecycle hooks, and the default HTML template path.
1457
+ * @param options - The options for creating the response.
1458
+ * @returns The React response.
1517
1459
  */
1518
- const useReactBlueprint = {
1519
- stone: {
1520
- useReact: {},
1521
- blueprint: {
1522
- middleware: metaUseReactBlueprintMiddleware
1523
- },
1524
- services: [MetaReactRuntime],
1525
- providers: [MetaUseReactServiceProvider]
1460
+ const reactResponse = (options) => {
1461
+ if (isNotEmpty(options) &&
1462
+ (isNotEmpty(options.url) ||
1463
+ (isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
1464
+ return reactRedirectResponse(options);
1526
1465
  }
1466
+ return OutgoingHttpResponse.create(options);
1467
+ };
1468
+ /**
1469
+ * Create an UseReact redirect response.
1470
+ *
1471
+ * @param options - The options for creating the response.
1472
+ * @returns The React redirect response.
1473
+ */
1474
+ const reactRedirectResponse = (options) => {
1475
+ return RedirectResponse.create({ statusCode: 302, ...options });
1527
1476
  };
1528
1477
 
1529
1478
  /**
1530
- * Defines a Stone React app using a factory-based or class-based main handler.
1479
+ * Class representing an UseReactServerErrorHandler.
1531
1480
  *
1532
- * @param moduleOrOptions - A factory function or class constructor for the main page.
1533
- * @param optionsOrBlueprints - Optional application-level configuration.
1534
- * @param maybeBlueprints - Additional blueprints to merge.
1535
- * @returns A fully merged Stone blueprint.
1481
+ * Adapter level error handler for React applications.
1536
1482
  */
1537
- function defineStoneReactApp(moduleOrOptions = {}, optionsOrBlueprints, maybeBlueprints) {
1538
- let module;
1539
- let options = {};
1540
- let blueprints = [];
1541
- // Pattern: defineStoneReactApp(handler, options?, blueprints?)
1542
- if (isFunctionModule(moduleOrOptions)) {
1543
- module = moduleOrOptions;
1544
- if (isObjectLikeModule(optionsOrBlueprints)) {
1545
- options = optionsOrBlueprints;
1546
- blueprints = Array.isArray(maybeBlueprints) ? maybeBlueprints : [];
1547
- }
1483
+ class UseReactServerErrorHandler {
1484
+ logger;
1485
+ blueprint;
1486
+ /**
1487
+ * Create an UseReactServerErrorHandler.
1488
+ *
1489
+ * @param options - UseReactServerErrorHandler options.
1490
+ */
1491
+ constructor({ blueprint }) {
1492
+ this.blueprint = blueprint;
1493
+ this.logger = Logger.getInstance();
1548
1494
  }
1549
- else if (isObjectLikeModule(moduleOrOptions)) { // Pattern: defineStoneReactApp(options, blueprints?)
1550
- options = moduleOrOptions;
1551
- blueprints = Array.isArray(optionsOrBlueprints) ? optionsOrBlueprints : [];
1495
+ /**
1496
+ * Handle an error.
1497
+ *
1498
+ * @param error - The error to handle.
1499
+ * @param context - The context of the adapter.
1500
+ * @returns The raw response.
1501
+ */
1502
+ async handle(error, context) {
1503
+ this.logger.error(error.message, { error });
1504
+ return context
1505
+ .rawResponseBuilder
1506
+ .add('statusCode', error.statusCode ?? 500)
1507
+ .add('headers', new Headers({ 'Content-Type': 'text/html' }))
1508
+ .add('body', await this.getErrorBody(error, context));
1552
1509
  }
1553
- const stonePart = {
1554
- ...options,
1555
- useReact: {
1556
- ...options.useReact
1557
- }
1558
- };
1559
- if (isNotEmpty(module)) {
1560
- stonePart.useReact.componentEventHandler = {
1561
- module,
1562
- isComponent: true,
1563
- isClass: options.isClass,
1564
- isFactory: options.isClass !== true
1565
- };
1510
+ /**
1511
+ * Get the error body.
1512
+ *
1513
+ * @param error - The error to handle.
1514
+ * @returns The error body.
1515
+ */
1516
+ async getErrorBody(error, context) {
1517
+ const statusCode = error.statusCode ?? 500;
1518
+ const template = htmlTemplate(this.blueprint);
1519
+ const ClientApp = await buildAdapterErrorComponent(this.blueprint, context, statusCode, error);
1520
+ return template.replace('<!--app-html-->', renderToString(ClientApp));
1566
1521
  }
1567
- return mergeBlueprints(stoneBlueprint, useReactBlueprint, ...blueprints, { stone: stonePart });
1568
1522
  }
1569
1523
 
1570
1524
  /**
1571
- * A class decorator for defining a class as a React Handler layout.
1525
+ * Blueprint middleware to process and register adapter error page definitions from modules.
1572
1526
  *
1573
- * @param options - Configuration options for the layout definition.
1574
- * @returns A method decorator to be applied to a class method.
1527
+ * @param context - The configuration context containing modules and blueprint.
1528
+ * @param next - The next pipeline function to continue processing.
1529
+ * @returns The updated blueprint or a promise resolving to it.
1575
1530
  *
1576
1531
  * @example
1577
1532
  * ```typescript
1578
- * import { AdapterErrorPage } from '@stone-js/use-react';
1579
- *
1580
- * @AdapterErrorPage({ error: 'UserNotFoundError' })
1581
- * class UserAdapterErrorPage {
1582
- * render({ error }) {
1583
- * return <h1>User name: {error.message}</h1>;
1584
- * }
1585
- * }
1533
+ * SetReactAdapterErrorPageMiddleware(context, next)
1586
1534
  * ```
1587
1535
  */
1588
- const AdapterErrorPage = (options) => {
1589
- return classDecoratorLegacyWrapper((_target, context) => {
1590
- setMetadata(context, REACT_ADAPTER_ERROR_PAGE_KEY, { ...options, isClass: true });
1591
- });
1536
+ const SetReactAdapterErrorPageMiddleware = (context, next) => {
1537
+ return next(setUseReactAdapterErrorHandler(UseReactServerErrorHandler, context));
1592
1538
  };
1593
-
1594
1539
  /**
1595
- * A class decorator for defining a class as a React Handler layout.
1596
- *
1597
- * @param options - Configuration options for the layout definition.
1598
- * @returns A method decorator to be applied to a class method.
1599
- *
1600
- * @example
1601
- * ```typescript
1602
- * import { ErrorPage } from '@stone-js/use-react';
1540
+ * Blueprint middleware to set StaticFileMiddleware for SSR adapter.
1603
1541
  *
1604
- * @ErrorPage({ error: 'UserNotFoundError' })
1605
- * class UserErrorPage {
1606
- * render({ error }) {
1607
- * return <h1>User name: {error.message}</h1>;
1608
- * }
1609
- * }
1610
- * ```
1611
- */
1612
- const ErrorPage = (options) => {
1613
- return classDecoratorLegacyWrapper((_target, context) => {
1614
- setMetadata(context, REACT_ERROR_PAGE_KEY, { ...options, isClass: true });
1615
- });
1616
- };
1617
-
1618
- /**
1619
- * Hook decorator to mark a method as a lifecycle hook
1620
- * And automatically add it to the global lifecycle hook registry.
1542
+ * @param context - The configuration context containing modules and blueprint.
1543
+ * @param next - The next pipeline function to continue processing.
1544
+ * @returns The updated blueprint or a promise resolving to it.
1621
1545
  *
1622
1546
  * @example
1623
1547
  * ```typescript
1624
- * class MyClass {
1625
- * // ...
1626
- * @Hook('onPreparingPage')
1627
- * onPreparingPage () {}
1628
- * }
1548
+ * SetSSRStaticFileMiddleware(context, next)
1629
1549
  * ```
1630
- *
1631
- * @param name - The name of the lifecycle hook.
1632
- * @returns A class decorator function that sets the metadata using the provided options.
1633
1550
  */
1634
- const Hook = (name) => {
1635
- return methodDecoratorLegacyWrapper((_target, context) => {
1636
- addMetadata(context, LIFECYCLE_HOOK_KEY, { name, method: context.name });
1637
- });
1551
+ const SetSSRStaticFileMiddleware = async (context, next) => {
1552
+ context.blueprint.add('stone.kernel.middleware', [MetaStaticFileMiddleware]);
1553
+ return await next(context);
1638
1554
  };
1639
-
1640
1555
  /**
1641
- * A class decorator for defining a class as a React Page route action.
1642
- * Uses the `Match` decorator internally to register the route with the HTTP `GET` method.
1556
+ * Blueprint middleware to set CompressionMiddleware for SSR adapter.
1643
1557
  *
1644
- * @param options - Configuration options for the route definition, excluding the `methods` property.
1645
- * @returns A method decorator to be applied to a class method.
1558
+ * @param context - The configuration context containing modules and blueprint.
1559
+ * @param next - The next pipeline function to continue processing.
1560
+ * @returns The updated blueprint or a promise resolving to it.
1646
1561
  *
1647
1562
  * @example
1648
1563
  * ```typescript
1649
- * import { Page } from '@stone-js/use-react';
1650
- *
1651
- * @Page('/user-profile')
1652
- * class UserPage {
1653
- * handle({ event }): Record<string, string> {
1654
- * return { name: 'Jane Doe' };
1655
- * }
1656
- *
1657
- * render({ data }) {
1658
- * return <h1>User name: {data.name}</h1>;
1659
- * }
1660
- * }
1564
+ * SetSSRCompressionMiddleware(context, next)
1661
1565
  * ```
1662
1566
  */
1663
- const Page = (path, options = {}) => {
1664
- return classDecoratorLegacyWrapper((target, context) => {
1665
- setMetadata(context, REACT_PAGE_KEY, {
1666
- ...options,
1667
- path,
1668
- method: GET,
1669
- methods: [],
1670
- handler: { isClass: true, isComponent: true, layout: options.layout, module: target }
1671
- });
1672
- });
1567
+ const SetSSRCompressionMiddleware = async (context, next) => {
1568
+ context.blueprint.add('stone.kernel.middleware', [MetaCompressionMiddleware]);
1569
+ return await next(context);
1673
1570
  };
1674
-
1675
1571
  /**
1676
- * A class decorator for defining a class as a React Page layout.
1677
- *
1678
- * @param options - Configuration options for the layout definition.
1679
- * @returns A method decorator to be applied to a class method.
1680
- *
1681
- * @example
1682
- * ```typescript
1683
- * import { PageLayout } from '@stone-js/use-react';
1572
+ * Configuration for react processing middleware.
1684
1573
  *
1685
- * @PageLayout({ name: 'UserPageLayout' })
1686
- * class UserPageLayout {
1687
- * render({ data }) {
1688
- * return <h1>User name: {data.name}</h1>;
1689
- * }
1690
- * }
1691
- * ```
1574
+ * This array defines a list of middleware pipes, each with a `pipe` function and a `priority`.
1575
+ * These pipes are executed in the order of their priority values, with lower values running first.
1692
1576
  */
1693
- const PageLayout = (options) => {
1694
- return classDecoratorLegacyWrapper((_target, context) => {
1695
- setMetadata(context, REACT_PAGE_LAYOUT_KEY, { ...options, isClass: true });
1696
- });
1697
- };
1577
+ const metaServerUseReactBlueprintMiddleware = [
1578
+ { module: SetSSRStaticFileMiddleware, priority: 10 },
1579
+ { module: SetUseReactHooksMiddleware, priority: 10 },
1580
+ { module: SetSSRCompressionMiddleware, priority: 10 },
1581
+ { module: SetReactPageLayoutMiddleware, priority: 10 },
1582
+ { module: SetUseReactEventHandlerMiddleware, priority: 2 },
1583
+ { module: SetReactKernelErrorPageMiddleware, priority: 10 },
1584
+ { module: SetReactAdapterErrorPageMiddleware, priority: 10 },
1585
+ { module: SetReactRouteDefinitionsMiddleware, priority: 10 }
1586
+ ];
1698
1587
 
1699
1588
  /**
1700
- * Decorator to set the status code of the response.
1701
- *
1702
- * @param statusCode - The status code of the response.
1703
- * @param headers - The headers for the response.
1704
- * @returns A method decorator.
1705
- *
1706
- * @example
1707
- * ```typescript
1708
- * import { Page, PageStatus } from '@stone-js/use-react';
1709
- *
1710
- * @Page('/user-profile')
1711
- * class UserPage {
1712
- * @PageStatus()
1713
- * handle() {
1714
- * return { name: 'John Doe' };
1715
- * }
1716
- * }
1717
- * ```
1589
+ * Middleware for the React blueprint.
1718
1590
  */
1719
- const PageStatus = (statusCode = 200, headers = {}) => {
1720
- return methodDecoratorLegacyWrapper((target, _context) => {
1721
- return async function (...args) {
1722
- const content = await target.apply(this, args);
1723
- return { content, statusCode, headers };
1724
- };
1725
- });
1726
- };
1727
-
1591
+ internalUseReactBlueprint.stone.useReact.ignorePlatforms = [NODE_CONSOLE_PLATFORM];
1592
+ internalUseReactBlueprint.stone.blueprint = { middleware: metaServerUseReactBlueprintMiddleware };
1728
1593
  /**
1729
- * Decorator to create a snapshot of the current data.
1730
- *
1731
- * @param name - The name of the snapshot.
1732
- * @returns A method decorator.
1733
- *
1734
- * @example
1735
- * ```typescript
1736
- * import { Service } from '@stone-js/core';
1737
- * import { Snapshot } from '@stone-js/use-react';
1594
+ * Default blueprint for a React-based Stone.js application.
1738
1595
  *
1739
- * @Service({ alias: 'userService' })
1740
- * class UserService {
1741
- * @Snapshot()
1742
- * showProfile() {
1743
- * return { name: 'John Doe' };
1744
- * }
1745
- * }
1746
- * ```
1596
+ * - Defines middleware, lifecycle hooks, and the default HTML template path.
1747
1597
  */
1748
- const Snapshot = (name) => {
1749
- return methodDecoratorLegacyWrapper((target, context) => {
1750
- return async function (...args) {
1751
- name = name ?? `${String(Object.getPrototypeOf(this).constructor.name)}.${String(context.name)}`;
1752
- return await ReactRuntime.instance?.snapshot(name, () => target.apply(this, args));
1753
- };
1754
- });
1755
- };
1598
+ const useReactBlueprint = internalUseReactBlueprint;
1756
1599
 
1757
1600
  /**
1758
1601
  * UseReact decorator.
@@ -1781,6 +1624,33 @@ const StoneClient = ({ children }) => {
1781
1624
  return isClient() ? jsx(Fragment, { children: children }) : jsx(Fragment, {});
1782
1625
  };
1783
1626
 
1627
+ /**
1628
+ * A dynamic rendering component that updates its content based on a global event.
1629
+ *
1630
+ * - Listens for `stone:inject:react-page:outlet` and updates its view when triggered.
1631
+ * - Uses `useState` to manage the currently displayed content.
1632
+ * - Automatically cleans up event listeners on unmount.
1633
+ *
1634
+ * This component enables dynamic content updates within a Stone.js application.
1635
+ *
1636
+ * @param options - The options to create the Stone Outlet.
1637
+ * @returns The Stone Outlet component.
1638
+ */
1639
+ const StoneOutlet = ({ children }) => {
1640
+ const [currentView, setCurrentView] = useState(children);
1641
+ useEffect(() => {
1642
+ const eventName = STONE_PAGE_EVENT_OUTLET;
1643
+ const handleEvent = (e) => {
1644
+ if (isNotEmpty(e) && isNotEmpty(e.detail)) {
1645
+ setCurrentView(e.detail);
1646
+ }
1647
+ };
1648
+ window.addEventListener(eventName, handleEvent);
1649
+ return () => window.removeEventListener(eventName, handleEvent);
1650
+ }, []);
1651
+ return jsx("div", { "data-stone-outlet": 'true', children: currentView });
1652
+ };
1653
+
1784
1654
  /**
1785
1655
  * Internal link component using Stone.js router.
1786
1656
  */
@@ -1818,33 +1688,6 @@ const StoneLink = (props) => {
1818
1688
  return props.external === true ? jsx(ExternalLink, { ...props }) : jsx(InternalLink, { ...props });
1819
1689
  };
1820
1690
 
1821
- /**
1822
- * A dynamic rendering component that updates its content based on a global event.
1823
- *
1824
- * - Listens for `stone:inject:react-page:outlet` and updates its view when triggered.
1825
- * - Uses `useState` to manage the currently displayed content.
1826
- * - Automatically cleans up event listeners on unmount.
1827
- *
1828
- * This component enables dynamic content updates within a Stone.js application.
1829
- *
1830
- * @param options - The options to create the Stone Outlet.
1831
- * @returns The Stone Outlet component.
1832
- */
1833
- const StoneOutlet = ({ children }) => {
1834
- const [currentView, setCurrentView] = useState(children);
1835
- useEffect(() => {
1836
- const eventName = STONE_PAGE_EVENT_OUTLET;
1837
- const handleEvent = (e) => {
1838
- if (isNotEmpty(e) && isNotEmpty(e.detail)) {
1839
- setCurrentView(e.detail);
1840
- }
1841
- };
1842
- window.addEventListener(eventName, handleEvent);
1843
- return () => window.removeEventListener(eventName, handleEvent);
1844
- }, []);
1845
- return jsx("div", { "data-stone-outlet": 'true', children: currentView });
1846
- };
1847
-
1848
1691
  /**
1849
1692
  * Stone Server.
1850
1693
  * This component is used to wrap content
@@ -1856,4 +1699,4 @@ const StoneServer = ({ children }) => {
1856
1699
  return isServer() ? jsx(Fragment, { children: children }) : jsx(Fragment, {});
1857
1700
  };
1858
1701
 
1859
- export { AdapterErrorPage, BrowserResponseMiddleware, ErrorPage, Hook, MetaBrowserResponseMiddleware, MetaReactRuntime, MetaUseReactServiceProvider, Page, PageLayout, PageStatus, REACT_ADAPTER_ERROR_PAGE_KEY, REACT_ERROR_PAGE_KEY, REACT_PAGE_KEY, REACT_PAGE_LAYOUT_KEY, ReactRuntime, STONE_DOM_ATTR, STONE_PAGE_EVENT_OUTLET, STONE_REACT_APP_KEY, STONE_SNAPSHOT, SetBrowserResponseMiddlewareMiddleware, SetReactAdapterErrorPageMiddleware, SetReactKernelErrorPageMiddleware, SetReactPageLayoutMiddleware, SetReactRouteDefinitionsMiddleware, SetSSRCompressionMiddleware, SetSSRStaticFileMiddleware, SetUseReactEventHandlerMiddleware, SetUseReactHooksMiddleware, Snapshot, StoneClient, StoneContext, StoneError, StoneLink, StoneOutlet, StonePage, StoneServer, UseReact, UseReactBrowserErrorHandler, UseReactError, UseReactEventHandler, UseReactKernelErrorHandler, UseReactServerErrorHandler, UseReactServiceProvider, applyHeadContextToDom, applyHeadContextToHtmlString, applyMeta, buildAdapterErrorComponent, buildAppComponent, buildLayoutComponent, buildPageComponent, defineAdapterErrorPage, defineErrorPage, definePage, definePageLayout, defineStoneReactApp, executeHandler, executeHooks, getAppRootElement, getBrowserContent, getResponseSnapshot, getServerContent, htmlTemplate, hydrateReactApp, isClient, isSSR, isServer, metaUseReactBlueprintMiddleware, onPreparingResponse, prepareErrorPage, prepareFallbackErrorPage, preparePage, reactRedirectResponse, reactResponse, renderReactApp, renderStoneSnapshot, resolveComponent, resolveLazyComponent, snapshotResponse, useReactBlueprint };
1702
+ export { AdapterErrorPage, ErrorPage, Hook, MetaReactRuntime, MetaUseReactServiceProvider, Page, PageLayout, PageStatus, REACT_ADAPTER_ERROR_PAGE_KEY, REACT_ERROR_PAGE_KEY, REACT_PAGE_KEY, REACT_PAGE_LAYOUT_KEY, ReactRuntime, STONE_DOM_ATTR, STONE_PAGE_EVENT_OUTLET, STONE_REACT_APP_KEY, STONE_SNAPSHOT, SetReactAdapterErrorPageMiddleware, SetReactKernelErrorPageMiddleware, SetReactPageLayoutMiddleware, SetReactRouteDefinitionsMiddleware, SetSSRCompressionMiddleware, SetSSRStaticFileMiddleware, SetUseReactEventHandlerMiddleware, SetUseReactHooksMiddleware, Snapshot, StoneClient, StoneContext, StoneError, StoneLink, StoneOutlet, StonePage, StoneServer, UseReact, UseReactError, UseReactEventHandler, UseReactKernelErrorHandler, UseReactServerErrorHandler, UseReactServiceProvider, applyHeadContextToDom, applyHeadContextToHtmlString, applyMeta, buildAdapterErrorComponent, buildAppComponent, buildLayoutComponent, buildPageComponent, defineAdapterErrorPage, defineErrorPage, definePage, definePageLayout, defineStoneReactApp, executeHandler, executeHooks, getAppRootElement, getBrowserContent, getResponseSnapshot, getServerContent, htmlTemplate, hydrateReactApp, internalUseReactBlueprint, isClient, isSSR, isServer, metaServerUseReactBlueprintMiddleware, onPreparingResponse, prepareErrorPage, prepareFallbackErrorPage, preparePage, reactRedirectResponse, reactResponse, renderReactApp, renderStoneSnapshot, resolveComponent, resolveLazyComponent, setUseReactAdapterErrorHandler, snapshotResponse, useReactBlueprint };