@alepha/react 0.9.5 → 0.10.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/README.md +85 -3
- package/dist/index.browser.js +110 -25
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +163 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +122 -29
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +100 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +164 -45
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
- package/src/descriptors/$page.ts +85 -0
- package/src/hooks/useAlepha.ts +1 -1
- package/src/hooks/useQueryParams.ts +9 -5
- package/src/hooks/useRouterEvents.ts +4 -4
- package/src/hooks/useStore.ts +5 -5
- package/src/providers/ReactBrowserProvider.ts +3 -3
- package/src/providers/ReactBrowserRouterProvider.ts +6 -6
- package/src/providers/ReactPageProvider.ts +2 -3
- package/src/providers/ReactServerProvider.ts +83 -35
- package/src/services/ReactRouter.ts +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,91 @@ const __alepha_router = __toESM(require("@alepha/router"));
|
|
|
38
38
|
//#region src/descriptors/$page.ts
|
|
39
39
|
/**
|
|
40
40
|
* Main descriptor for defining a React route in the application.
|
|
41
|
+
*
|
|
42
|
+
* The $page descriptor is the core building block for creating type-safe, SSR-enabled React routes.
|
|
43
|
+
* It provides a declarative way to define pages with powerful features:
|
|
44
|
+
*
|
|
45
|
+
* **Routing & Navigation**
|
|
46
|
+
* - URL pattern matching with parameters (e.g., `/users/:id`)
|
|
47
|
+
* - Nested routing with parent-child relationships
|
|
48
|
+
* - Type-safe URL parameter and query string validation
|
|
49
|
+
*
|
|
50
|
+
* **Data Loading**
|
|
51
|
+
* - Server-side data fetching with the `resolve` function
|
|
52
|
+
* - Automatic serialization and hydration for SSR
|
|
53
|
+
* - Access to request context, URL params, and parent data
|
|
54
|
+
*
|
|
55
|
+
* **Component Loading**
|
|
56
|
+
* - Direct component rendering or lazy loading for code splitting
|
|
57
|
+
* - Client-only rendering when browser APIs are needed
|
|
58
|
+
* - Automatic fallback handling during hydration
|
|
59
|
+
*
|
|
60
|
+
* **Performance Optimization**
|
|
61
|
+
* - Static generation for pre-rendered pages at build time
|
|
62
|
+
* - Server-side caching with configurable TTL and providers
|
|
63
|
+
* - Code splitting through lazy component loading
|
|
64
|
+
*
|
|
65
|
+
* **Error Handling**
|
|
66
|
+
* - Custom error handlers with support for redirects
|
|
67
|
+
* - Hierarchical error handling (child → parent)
|
|
68
|
+
* - HTTP status code handling (404, 401, etc.)
|
|
69
|
+
*
|
|
70
|
+
* **Page Animations**
|
|
71
|
+
* - CSS-based enter/exit animations
|
|
72
|
+
* - Dynamic animations based on page state
|
|
73
|
+
* - Custom timing and easing functions
|
|
74
|
+
*
|
|
75
|
+
* **Lifecycle Management**
|
|
76
|
+
* - Server response hooks for headers and status codes
|
|
77
|
+
* - Page leave handlers for cleanup (browser only)
|
|
78
|
+
* - Permission-based access control
|
|
79
|
+
*
|
|
80
|
+
* @example Simple page with data fetching
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const userProfile = $page({
|
|
83
|
+
* path: "/users/:id",
|
|
84
|
+
* schema: {
|
|
85
|
+
* params: t.object({ id: t.int() }),
|
|
86
|
+
* query: t.object({ tab: t.optional(t.string()) })
|
|
87
|
+
* },
|
|
88
|
+
* resolve: async ({ params }) => {
|
|
89
|
+
* const user = await userApi.getUser(params.id);
|
|
90
|
+
* return { user };
|
|
91
|
+
* },
|
|
92
|
+
* lazy: () => import("./UserProfile.tsx")
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @example Nested routing with error handling
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const projectSection = $page({
|
|
99
|
+
* path: "/projects/:id",
|
|
100
|
+
* children: () => [projectBoard, projectSettings],
|
|
101
|
+
* resolve: async ({ params }) => {
|
|
102
|
+
* const project = await projectApi.get(params.id);
|
|
103
|
+
* return { project };
|
|
104
|
+
* },
|
|
105
|
+
* errorHandler: (error) => {
|
|
106
|
+
* if (HttpError.is(error, 404)) {
|
|
107
|
+
* return <ProjectNotFound />;
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @example Static generation with caching
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const blogPost = $page({
|
|
116
|
+
* path: "/blog/:slug",
|
|
117
|
+
* static: {
|
|
118
|
+
* entries: posts.map(p => ({ params: { slug: p.slug } }))
|
|
119
|
+
* },
|
|
120
|
+
* resolve: async ({ params }) => {
|
|
121
|
+
* const post = await loadPost(params.slug);
|
|
122
|
+
* return { post };
|
|
123
|
+
* }
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
41
126
|
*/
|
|
42
127
|
const $page = (options) => {
|
|
43
128
|
return (0, __alepha_core.createDescriptor)(PageDescriptor, options);
|
|
@@ -271,7 +356,7 @@ const AlephaContext = (0, react.createContext)(void 0);
|
|
|
271
356
|
*
|
|
272
357
|
* - alepha.state() for state management
|
|
273
358
|
* - alepha.inject() for dependency injection
|
|
274
|
-
* - alepha.emit() for event handling
|
|
359
|
+
* - alepha.events.emit() for event handling
|
|
275
360
|
* etc...
|
|
276
361
|
*/
|
|
277
362
|
const useAlepha = () => {
|
|
@@ -298,10 +383,10 @@ const useRouterEvents = (opts = {}, deps = []) => {
|
|
|
298
383
|
const onEnd = opts.onEnd;
|
|
299
384
|
const onError = opts.onError;
|
|
300
385
|
const onSuccess = opts.onSuccess;
|
|
301
|
-
if (onBegin) subs.push(alepha.on("react:transition:begin", cb(onBegin)));
|
|
302
|
-
if (onEnd) subs.push(alepha.on("react:transition:end", cb(onEnd)));
|
|
303
|
-
if (onError) subs.push(alepha.on("react:transition:error", cb(onError)));
|
|
304
|
-
if (onSuccess) subs.push(alepha.on("react:transition:success", cb(onSuccess)));
|
|
386
|
+
if (onBegin) subs.push(alepha.events.on("react:transition:begin", cb(onBegin)));
|
|
387
|
+
if (onEnd) subs.push(alepha.events.on("react:transition:end", cb(onEnd)));
|
|
388
|
+
if (onError) subs.push(alepha.events.on("react:transition:error", cb(onError)));
|
|
389
|
+
if (onSuccess) subs.push(alepha.events.on("react:transition:success", cb(onSuccess)));
|
|
305
390
|
return () => {
|
|
306
391
|
for (const sub of subs) sub();
|
|
307
392
|
};
|
|
@@ -316,17 +401,17 @@ const useRouterEvents = (opts = {}, deps = []) => {
|
|
|
316
401
|
const useStore = (key, defaultValue) => {
|
|
317
402
|
const alepha = useAlepha();
|
|
318
403
|
(0, react.useMemo)(() => {
|
|
319
|
-
if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
|
|
404
|
+
if (defaultValue != null && alepha.state.get(key) == null) alepha.state.set(key, defaultValue);
|
|
320
405
|
}, [defaultValue]);
|
|
321
|
-
const [state, setState] = (0, react.useState)(alepha.state(key));
|
|
406
|
+
const [state, setState] = (0, react.useState)(alepha.state.get(key));
|
|
322
407
|
(0, react.useEffect)(() => {
|
|
323
408
|
if (!alepha.isBrowser()) return;
|
|
324
|
-
return alepha.on("state:mutate", (ev) => {
|
|
409
|
+
return alepha.events.on("state:mutate", (ev) => {
|
|
325
410
|
if (ev.key === key) setState(ev.value);
|
|
326
411
|
});
|
|
327
412
|
}, []);
|
|
328
413
|
return [state, (value) => {
|
|
329
|
-
alepha.state(key, value);
|
|
414
|
+
alepha.state.set(key, value);
|
|
330
415
|
}];
|
|
331
416
|
};
|
|
332
417
|
|
|
@@ -560,8 +645,8 @@ var ReactPageProvider = class {
|
|
|
560
645
|
return root;
|
|
561
646
|
}
|
|
562
647
|
convertStringObjectToObject = (schema, value) => {
|
|
563
|
-
if (__alepha_core.
|
|
564
|
-
for (const key in schema.properties) if (__alepha_core.
|
|
648
|
+
if (__alepha_core.t.schema.isObject(schema) && typeof value === "object") {
|
|
649
|
+
for (const key in schema.properties) if (__alepha_core.t.schema.isObject(schema.properties[key]) && typeof value[key] === "string") try {
|
|
565
650
|
value[key] = this.alepha.parse(schema.properties[key], decodeURIComponent(value[key]));
|
|
566
651
|
} catch (e) {}
|
|
567
652
|
}
|
|
@@ -848,12 +933,13 @@ var ReactServerProvider = class {
|
|
|
848
933
|
serverTimingProvider = (0, __alepha_core.$inject)(__alepha_server.ServerTimingProvider);
|
|
849
934
|
env = (0, __alepha_core.$env)(envSchema$1);
|
|
850
935
|
ROOT_DIV_REGEX = new RegExp(`<div([^>]*)\\s+id=["']${this.env.REACT_ROOT_ID}["']([^>]*)>(.*?)<\\/div>`, "is");
|
|
936
|
+
preprocessedTemplate = null;
|
|
851
937
|
onConfigure = (0, __alepha_core.$hook)({
|
|
852
938
|
on: "configure",
|
|
853
939
|
handler: async () => {
|
|
854
940
|
const pages = this.alepha.descriptors($page);
|
|
855
941
|
const ssrEnabled = pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
|
|
856
|
-
this.alepha.state("react.server.ssr", ssrEnabled);
|
|
942
|
+
this.alepha.state.set("react.server.ssr", ssrEnabled);
|
|
857
943
|
for (const page of pages) {
|
|
858
944
|
page.render = this.createRenderFunction(page.name);
|
|
859
945
|
page.fetch = async (options) => {
|
|
@@ -909,6 +995,8 @@ var ReactServerProvider = class {
|
|
|
909
995
|
return this.alepha.env.REACT_SERVER_TEMPLATE ?? "<!DOCTYPE html><html lang='en'><head></head><body></body></html>";
|
|
910
996
|
}
|
|
911
997
|
async registerPages(templateLoader) {
|
|
998
|
+
const template = await templateLoader();
|
|
999
|
+
if (template) this.preprocessedTemplate = this.preprocessTemplate(template);
|
|
912
1000
|
for (const page of this.pageApi.getPages()) {
|
|
913
1001
|
if (page.children?.length) continue;
|
|
914
1002
|
this.log.debug(`+ ${page.match} -> ${page.name}`);
|
|
@@ -955,7 +1043,7 @@ var ReactServerProvider = class {
|
|
|
955
1043
|
};
|
|
956
1044
|
const state = entry;
|
|
957
1045
|
this.log.trace("Rendering", { url });
|
|
958
|
-
await this.alepha.emit("react:server:render:begin", { state });
|
|
1046
|
+
await this.alepha.events.emit("react:server:render:begin", { state });
|
|
959
1047
|
const { redirect } = await this.pageApi.createLayers(page, state);
|
|
960
1048
|
if (redirect) return {
|
|
961
1049
|
state,
|
|
@@ -963,13 +1051,14 @@ var ReactServerProvider = class {
|
|
|
963
1051
|
redirect
|
|
964
1052
|
};
|
|
965
1053
|
if (!withIndex && !options.html) {
|
|
966
|
-
this.alepha.state("react.router.state", state);
|
|
1054
|
+
this.alepha.state.set("react.router.state", state);
|
|
967
1055
|
return {
|
|
968
1056
|
state,
|
|
969
1057
|
html: (0, react_dom_server.renderToString)(this.pageApi.root(state))
|
|
970
1058
|
};
|
|
971
1059
|
}
|
|
972
|
-
const
|
|
1060
|
+
const template = this.template ?? "";
|
|
1061
|
+
const html = this.renderToHtml(template, state, options.hydration);
|
|
973
1062
|
if (html instanceof Redirection) return {
|
|
974
1063
|
state,
|
|
975
1064
|
html: "",
|
|
@@ -979,7 +1068,7 @@ var ReactServerProvider = class {
|
|
|
979
1068
|
state,
|
|
980
1069
|
html
|
|
981
1070
|
};
|
|
982
|
-
await this.alepha.emit("react:server:render:end", result);
|
|
1071
|
+
await this.alepha.events.emit("react:server:render:end", result);
|
|
983
1072
|
return result;
|
|
984
1073
|
};
|
|
985
1074
|
}
|
|
@@ -997,7 +1086,7 @@ var ReactServerProvider = class {
|
|
|
997
1086
|
layers: []
|
|
998
1087
|
};
|
|
999
1088
|
const state = entry;
|
|
1000
|
-
if (this.alepha.has(__alepha_server_links.ServerLinksProvider)) this.alepha.state("api", await this.alepha.inject(__alepha_server_links.ServerLinksProvider).getUserApiLinks({
|
|
1089
|
+
if (this.alepha.has(__alepha_server_links.ServerLinksProvider)) this.alepha.state.set("api", await this.alepha.inject(__alepha_server_links.ServerLinksProvider).getUserApiLinks({
|
|
1001
1090
|
user: serverRequest.user,
|
|
1002
1091
|
authorization: serverRequest.headers.authorization
|
|
1003
1092
|
}));
|
|
@@ -1010,7 +1099,7 @@ var ReactServerProvider = class {
|
|
|
1010
1099
|
}
|
|
1011
1100
|
target = target.parent;
|
|
1012
1101
|
}
|
|
1013
|
-
await this.alepha.emit("react:server:render:begin", {
|
|
1102
|
+
await this.alepha.events.emit("react:server:render:begin", {
|
|
1014
1103
|
request: serverRequest,
|
|
1015
1104
|
state
|
|
1016
1105
|
});
|
|
@@ -1032,7 +1121,7 @@ var ReactServerProvider = class {
|
|
|
1032
1121
|
state,
|
|
1033
1122
|
html
|
|
1034
1123
|
};
|
|
1035
|
-
await this.alepha.emit("react:server:render:end", event);
|
|
1124
|
+
await this.alepha.events.emit("react:server:render:end", event);
|
|
1036
1125
|
route.onServerResponse?.(serverRequest);
|
|
1037
1126
|
this.log.trace("Page rendered", { name: route.name });
|
|
1038
1127
|
return event.html;
|
|
@@ -1040,7 +1129,7 @@ var ReactServerProvider = class {
|
|
|
1040
1129
|
}
|
|
1041
1130
|
renderToHtml(template, state, hydration = true) {
|
|
1042
1131
|
const element = this.pageApi.root(state);
|
|
1043
|
-
this.alepha.state("react.router.state", state);
|
|
1132
|
+
this.alepha.state.set("react.router.state", state);
|
|
1044
1133
|
this.serverTimingProvider.beginTiming("renderToString");
|
|
1045
1134
|
let app = "";
|
|
1046
1135
|
try {
|
|
@@ -1078,18 +1167,48 @@ var ReactServerProvider = class {
|
|
|
1078
1167
|
}
|
|
1079
1168
|
return response.html;
|
|
1080
1169
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1170
|
+
preprocessTemplate(template) {
|
|
1171
|
+
const bodyCloseMatch = template.match(/<\/body>/i);
|
|
1172
|
+
const bodyCloseIndex = bodyCloseMatch?.index ?? template.length;
|
|
1173
|
+
const beforeScript = template.substring(0, bodyCloseIndex);
|
|
1174
|
+
const afterScript = template.substring(bodyCloseIndex);
|
|
1175
|
+
const rootDivMatch = beforeScript.match(this.ROOT_DIV_REGEX);
|
|
1176
|
+
if (rootDivMatch) {
|
|
1177
|
+
const beforeDiv = beforeScript.substring(0, rootDivMatch.index);
|
|
1178
|
+
const afterDivStart = rootDivMatch.index + rootDivMatch[0].length;
|
|
1179
|
+
const afterDiv = beforeScript.substring(afterDivStart);
|
|
1180
|
+
const beforeApp = `${beforeDiv}<div${rootDivMatch[1]} id="${this.env.REACT_ROOT_ID}"${rootDivMatch[2]}>`;
|
|
1181
|
+
const afterApp = `</div>${afterDiv}`;
|
|
1182
|
+
return {
|
|
1183
|
+
beforeApp,
|
|
1184
|
+
afterApp,
|
|
1185
|
+
beforeScript: "",
|
|
1186
|
+
afterScript
|
|
1187
|
+
};
|
|
1090
1188
|
}
|
|
1091
|
-
const
|
|
1092
|
-
if (
|
|
1189
|
+
const bodyMatch = beforeScript.match(/<body([^>]*)>/i);
|
|
1190
|
+
if (bodyMatch) {
|
|
1191
|
+
const beforeBody = beforeScript.substring(0, bodyMatch.index + bodyMatch[0].length);
|
|
1192
|
+
const afterBody = beforeScript.substring(bodyMatch.index + bodyMatch[0].length);
|
|
1193
|
+
const beforeApp = `${beforeBody}<div id="${this.env.REACT_ROOT_ID}">`;
|
|
1194
|
+
const afterApp = `</div>${afterBody}`;
|
|
1195
|
+
return {
|
|
1196
|
+
beforeApp,
|
|
1197
|
+
afterApp,
|
|
1198
|
+
beforeScript: "",
|
|
1199
|
+
afterScript
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
return {
|
|
1203
|
+
beforeApp: `<div id="${this.env.REACT_ROOT_ID}">`,
|
|
1204
|
+
afterApp: `</div>`,
|
|
1205
|
+
beforeScript,
|
|
1206
|
+
afterScript
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
fillTemplate(response, app, script) {
|
|
1210
|
+
if (!this.preprocessedTemplate) this.preprocessedTemplate = this.preprocessTemplate(response.html);
|
|
1211
|
+
response.html = this.preprocessedTemplate.beforeApp + app + this.preprocessedTemplate.afterApp + script + this.preprocessedTemplate.afterScript;
|
|
1093
1212
|
}
|
|
1094
1213
|
};
|
|
1095
1214
|
|
|
@@ -1122,8 +1241,8 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
1122
1241
|
meta
|
|
1123
1242
|
};
|
|
1124
1243
|
const state = entry;
|
|
1125
|
-
await this.alepha.emit("react:transition:begin", {
|
|
1126
|
-
previous: this.alepha.state("react.router.state"),
|
|
1244
|
+
await this.alepha.events.emit("react:transition:begin", {
|
|
1245
|
+
previous: this.alepha.state.get("react.router.state"),
|
|
1127
1246
|
state
|
|
1128
1247
|
});
|
|
1129
1248
|
try {
|
|
@@ -1142,7 +1261,7 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
1142
1261
|
index: 0,
|
|
1143
1262
|
path: "/"
|
|
1144
1263
|
});
|
|
1145
|
-
await this.alepha.emit("react:transition:success", { state });
|
|
1264
|
+
await this.alepha.events.emit("react:transition:success", { state });
|
|
1146
1265
|
} catch (e) {
|
|
1147
1266
|
this.log.error("Transition has failed", e);
|
|
1148
1267
|
state.layers = [{
|
|
@@ -1151,7 +1270,7 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
1151
1270
|
index: 0,
|
|
1152
1271
|
path: "/"
|
|
1153
1272
|
}];
|
|
1154
|
-
await this.alepha.emit("react:transition:error", {
|
|
1273
|
+
await this.alepha.events.emit("react:transition:error", {
|
|
1155
1274
|
error: e,
|
|
1156
1275
|
state
|
|
1157
1276
|
});
|
|
@@ -1160,8 +1279,8 @@ var ReactBrowserRouterProvider = class extends __alepha_router.RouterProvider {
|
|
|
1160
1279
|
const layer = previous[i];
|
|
1161
1280
|
if (state.layers[i]?.name !== layer.name) this.pageApi.page(layer.name)?.onLeave?.();
|
|
1162
1281
|
}
|
|
1163
|
-
this.alepha.state("react.router.state", state);
|
|
1164
|
-
await this.alepha.emit("react:transition:end", { state });
|
|
1282
|
+
this.alepha.state.set("react.router.state", state);
|
|
1283
|
+
await this.alepha.events.emit("react:transition:end", { state });
|
|
1165
1284
|
}
|
|
1166
1285
|
root(state) {
|
|
1167
1286
|
return this.pageApi.root(state);
|
|
@@ -1189,7 +1308,7 @@ var ReactBrowserProvider = class {
|
|
|
1189
1308
|
}
|
|
1190
1309
|
transitioning;
|
|
1191
1310
|
get state() {
|
|
1192
|
-
return this.alepha.state("react.router.state");
|
|
1311
|
+
return this.alepha.state.get("react.router.state");
|
|
1193
1312
|
}
|
|
1194
1313
|
/**
|
|
1195
1314
|
* Accessor for Document DOM API.
|
|
@@ -1305,11 +1424,11 @@ var ReactBrowserProvider = class {
|
|
|
1305
1424
|
const hydration = this.getHydrationState();
|
|
1306
1425
|
const previous = hydration?.layers ?? [];
|
|
1307
1426
|
if (hydration) {
|
|
1308
|
-
for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.state(key, value);
|
|
1427
|
+
for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.state.set(key, value);
|
|
1309
1428
|
}
|
|
1310
1429
|
await this.render({ previous });
|
|
1311
1430
|
const element = this.router.root(this.state);
|
|
1312
|
-
await this.alepha.emit("react:browser:render", {
|
|
1431
|
+
await this.alepha.events.emit("react:browser:render", {
|
|
1313
1432
|
element,
|
|
1314
1433
|
root: this.getRootElement(),
|
|
1315
1434
|
hydration,
|
|
@@ -1330,7 +1449,7 @@ var ReactRouter = class {
|
|
|
1330
1449
|
alepha = (0, __alepha_core.$inject)(__alepha_core.Alepha);
|
|
1331
1450
|
pageApi = (0, __alepha_core.$inject)(ReactPageProvider);
|
|
1332
1451
|
get state() {
|
|
1333
|
-
return this.alepha.state("react.router.state");
|
|
1452
|
+
return this.alepha.state.get("react.router.state");
|
|
1334
1453
|
}
|
|
1335
1454
|
get pages() {
|
|
1336
1455
|
return this.pageApi.getPages();
|
|
@@ -1516,7 +1635,7 @@ const useQueryParams = (schema, options = {}) => {
|
|
|
1516
1635
|
const key = options.key ?? "q";
|
|
1517
1636
|
const router = useRouter();
|
|
1518
1637
|
const querystring = router.query[key];
|
|
1519
|
-
const [queryParams, setQueryParams] = (0, react.useState)(decode(alepha, schema, router.query[key]));
|
|
1638
|
+
const [queryParams = {}, setQueryParams] = (0, react.useState)(decode(alepha, schema, router.query[key]));
|
|
1520
1639
|
(0, react.useEffect)(() => {
|
|
1521
1640
|
setQueryParams(decode(alepha, schema, querystring));
|
|
1522
1641
|
}, [querystring]);
|
|
@@ -1536,8 +1655,8 @@ const encode = (alepha, schema, data) => {
|
|
|
1536
1655
|
const decode = (alepha, schema, data) => {
|
|
1537
1656
|
try {
|
|
1538
1657
|
return alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));
|
|
1539
|
-
} catch
|
|
1540
|
-
return
|
|
1658
|
+
} catch {
|
|
1659
|
+
return;
|
|
1541
1660
|
}
|
|
1542
1661
|
};
|
|
1543
1662
|
|