@stone-js/use-react 0.3.0 → 0.3.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.
- package/dist/browser.js +69 -69
- package/dist/index.d.ts +287 -287
- package/dist/index.js +374 -374
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNotEmpty, isEmpty, InitializationError, isMetaClassModule, isMetaFactoryModule, isObjectLikeModule, isFunction, isFunctionModule, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, hasMetadata, getMetadata, isMatchedAdapter, mergeBlueprints, stoneBlueprint, 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
4
|
import { createContext, StrictMode, useContext, useMemo, useState, useEffect } from 'react';
|
|
@@ -7,58 +7,6 @@ import { Config } from '@stone-js/config';
|
|
|
7
7
|
import { GET, NODE_CONSOLE_PLATFORM, Router, RouteEvent } from '@stone-js/router';
|
|
8
8
|
import { RedirectResponse, OutgoingHttpResponse, MetaCompressionMiddleware, MetaStaticFileMiddleware } from '@stone-js/http-core';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Custom error for react operations.
|
|
12
|
-
*/
|
|
13
|
-
class UseReactError extends InitializationError {
|
|
14
|
-
constructor(message, options) {
|
|
15
|
-
super(message, options);
|
|
16
|
-
this.name = 'UseReactError';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A useReact event handler for processing incoming events
|
|
22
|
-
* For single event handler.
|
|
23
|
-
*
|
|
24
|
-
* Multiple event handlers will be processed by the router.
|
|
25
|
-
*
|
|
26
|
-
* @template IncomingEventType - The type representing the incoming event.
|
|
27
|
-
* @template OutgoingResponseType - The type representing the outgoing response.
|
|
28
|
-
*/
|
|
29
|
-
class UseReactEventHandler {
|
|
30
|
-
blueprint;
|
|
31
|
-
/**
|
|
32
|
-
* Constructs a `UseReactEventHandler` instance.
|
|
33
|
-
*
|
|
34
|
-
* @param options - The UseReactEventHandler options including blueprint.
|
|
35
|
-
*/
|
|
36
|
-
constructor({ blueprint }) {
|
|
37
|
-
this.blueprint = blueprint;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Handle an incoming event.
|
|
41
|
-
*
|
|
42
|
-
* @returns The outgoing response.
|
|
43
|
-
*/
|
|
44
|
-
handle() {
|
|
45
|
-
return this.getComponentEventHandler();
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Get the component event handler.
|
|
49
|
-
*
|
|
50
|
-
* @returns The component event handler.
|
|
51
|
-
* @throws {UseReactError} If the component event handler is missing.
|
|
52
|
-
*/
|
|
53
|
-
getComponentEventHandler() {
|
|
54
|
-
const handler = this.blueprint.get('stone.useReact.componentEventHandler');
|
|
55
|
-
if (isEmpty(handler)) {
|
|
56
|
-
throw new UseReactError('The component event handler is missing.');
|
|
57
|
-
}
|
|
58
|
-
return handler;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
10
|
/**
|
|
63
11
|
* Stone DOM Attribute.
|
|
64
12
|
*/
|
|
@@ -321,6 +269,16 @@ const StoneError = () => {
|
|
|
321
269
|
return (jsxs(Fragment, { children: [jsx("h1", { children: "An error occured" }), jsx("p", { children: "Sorry, something went wrong." })] }));
|
|
322
270
|
};
|
|
323
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Custom error for react operations.
|
|
274
|
+
*/
|
|
275
|
+
class UseReactError extends InitializationError {
|
|
276
|
+
constructor(message, options) {
|
|
277
|
+
super(message, options);
|
|
278
|
+
this.name = 'UseReactError';
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
324
282
|
/**
|
|
325
283
|
* Build the React application for the current route.
|
|
326
284
|
* Or for the main handler if the route is not defined.
|
|
@@ -752,6 +710,48 @@ class ReactRuntime {
|
|
|
752
710
|
*/
|
|
753
711
|
const MetaReactRuntime = { module: ReactRuntime, isClass: true, alias: 'reactRuntime', singleton: true };
|
|
754
712
|
|
|
713
|
+
/**
|
|
714
|
+
* A useReact event handler for processing incoming events
|
|
715
|
+
* For single event handler.
|
|
716
|
+
*
|
|
717
|
+
* Multiple event handlers will be processed by the router.
|
|
718
|
+
*
|
|
719
|
+
* @template IncomingEventType - The type representing the incoming event.
|
|
720
|
+
* @template OutgoingResponseType - The type representing the outgoing response.
|
|
721
|
+
*/
|
|
722
|
+
class UseReactEventHandler {
|
|
723
|
+
blueprint;
|
|
724
|
+
/**
|
|
725
|
+
* Constructs a `UseReactEventHandler` instance.
|
|
726
|
+
*
|
|
727
|
+
* @param options - The UseReactEventHandler options including blueprint.
|
|
728
|
+
*/
|
|
729
|
+
constructor({ blueprint }) {
|
|
730
|
+
this.blueprint = blueprint;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Handle an incoming event.
|
|
734
|
+
*
|
|
735
|
+
* @returns The outgoing response.
|
|
736
|
+
*/
|
|
737
|
+
handle() {
|
|
738
|
+
return this.getComponentEventHandler();
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Get the component event handler.
|
|
742
|
+
*
|
|
743
|
+
* @returns The component event handler.
|
|
744
|
+
* @throws {UseReactError} If the component event handler is missing.
|
|
745
|
+
*/
|
|
746
|
+
getComponentEventHandler() {
|
|
747
|
+
const handler = this.blueprint.get('stone.useReact.componentEventHandler');
|
|
748
|
+
if (isEmpty(handler)) {
|
|
749
|
+
throw new UseReactError('The component event handler is missing.');
|
|
750
|
+
}
|
|
751
|
+
return handler;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
755
|
/**
|
|
756
756
|
* Class representing an UseReactUseReactKernelErrorHandler.
|
|
757
757
|
*
|
|
@@ -913,230 +913,93 @@ class UseReactServiceProvider {
|
|
|
913
913
|
const MetaUseReactServiceProvider = { module: UseReactServiceProvider, isClass: true };
|
|
914
914
|
|
|
915
915
|
/**
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
* @param module - The adapter error page module.
|
|
919
|
-
* @param options - Optional adapter error page options.
|
|
920
|
-
* @returns The UseReactBlueprint.
|
|
916
|
+
* Constants are defined here to prevent Circular dependency between modules
|
|
917
|
+
* This pattern must be applied to all Stone libraries or third party libraries.
|
|
921
918
|
*/
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
919
|
+
/**
|
|
920
|
+
* A unique symbol key to mark classes as React Page component.
|
|
921
|
+
*/
|
|
922
|
+
const REACT_PAGE_KEY = Symbol.for('ReactPage');
|
|
923
|
+
/**
|
|
924
|
+
* A unique symbol key to mark classes as React Page layout component.
|
|
925
|
+
*/
|
|
926
|
+
const REACT_PAGE_LAYOUT_KEY = Symbol.for('ReactPageLayout');
|
|
927
|
+
/**
|
|
928
|
+
* A unique symbol key to mark classes as React Error handler component.
|
|
929
|
+
*/
|
|
930
|
+
const REACT_ERROR_PAGE_KEY = Symbol.for('ReactErrorPage');
|
|
931
|
+
/**
|
|
932
|
+
* A unique symbol key to mark classes as React Adapter Error handler component.
|
|
933
|
+
*/
|
|
934
|
+
const REACT_ADAPTER_ERROR_PAGE_KEY = Symbol.for('ReactAdapterErrorPage');
|
|
935
|
+
/**
|
|
936
|
+
* A unique symbol key to mark classes as React Stone application entry point.
|
|
937
|
+
*/
|
|
938
|
+
const STONE_REACT_APP_KEY = Symbol.for('StoneReactApp');
|
|
941
939
|
|
|
942
940
|
/**
|
|
943
|
-
*
|
|
941
|
+
* A class decorator for defining a class as a React Handler layout.
|
|
944
942
|
*
|
|
945
|
-
*
|
|
943
|
+
* @param options - Configuration options for the layout definition.
|
|
944
|
+
* @returns A method decorator to be applied to a class method.
|
|
945
|
+
*
|
|
946
|
+
* @example
|
|
947
|
+
* ```typescript
|
|
948
|
+
* import { AdapterErrorPage } from '@stone-js/use-react';
|
|
949
|
+
*
|
|
950
|
+
* @AdapterErrorPage({ error: 'UserNotFoundError' })
|
|
951
|
+
* class UserAdapterErrorPage {
|
|
952
|
+
* render({ error }) {
|
|
953
|
+
* return <h1>User name: {error.message}</h1>;
|
|
954
|
+
* }
|
|
955
|
+
* }
|
|
956
|
+
* ```
|
|
946
957
|
*/
|
|
947
|
-
const
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
providers: [MetaUseReactServiceProvider]
|
|
952
|
-
}
|
|
958
|
+
const AdapterErrorPage = (options) => {
|
|
959
|
+
return classDecoratorLegacyWrapper((_target, context) => {
|
|
960
|
+
setMetadata(context, REACT_ADAPTER_ERROR_PAGE_KEY, { ...options, isClass: true });
|
|
961
|
+
});
|
|
953
962
|
};
|
|
954
963
|
|
|
955
964
|
/**
|
|
956
|
-
*
|
|
965
|
+
* A class decorator for defining a class as a React Handler layout.
|
|
957
966
|
*
|
|
958
|
-
* @param
|
|
959
|
-
* @
|
|
960
|
-
*
|
|
961
|
-
* @
|
|
967
|
+
* @param options - Configuration options for the layout definition.
|
|
968
|
+
* @returns A method decorator to be applied to a class method.
|
|
969
|
+
*
|
|
970
|
+
* @example
|
|
971
|
+
* ```typescript
|
|
972
|
+
* import { ErrorPage } from '@stone-js/use-react';
|
|
973
|
+
*
|
|
974
|
+
* @ErrorPage({ error: 'UserNotFoundError' })
|
|
975
|
+
* class UserErrorPage {
|
|
976
|
+
* render({ error }) {
|
|
977
|
+
* return <h1>User name: {error.message}</h1>;
|
|
978
|
+
* }
|
|
979
|
+
* }
|
|
980
|
+
* ```
|
|
962
981
|
*/
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
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
|
-
}
|
|
982
|
+
const ErrorPage = (options) => {
|
|
983
|
+
return classDecoratorLegacyWrapper((_target, context) => {
|
|
984
|
+
setMetadata(context, REACT_ERROR_PAGE_KEY, { ...options, isClass: true });
|
|
985
|
+
});
|
|
986
|
+
};
|
|
995
987
|
|
|
996
988
|
/**
|
|
997
|
-
*
|
|
989
|
+
* Hook decorator to mark a method as a lifecycle hook
|
|
990
|
+
* And automatically add it to the global lifecycle hook registry.
|
|
998
991
|
*
|
|
999
|
-
* @
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
method: GET,
|
|
1011
|
-
methods: [],
|
|
1012
|
-
children: undefined,
|
|
1013
|
-
handler: {
|
|
1014
|
-
module,
|
|
1015
|
-
isComponent: true,
|
|
1016
|
-
layout: options?.layout,
|
|
1017
|
-
isClass: options?.isClass,
|
|
1018
|
-
isFactory: options?.isClass !== true
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
]
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Utility function to define a page layout.
|
|
1028
|
-
*
|
|
1029
|
-
* @param module - The layout module.
|
|
1030
|
-
* @param options - Optional page layout definition options.
|
|
1031
|
-
* @returns The UseReactBlueprint.
|
|
1032
|
-
*/
|
|
1033
|
-
function definePageLayout(module, options) {
|
|
1034
|
-
const name = options?.name ?? 'default';
|
|
1035
|
-
return {
|
|
1036
|
-
stone: {
|
|
1037
|
-
useReact: {
|
|
1038
|
-
layout: {
|
|
1039
|
-
[name]: {
|
|
1040
|
-
module,
|
|
1041
|
-
isClass: options?.isClass,
|
|
1042
|
-
isFactory: options?.isClass !== true
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Utility function to define an error page.
|
|
1051
|
-
*
|
|
1052
|
-
* @param module - The layout module.
|
|
1053
|
-
* @param options - Optional page layout definition options.
|
|
1054
|
-
* @returns The UseReactBlueprint.
|
|
1055
|
-
*/
|
|
1056
|
-
function defineErrorPage(module, options) {
|
|
1057
|
-
const error = options?.error ?? 'default';
|
|
1058
|
-
const errorPages = Object.fromEntries([error].flat().map((err) => [
|
|
1059
|
-
err,
|
|
1060
|
-
{
|
|
1061
|
-
...options,
|
|
1062
|
-
module,
|
|
1063
|
-
error: err,
|
|
1064
|
-
isFactory: options?.isClass !== true
|
|
1065
|
-
}
|
|
1066
|
-
]));
|
|
1067
|
-
return {
|
|
1068
|
-
stone: {
|
|
1069
|
-
useReact: {
|
|
1070
|
-
errorPages
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
/**
|
|
1077
|
-
* Constants are defined here to prevent Circular dependency between modules
|
|
1078
|
-
* This pattern must be applied to all Stone libraries or third party libraries.
|
|
1079
|
-
*/
|
|
1080
|
-
/**
|
|
1081
|
-
* A unique symbol key to mark classes as React Page component.
|
|
1082
|
-
*/
|
|
1083
|
-
const REACT_PAGE_KEY = Symbol.for('ReactPage');
|
|
1084
|
-
/**
|
|
1085
|
-
* A unique symbol key to mark classes as React Page layout component.
|
|
1086
|
-
*/
|
|
1087
|
-
const REACT_PAGE_LAYOUT_KEY = Symbol.for('ReactPageLayout');
|
|
1088
|
-
/**
|
|
1089
|
-
* A unique symbol key to mark classes as React Error handler component.
|
|
1090
|
-
*/
|
|
1091
|
-
const REACT_ERROR_PAGE_KEY = Symbol.for('ReactErrorPage');
|
|
1092
|
-
/**
|
|
1093
|
-
* A unique symbol key to mark classes as React Adapter Error handler component.
|
|
1094
|
-
*/
|
|
1095
|
-
const REACT_ADAPTER_ERROR_PAGE_KEY = Symbol.for('ReactAdapterErrorPage');
|
|
1096
|
-
/**
|
|
1097
|
-
* A unique symbol key to mark classes as React Stone application entry point.
|
|
1098
|
-
*/
|
|
1099
|
-
const STONE_REACT_APP_KEY = Symbol.for('StoneReactApp');
|
|
1100
|
-
|
|
1101
|
-
/**
|
|
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 { ErrorPage } from '@stone-js/use-react';
|
|
1110
|
-
*
|
|
1111
|
-
* @ErrorPage({ error: 'UserNotFoundError' })
|
|
1112
|
-
* class UserErrorPage {
|
|
1113
|
-
* render({ error }) {
|
|
1114
|
-
* return <h1>User name: {error.message}</h1>;
|
|
1115
|
-
* }
|
|
1116
|
-
* }
|
|
1117
|
-
* ```
|
|
1118
|
-
*/
|
|
1119
|
-
const ErrorPage = (options) => {
|
|
1120
|
-
return classDecoratorLegacyWrapper((_target, context) => {
|
|
1121
|
-
setMetadata(context, REACT_ERROR_PAGE_KEY, { ...options, isClass: true });
|
|
1122
|
-
});
|
|
1123
|
-
};
|
|
1124
|
-
|
|
1125
|
-
/**
|
|
1126
|
-
* Hook decorator to mark a method as a lifecycle hook
|
|
1127
|
-
* And automatically add it to the global lifecycle hook registry.
|
|
1128
|
-
*
|
|
1129
|
-
* @example
|
|
1130
|
-
* ```typescript
|
|
1131
|
-
* class MyClass {
|
|
1132
|
-
* // ...
|
|
1133
|
-
* @Hook('onPreparingPage')
|
|
1134
|
-
* onPreparingPage () {}
|
|
1135
|
-
* }
|
|
1136
|
-
* ```
|
|
1137
|
-
*
|
|
1138
|
-
* @param name - The name of the lifecycle hook.
|
|
1139
|
-
* @returns A class decorator function that sets the metadata using the provided options.
|
|
992
|
+
* @example
|
|
993
|
+
* ```typescript
|
|
994
|
+
* class MyClass {
|
|
995
|
+
* // ...
|
|
996
|
+
* @Hook('onPreparingPage')
|
|
997
|
+
* onPreparingPage () {}
|
|
998
|
+
* }
|
|
999
|
+
* ```
|
|
1000
|
+
*
|
|
1001
|
+
* @param name - The name of the lifecycle hook.
|
|
1002
|
+
* @returns A class decorator function that sets the metadata using the provided options.
|
|
1140
1003
|
*/
|
|
1141
1004
|
const Hook = (name) => {
|
|
1142
1005
|
return methodDecoratorLegacyWrapper((_target, context) => {
|
|
@@ -1169,26 +1032,31 @@ const PageLayout = (options) => {
|
|
|
1169
1032
|
};
|
|
1170
1033
|
|
|
1171
1034
|
/**
|
|
1172
|
-
*
|
|
1035
|
+
* Decorator to create a snapshot of the current data.
|
|
1173
1036
|
*
|
|
1174
|
-
* @param
|
|
1175
|
-
* @returns A method decorator
|
|
1037
|
+
* @param name - The name of the snapshot.
|
|
1038
|
+
* @returns A method decorator.
|
|
1176
1039
|
*
|
|
1177
1040
|
* @example
|
|
1178
1041
|
* ```typescript
|
|
1179
|
-
* import {
|
|
1042
|
+
* import { Service } from '@stone-js/core';
|
|
1043
|
+
* import { Snapshot } from '@stone-js/use-react';
|
|
1180
1044
|
*
|
|
1181
|
-
* @
|
|
1182
|
-
* class
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1045
|
+
* @Service({ alias: 'userService' })
|
|
1046
|
+
* class UserService {
|
|
1047
|
+
* @Snapshot()
|
|
1048
|
+
* showProfile() {
|
|
1049
|
+
* return { name: 'John Doe' };
|
|
1185
1050
|
* }
|
|
1186
1051
|
* }
|
|
1187
1052
|
* ```
|
|
1188
1053
|
*/
|
|
1189
|
-
const
|
|
1190
|
-
return
|
|
1191
|
-
|
|
1054
|
+
const Snapshot = (name) => {
|
|
1055
|
+
return methodDecoratorLegacyWrapper((target, context) => {
|
|
1056
|
+
return async function (...args) {
|
|
1057
|
+
name = name ?? `${String(Object.getPrototypeOf(this).constructor.name)}.${String(context.name)}`;
|
|
1058
|
+
return await ReactRuntime.instance?.snapshot(name, () => target.apply(this, args));
|
|
1059
|
+
};
|
|
1192
1060
|
});
|
|
1193
1061
|
};
|
|
1194
1062
|
|
|
@@ -1256,35 +1124,6 @@ const Page = (path, options = {}) => {
|
|
|
1256
1124
|
});
|
|
1257
1125
|
};
|
|
1258
1126
|
|
|
1259
|
-
/**
|
|
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';
|
|
1269
|
-
*
|
|
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
1127
|
/**
|
|
1289
1128
|
* Sets the error handler for the React adapter and registers error pages.
|
|
1290
1129
|
*
|
|
@@ -1320,76 +1159,6 @@ function setUseReactAdapterErrorHandler(errorHandler, context) {
|
|
|
1320
1159
|
return context;
|
|
1321
1160
|
}
|
|
1322
1161
|
|
|
1323
|
-
/**
|
|
1324
|
-
* Create an UseReact response.
|
|
1325
|
-
*
|
|
1326
|
-
* @param options - The options for creating the response.
|
|
1327
|
-
* @returns The React response.
|
|
1328
|
-
*/
|
|
1329
|
-
const reactResponse = (options) => {
|
|
1330
|
-
if (isNotEmpty(options) &&
|
|
1331
|
-
(isNotEmpty(options.url) ||
|
|
1332
|
-
(isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
|
|
1333
|
-
return reactRedirectResponse(options);
|
|
1334
|
-
}
|
|
1335
|
-
return OutgoingHttpResponse.create(options);
|
|
1336
|
-
};
|
|
1337
|
-
/**
|
|
1338
|
-
* Create an UseReact redirect response.
|
|
1339
|
-
*
|
|
1340
|
-
* @param options - The options for creating the response.
|
|
1341
|
-
* @returns The React redirect response.
|
|
1342
|
-
*/
|
|
1343
|
-
const reactRedirectResponse = (options) => {
|
|
1344
|
-
return RedirectResponse.create({ statusCode: 302, ...options });
|
|
1345
|
-
};
|
|
1346
|
-
|
|
1347
|
-
/**
|
|
1348
|
-
* Class representing an UseReactServerErrorHandler.
|
|
1349
|
-
*
|
|
1350
|
-
* Adapter level error handler for React applications.
|
|
1351
|
-
*/
|
|
1352
|
-
class UseReactServerErrorHandler {
|
|
1353
|
-
logger;
|
|
1354
|
-
blueprint;
|
|
1355
|
-
/**
|
|
1356
|
-
* Create an UseReactServerErrorHandler.
|
|
1357
|
-
*
|
|
1358
|
-
* @param options - UseReactServerErrorHandler options.
|
|
1359
|
-
*/
|
|
1360
|
-
constructor({ blueprint }) {
|
|
1361
|
-
this.blueprint = blueprint;
|
|
1362
|
-
this.logger = Logger.getInstance();
|
|
1363
|
-
}
|
|
1364
|
-
/**
|
|
1365
|
-
* Handle an error.
|
|
1366
|
-
*
|
|
1367
|
-
* @param error - The error to handle.
|
|
1368
|
-
* @param context - The context of the adapter.
|
|
1369
|
-
* @returns The raw response.
|
|
1370
|
-
*/
|
|
1371
|
-
async handle(error, context) {
|
|
1372
|
-
this.logger.error(error.message, { error });
|
|
1373
|
-
return context
|
|
1374
|
-
.rawResponseBuilder
|
|
1375
|
-
.add('statusCode', error.statusCode ?? 500)
|
|
1376
|
-
.add('headers', new Headers({ 'Content-Type': 'text/html' }))
|
|
1377
|
-
.add('body', await this.getErrorBody(error, context));
|
|
1378
|
-
}
|
|
1379
|
-
/**
|
|
1380
|
-
* Get the error body.
|
|
1381
|
-
*
|
|
1382
|
-
* @param error - The error to handle.
|
|
1383
|
-
* @returns The error body.
|
|
1384
|
-
*/
|
|
1385
|
-
async getErrorBody(error, context) {
|
|
1386
|
-
const statusCode = error.statusCode ?? 500;
|
|
1387
|
-
const template = htmlTemplate(this.blueprint);
|
|
1388
|
-
const ClientApp = await buildAdapterErrorComponent(this.blueprint, context, statusCode, error);
|
|
1389
|
-
return template.replace('<!--app-html-->', renderToString(ClientApp));
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
1162
|
/**
|
|
1394
1163
|
* Blueprint middleware to dynamically set lifecycle hooks for react.
|
|
1395
1164
|
*
|
|
@@ -1521,6 +1290,237 @@ async function SetUseReactEventHandlerMiddleware(context, next) {
|
|
|
1521
1290
|
return blueprint;
|
|
1522
1291
|
}
|
|
1523
1292
|
|
|
1293
|
+
/**
|
|
1294
|
+
* Default blueprint for a React-based Stone.js application.
|
|
1295
|
+
*
|
|
1296
|
+
* - Defines middleware, lifecycle hooks, and the default HTML template path.
|
|
1297
|
+
*/
|
|
1298
|
+
const internalUseReactBlueprint = {
|
|
1299
|
+
stone: {
|
|
1300
|
+
useReact: {},
|
|
1301
|
+
services: [MetaReactRuntime],
|
|
1302
|
+
providers: [MetaUseReactServiceProvider]
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Utility function to define an adapter error page.
|
|
1308
|
+
*
|
|
1309
|
+
* @param module - The adapter error page module.
|
|
1310
|
+
* @param options - Optional adapter error page options.
|
|
1311
|
+
* @returns The UseReactBlueprint.
|
|
1312
|
+
*/
|
|
1313
|
+
function defineAdapterErrorPage(module, options) {
|
|
1314
|
+
const error = options?.error ?? 'default';
|
|
1315
|
+
const adapterErrorPages = Object.fromEntries([error].flat().map((err) => [
|
|
1316
|
+
err,
|
|
1317
|
+
{
|
|
1318
|
+
...options,
|
|
1319
|
+
module,
|
|
1320
|
+
error: err,
|
|
1321
|
+
isFactory: options?.isClass !== true
|
|
1322
|
+
}
|
|
1323
|
+
]));
|
|
1324
|
+
return {
|
|
1325
|
+
stone: {
|
|
1326
|
+
useReact: {
|
|
1327
|
+
adapterErrorPages
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Defines a Stone React app using a factory-based or class-based main handler.
|
|
1335
|
+
*
|
|
1336
|
+
* @param moduleOrOptions - A factory function or class constructor for the main page.
|
|
1337
|
+
* @param optionsOrBlueprints - Optional application-level configuration.
|
|
1338
|
+
* @param maybeBlueprints - Additional blueprints to merge.
|
|
1339
|
+
* @returns A fully merged Stone blueprint.
|
|
1340
|
+
*/
|
|
1341
|
+
function defineStoneReactApp(moduleOrOptions = {}, optionsOrBlueprints, maybeBlueprints) {
|
|
1342
|
+
let module;
|
|
1343
|
+
let options = {};
|
|
1344
|
+
let blueprints = [];
|
|
1345
|
+
// Pattern: defineStoneReactApp(handler, options?, blueprints?)
|
|
1346
|
+
if (isFunctionModule(moduleOrOptions)) {
|
|
1347
|
+
module = moduleOrOptions;
|
|
1348
|
+
if (isObjectLikeModule(optionsOrBlueprints)) {
|
|
1349
|
+
options = optionsOrBlueprints;
|
|
1350
|
+
blueprints = Array.isArray(maybeBlueprints) ? maybeBlueprints : [];
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
else if (isObjectLikeModule(moduleOrOptions)) { // Pattern: defineStoneReactApp(options, blueprints?)
|
|
1354
|
+
options = moduleOrOptions;
|
|
1355
|
+
blueprints = Array.isArray(optionsOrBlueprints) ? optionsOrBlueprints : [];
|
|
1356
|
+
}
|
|
1357
|
+
const stonePart = {
|
|
1358
|
+
...options,
|
|
1359
|
+
useReact: {
|
|
1360
|
+
...options.useReact
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
if (isNotEmpty(module)) {
|
|
1364
|
+
stonePart.useReact.componentEventHandler = {
|
|
1365
|
+
module,
|
|
1366
|
+
isComponent: true,
|
|
1367
|
+
isClass: options.isClass,
|
|
1368
|
+
isFactory: options.isClass !== true
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
return mergeBlueprints(stoneBlueprint, internalUseReactBlueprint, ...blueprints, { stone: stonePart });
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Utility function to define a page.
|
|
1376
|
+
*
|
|
1377
|
+
* @param module - The EventHandler module.
|
|
1378
|
+
* @param options - Page definition options.
|
|
1379
|
+
* @returns The UseReactBlueprint.
|
|
1380
|
+
*/
|
|
1381
|
+
function definePage(module, options) {
|
|
1382
|
+
return {
|
|
1383
|
+
stone: {
|
|
1384
|
+
router: {
|
|
1385
|
+
definitions: [
|
|
1386
|
+
{
|
|
1387
|
+
...options,
|
|
1388
|
+
method: GET,
|
|
1389
|
+
methods: [],
|
|
1390
|
+
children: undefined,
|
|
1391
|
+
handler: {
|
|
1392
|
+
module,
|
|
1393
|
+
isComponent: true,
|
|
1394
|
+
layout: options?.layout,
|
|
1395
|
+
isClass: options?.isClass,
|
|
1396
|
+
isFactory: options?.isClass !== true
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
]
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Utility function to define a page layout.
|
|
1406
|
+
*
|
|
1407
|
+
* @param module - The layout module.
|
|
1408
|
+
* @param options - Optional page layout definition options.
|
|
1409
|
+
* @returns The UseReactBlueprint.
|
|
1410
|
+
*/
|
|
1411
|
+
function definePageLayout(module, options) {
|
|
1412
|
+
const name = options?.name ?? 'default';
|
|
1413
|
+
return {
|
|
1414
|
+
stone: {
|
|
1415
|
+
useReact: {
|
|
1416
|
+
layout: {
|
|
1417
|
+
[name]: {
|
|
1418
|
+
module,
|
|
1419
|
+
isClass: options?.isClass,
|
|
1420
|
+
isFactory: options?.isClass !== true
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Utility function to define an error page.
|
|
1429
|
+
*
|
|
1430
|
+
* @param module - The layout module.
|
|
1431
|
+
* @param options - Optional page layout definition options.
|
|
1432
|
+
* @returns The UseReactBlueprint.
|
|
1433
|
+
*/
|
|
1434
|
+
function defineErrorPage(module, options) {
|
|
1435
|
+
const error = options?.error ?? 'default';
|
|
1436
|
+
const errorPages = Object.fromEntries([error].flat().map((err) => [
|
|
1437
|
+
err,
|
|
1438
|
+
{
|
|
1439
|
+
...options,
|
|
1440
|
+
module,
|
|
1441
|
+
error: err,
|
|
1442
|
+
isFactory: options?.isClass !== true
|
|
1443
|
+
}
|
|
1444
|
+
]));
|
|
1445
|
+
return {
|
|
1446
|
+
stone: {
|
|
1447
|
+
useReact: {
|
|
1448
|
+
errorPages
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
/**
|
|
1455
|
+
* Create an UseReact response.
|
|
1456
|
+
*
|
|
1457
|
+
* @param options - The options for creating the response.
|
|
1458
|
+
* @returns The React response.
|
|
1459
|
+
*/
|
|
1460
|
+
const reactResponse = (options) => {
|
|
1461
|
+
if (isNotEmpty(options) &&
|
|
1462
|
+
(isNotEmpty(options.url) ||
|
|
1463
|
+
(isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
|
|
1464
|
+
return reactRedirectResponse(options);
|
|
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 });
|
|
1476
|
+
};
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Class representing an UseReactServerErrorHandler.
|
|
1480
|
+
*
|
|
1481
|
+
* Adapter level error handler for React applications.
|
|
1482
|
+
*/
|
|
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();
|
|
1494
|
+
}
|
|
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));
|
|
1509
|
+
}
|
|
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));
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
1524
|
/**
|
|
1525
1525
|
* Blueprint middleware to process and register adapter error page definitions from modules.
|
|
1526
1526
|
*
|