@alepha/react 0.9.1 → 0.9.3

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 CHANGED
@@ -15,6 +15,7 @@ Alternatively, you can install it individually:
15
15
  ```bash
16
16
  npm install @alepha/core @alepha/react
17
17
  ```
18
+
18
19
  ## Module
19
20
 
20
21
  Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.
@@ -30,3 +31,9 @@ type safety and schema validation for route parameters and data.
30
31
  #### $page()
31
32
 
32
33
  Main descriptor for defining a React route in the application.
34
+
35
+ ### Hooks
36
+
37
+ #### useStore()
38
+
39
+ Hook to access and mutate the Alepha state.
@@ -1,5 +1,5 @@
1
- import { $env, $hook, $inject, $logger, $module, Alepha, Descriptor, KIND, NotImplementedError, createDescriptor, t } from "@alepha/core";
2
- import { AlephaServer } from "@alepha/server";
1
+ import { $env, $hook, $inject, $logger, $module, Alepha, Descriptor, KIND, createDescriptor, t } from "@alepha/core";
2
+ import { AlephaServer, HttpClient } from "@alepha/server";
3
3
  import { AlephaServerLinks, LinkProvider } from "@alepha/server-links";
4
4
  import { RouterProvider } from "@alepha/router";
5
5
  import React, { StrictMode, createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
@@ -14,6 +14,12 @@ const $page = (options) => {
14
14
  return createDescriptor(PageDescriptor, options);
15
15
  };
16
16
  var PageDescriptor = class extends Descriptor {
17
+ onInit() {
18
+ if (this.options.static) this.options.cache ??= {
19
+ provider: "memory",
20
+ ttl: [1, "week"]
21
+ };
22
+ }
17
23
  get name() {
18
24
  return this.options.name ?? this.config.propertyKey;
19
25
  }
@@ -22,14 +28,14 @@ var PageDescriptor = class extends Descriptor {
22
28
  * Only valid for server-side rendering, it will throw an error if called on the client-side.
23
29
  */
24
30
  async render(options) {
25
- throw new NotImplementedError("");
31
+ throw new Error("render method is not implemented in this environment");
26
32
  }
27
33
  };
28
34
  $page[KIND] = PageDescriptor;
29
35
 
30
36
  //#endregion
31
37
  //#region src/components/NotFound.tsx
32
- function NotFoundPage() {
38
+ function NotFoundPage(props) {
33
39
  return /* @__PURE__ */ jsx("div", {
34
40
  style: {
35
41
  height: "100vh",
@@ -39,7 +45,8 @@ function NotFoundPage() {
39
45
  alignItems: "center",
40
46
  textAlign: "center",
41
47
  fontFamily: "sans-serif",
42
- padding: "1rem"
48
+ padding: "1rem",
49
+ ...props.style
43
50
  },
44
51
  children: /* @__PURE__ */ jsx("h1", {
45
52
  style: {
@@ -100,7 +107,7 @@ const ErrorViewer = ({ error, alepha }) => {
100
107
  heading: {
101
108
  fontSize: "20px",
102
109
  fontWeight: "bold",
103
- marginBottom: "4px"
110
+ marginBottom: "10px"
104
111
  },
105
112
  name: {
106
113
  fontSize: "16px",
@@ -227,20 +234,31 @@ const RouterContext = createContext(void 0);
227
234
  //#region src/contexts/RouterLayerContext.ts
228
235
  const RouterLayerContext = createContext(void 0);
229
236
 
237
+ //#endregion
238
+ //#region src/contexts/AlephaContext.ts
239
+ const AlephaContext = createContext(void 0);
240
+
241
+ //#endregion
242
+ //#region src/hooks/useAlepha.ts
243
+ const useAlepha = () => {
244
+ const alepha = useContext(AlephaContext);
245
+ if (!alepha) throw new Error("useAlepha must be used within an AlephaContext.Provider");
246
+ return alepha;
247
+ };
248
+
230
249
  //#endregion
231
250
  //#region src/hooks/useRouterEvents.ts
232
251
  const useRouterEvents = (opts = {}, deps = []) => {
233
- const ctx = useContext(RouterContext);
234
- if (!ctx) throw new Error("useRouter must be used within a RouterProvider");
252
+ const alepha = useAlepha();
235
253
  useEffect(() => {
236
- if (!ctx.alepha.isBrowser()) return;
254
+ if (!alepha.isBrowser()) return;
237
255
  const subs = [];
238
256
  const onBegin = opts.onBegin;
239
257
  const onEnd = opts.onEnd;
240
258
  const onError = opts.onError;
241
- if (onBegin) subs.push(ctx.alepha.on("react:transition:begin", { callback: onBegin }));
242
- if (onEnd) subs.push(ctx.alepha.on("react:transition:end", { callback: onEnd }));
243
- if (onError) subs.push(ctx.alepha.on("react:transition:error", { callback: onError }));
259
+ if (onBegin) subs.push(alepha.on("react:transition:begin", { callback: onBegin }));
260
+ if (onEnd) subs.push(alepha.on("react:transition:end", { callback: onEnd }));
261
+ if (onError) subs.push(alepha.on("react:transition:error", { callback: onError }));
244
262
  return () => {
245
263
  for (const sub of subs) sub();
246
264
  };
@@ -306,21 +324,24 @@ const NestedView = (props) => {
306
324
  const layer = useContext(RouterLayerContext);
307
325
  const index = layer?.index ?? 0;
308
326
  const [view, setView] = useState(app?.state.layers[index]?.element);
309
- useRouterEvents({ onEnd: ({ state }) => {
327
+ useRouterEvents({ onEnd: ({ state, context }) => {
328
+ if (app) app.context = context;
310
329
  if (!state.layers[index]?.cache) setView(state.layers[index]?.element);
311
330
  } }, [app]);
312
331
  if (!app) throw new Error("NestedView must be used within a RouterContext.");
313
332
  const element = view ?? props.children ?? null;
314
333
  return /* @__PURE__ */ jsx(ErrorBoundary_default, {
315
- fallback: app.context.onError,
334
+ fallback: (error) => {
335
+ return app.context.onError?.(error, app.context);
336
+ },
316
337
  children: element
317
338
  });
318
339
  };
319
340
  var NestedView_default = NestedView;
320
341
 
321
342
  //#endregion
322
- //#region src/errors/RedirectionError.ts
323
- var RedirectionError = class extends Error {
343
+ //#region src/errors/Redirection.ts
344
+ var Redirection = class extends Error {
324
345
  page;
325
346
  constructor(page) {
326
347
  super("Redirection");
@@ -343,7 +364,7 @@ var PageDescriptorProvider = class {
343
364
  for (const page of this.pages) if (page.name === name) return page;
344
365
  throw new Error(`Page ${name} not found`);
345
366
  }
346
- url(name, options = {}) {
367
+ pathname(name, options = {}) {
347
368
  const page = this.page(name);
348
369
  if (!page) throw new Error(`Page ${name} not found`);
349
370
  let url = page.path ?? "";
@@ -353,14 +374,20 @@ var PageDescriptorProvider = class {
353
374
  parent = parent.parent;
354
375
  }
355
376
  url = this.compile(url, options.params ?? {});
356
- return new URL(url.replace(/\/\/+/g, "/") || "/", options.base ?? `http://localhost`);
377
+ if (options.query) {
378
+ const query = new URLSearchParams(options.query);
379
+ if (query.toString()) url += `?${query.toString()}`;
380
+ }
381
+ return url.replace(/\/\/+/g, "/") || "/";
382
+ }
383
+ url(name, options = {}) {
384
+ return new URL(this.pathname(name, options), options.base ?? `http://localhost`);
357
385
  }
358
386
  root(state, context) {
359
- const root = createElement(RouterContext.Provider, { value: {
360
- alepha: this.alepha,
387
+ const root = createElement(AlephaContext.Provider, { value: this.alepha }, createElement(RouterContext.Provider, { value: {
361
388
  state,
362
389
  context
363
- } }, createElement(NestedView_default, {}, state.layers[0]?.element));
390
+ } }, createElement(NestedView_default, {}, state.layers[0]?.element)));
364
391
  if (this.env.REACT_STRICT_MODE) return createElement(StrictMode, {}, root);
365
392
  return root;
366
393
  }
@@ -429,12 +456,10 @@ var PageDescriptorProvider = class {
429
456
  ...props
430
457
  };
431
458
  } catch (e) {
432
- if (e instanceof RedirectionError) return {
433
- layers: [],
434
- redirect: typeof e.page === "string" ? e.page : this.href(e.page),
459
+ if (e instanceof Redirection) return this.createRedirectionLayer(e.page, {
435
460
  pathname,
436
461
  search
437
- };
462
+ });
438
463
  this.log.error(e);
439
464
  it.error = e;
440
465
  break;
@@ -450,9 +475,21 @@ var PageDescriptorProvider = class {
450
475
  acc += it.route.path ? this.compile(it.route.path, params) : "";
451
476
  const path = acc.replace(/\/+/, "/");
452
477
  const localErrorHandler = this.getErrorHandler(it.route);
453
- if (localErrorHandler) request.onError = localErrorHandler;
454
- if (it.error) {
455
- let element$1 = await request.onError(it.error);
478
+ if (localErrorHandler) {
479
+ const onErrorParent = request.onError;
480
+ request.onError = (error, context$1) => {
481
+ const result = localErrorHandler(error, context$1);
482
+ if (result === void 0) return onErrorParent(error, context$1);
483
+ return result;
484
+ };
485
+ }
486
+ if (it.error) try {
487
+ let element$1 = await request.onError(it.error, request);
488
+ if (element$1 === void 0) throw it.error;
489
+ if (element$1 instanceof Redirection) return this.createRedirectionLayer(element$1.page, {
490
+ pathname,
491
+ search
492
+ });
456
493
  if (element$1 === null) element$1 = this.renderError(it.error);
457
494
  layers.push({
458
495
  props,
@@ -466,6 +503,12 @@ var PageDescriptorProvider = class {
466
503
  route: it.route
467
504
  });
468
505
  break;
506
+ } catch (e) {
507
+ if (e instanceof Redirection) return this.createRedirectionLayer(e.page, {
508
+ pathname,
509
+ search
510
+ });
511
+ throw e;
469
512
  }
470
513
  const element = await this.createElement(it.route, {
471
514
  ...props,
@@ -489,6 +532,14 @@ var PageDescriptorProvider = class {
489
532
  search
490
533
  };
491
534
  }
535
+ createRedirectionLayer(href, context) {
536
+ return {
537
+ layers: [],
538
+ redirect: typeof href === "string" ? href : this.href(href),
539
+ pathname: context.pathname,
540
+ search: context.search
541
+ };
542
+ }
492
543
  getErrorHandler(route) {
493
544
  if (route.errorHandler) return route.errorHandler;
494
545
  let parent = route.parent;
@@ -544,6 +595,7 @@ var PageDescriptorProvider = class {
544
595
  let hasNotFoundHandler = false;
545
596
  const pages = this.alepha.descriptors($page);
546
597
  const hasParent = (it) => {
598
+ if (it.options.parent) return true;
547
599
  for (const page of pages) {
548
600
  const children = page.options.children ? Array.isArray(page.options.children) ? page.options.children : page.options.children() : [];
549
601
  if (children.includes(it)) return true;
@@ -559,7 +611,7 @@ var PageDescriptorProvider = class {
559
611
  name: "notFound",
560
612
  cache: true,
561
613
  component: NotFoundPage,
562
- afterHandler: ({ reply }) => {
614
+ onServerResponse: ({ reply }) => {
563
615
  reply.status = 404;
564
616
  }
565
617
  });
@@ -567,6 +619,12 @@ var PageDescriptorProvider = class {
567
619
  });
568
620
  map(pages, target) {
569
621
  const children = target.options.children ? Array.isArray(target.options.children) ? target.options.children : target.options.children() : [];
622
+ const getChildrenFromParent = (it) => {
623
+ const children$1 = [];
624
+ for (const page of pages) if (page.options.parent === it) children$1.push(page);
625
+ return children$1;
626
+ };
627
+ children.push(...getChildrenFromParent(target));
570
628
  return {
571
629
  ...target.options,
572
630
  name: target.name,
@@ -688,6 +746,10 @@ var BrowserRouterProvider = class extends RouterProvider {
688
746
  options.state.pathname = state.pathname;
689
747
  options.state.search = state.search;
690
748
  }
749
+ if (options.previous) for (let i = 0; i < options.previous.length; i++) {
750
+ const layer = options.previous[i];
751
+ if (state.layers[i]?.name !== layer.name) this.pageDescriptorProvider.page(layer.name)?.onLeave?.();
752
+ }
691
753
  await this.alepha.emit("react:transition:end", {
692
754
  state: options.state,
693
755
  context
@@ -762,15 +824,11 @@ var ReactBrowserProvider = class {
762
824
  }
763
825
  async go(url, options = {}) {
764
826
  const result = await this.render({ url });
765
- if (result.context.url.pathname !== url) {
766
- this.pushState(result.context.url.pathname);
767
- return;
768
- }
769
- if (options.replace) {
770
- this.pushState(url);
827
+ if (result.context.url.pathname + result.context.url.search !== url) {
828
+ this.pushState(result.context.url.pathname + result.context.url.search);
771
829
  return;
772
830
  }
773
- this.pushState(url);
831
+ this.pushState(url, options.replace);
774
832
  }
775
833
  async render(options = {}) {
776
834
  const previous = options.previous ?? this.state.layers;
@@ -799,7 +857,13 @@ var ReactBrowserProvider = class {
799
857
  handler: async () => {
800
858
  const hydration = this.getHydrationState();
801
859
  const previous = hydration?.layers ?? [];
802
- if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink(link);
860
+ if (hydration) {
861
+ for (const [key, value] of Object.entries(hydration)) if (key !== "layers" && key !== "links") this.alepha.state(key, value);
862
+ }
863
+ if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink({
864
+ ...link,
865
+ prefix: hydration.links.prefix
866
+ });
803
867
  const { context } = await this.render({ previous });
804
868
  await this.alepha.emit("react:browser:render", {
805
869
  state: this.state,
@@ -857,13 +921,23 @@ var ReactBrowserRenderer = class {
857
921
  //#endregion
858
922
  //#region src/hooks/RouterHookApi.ts
859
923
  var RouterHookApi = class {
860
- constructor(pages, context, state, layer, browser) {
924
+ constructor(pages, context, state, layer, pageApi, browser) {
861
925
  this.pages = pages;
862
926
  this.context = context;
863
927
  this.state = state;
864
928
  this.layer = layer;
929
+ this.pageApi = pageApi;
865
930
  this.browser = browser;
866
931
  }
932
+ path(name, config = {}) {
933
+ return this.pageApi.pathname(name, {
934
+ params: {
935
+ ...this.context.params,
936
+ ...config.params
937
+ },
938
+ query: config.query
939
+ });
940
+ }
867
941
  getURL() {
868
942
  if (!this.browser) return this.context.url;
869
943
  return new URL(this.location.href);
@@ -905,23 +979,23 @@ var RouterHookApi = class {
905
979
  }
906
980
  async go(path, options) {
907
981
  for (const page of this.pages) if (page.name === path) {
908
- path = page.path ?? "";
909
- break;
982
+ await this.browser?.go(this.path(path, options), options);
983
+ return;
910
984
  }
911
- await this.browser?.go(this.createHref(path, this.layer, options), options);
985
+ await this.browser?.go(path, options);
912
986
  }
913
987
  anchor(path, options = {}) {
988
+ let href = path;
914
989
  for (const page of this.pages) if (page.name === path) {
915
- path = page.path ?? "";
990
+ href = this.path(path, options);
916
991
  break;
917
992
  }
918
- const href = this.createHref(path, this.layer, options);
919
993
  return {
920
994
  href,
921
995
  onClick: (ev) => {
922
996
  ev.stopPropagation();
923
997
  ev.preventDefault();
924
- this.go(path, options).catch(console.error);
998
+ this.go(href, options).catch(console.error);
925
999
  }
926
1000
  };
927
1001
  }
@@ -943,33 +1017,25 @@ var RouterHookApi = class {
943
1017
  //#endregion
944
1018
  //#region src/hooks/useRouter.ts
945
1019
  const useRouter = () => {
1020
+ const alepha = useAlepha();
946
1021
  const ctx = useContext(RouterContext);
947
1022
  const layer = useContext(RouterLayerContext);
948
1023
  if (!ctx || !layer) throw new Error("useRouter must be used within a RouterProvider");
949
1024
  const pages = useMemo(() => {
950
- return ctx.alepha.inject(PageDescriptorProvider).getPages();
1025
+ return alepha.inject(PageDescriptorProvider).getPages();
951
1026
  }, []);
952
- return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer, ctx.alepha.isBrowser() ? ctx.alepha.inject(ReactBrowserProvider) : void 0), [layer]);
1027
+ return useMemo(() => new RouterHookApi(pages, ctx.context, ctx.state, layer, alepha.inject(PageDescriptorProvider), alepha.isBrowser() ? alepha.inject(ReactBrowserProvider) : void 0), [layer]);
953
1028
  };
954
1029
 
955
1030
  //#endregion
956
1031
  //#region src/components/Link.tsx
957
1032
  const Link = (props) => {
958
- React.useContext(RouterContext);
959
1033
  const router = useRouter();
960
- const to = typeof props.to === "string" ? props.to : props.to.options.path;
961
- if (!to) return null;
962
- const can = typeof props.to === "string" ? void 0 : props.to.options.can;
963
- if (can && !can()) return null;
964
- const name = typeof props.to === "string" ? void 0 : props.to.options.name;
965
- const anchorProps = {
966
- ...props,
967
- to: void 0
968
- };
1034
+ const { to,...anchorProps } = props;
969
1035
  return /* @__PURE__ */ jsx("a", {
970
1036
  ...router.anchor(to),
971
1037
  ...anchorProps,
972
- children: props.children ?? name
1038
+ children: props.children
973
1039
  });
974
1040
  };
975
1041
  var Link_default = Link;
@@ -981,22 +1047,21 @@ const useActive = (path) => {
981
1047
  const ctx = useContext(RouterContext);
982
1048
  const layer = useContext(RouterLayerContext);
983
1049
  if (!ctx || !layer) throw new Error("useRouter must be used within a RouterProvider");
984
- let name;
985
- if (typeof path === "object" && path.options.name) name = path.options.name;
986
1050
  const [current, setCurrent] = useState(ctx.state.pathname);
987
- const href = useMemo(() => router.createHref(path, layer), [path, layer]);
1051
+ const href = useMemo(() => router.createHref(path ?? "", layer), [path, layer]);
988
1052
  const [isPending, setPending] = useState(false);
989
- const isActive = current === href;
990
- useRouterEvents({ onEnd: ({ state }) => setCurrent(state.pathname) });
1053
+ const isActive = current === href || current === `${href}/` || `${current}/` === href;
1054
+ useRouterEvents({ onEnd: ({ state }) => {
1055
+ path && setCurrent(state.pathname);
1056
+ } }, [path]);
991
1057
  return {
992
- name,
993
1058
  isPending,
994
1059
  isActive,
995
1060
  anchorProps: {
996
1061
  href,
997
1062
  onClick: (ev) => {
998
- ev.stopPropagation();
999
- ev.preventDefault();
1063
+ ev?.stopPropagation();
1064
+ ev?.preventDefault();
1000
1065
  if (isActive) return;
1001
1066
  if (isPending) return;
1002
1067
  setPending(true);
@@ -1009,45 +1074,62 @@ const useActive = (path) => {
1009
1074
  };
1010
1075
 
1011
1076
  //#endregion
1012
- //#region src/hooks/useAlepha.ts
1013
- const useAlepha = () => {
1014
- const routerContext = useContext(RouterContext);
1015
- if (!routerContext) throw new Error("useAlepha must be used within a RouterProvider");
1016
- return routerContext.alepha;
1077
+ //#region src/hooks/useInject.ts
1078
+ const useInject = (service) => {
1079
+ const alepha = useAlepha();
1080
+ return useMemo(() => alepha.inject(service), []);
1017
1081
  };
1018
1082
 
1019
1083
  //#endregion
1020
- //#region src/hooks/useInject.ts
1021
- const useInject = (clazz) => {
1022
- const ctx = useContext(RouterContext);
1023
- if (!ctx) throw new Error("useRouter must be used within a <RouterProvider>");
1024
- return useMemo(() => ctx.alepha.inject(clazz), []);
1084
+ //#region src/hooks/useStore.ts
1085
+ /**
1086
+ * Hook to access and mutate the Alepha state.
1087
+ */
1088
+ const useStore = (key, defaultValue) => {
1089
+ const alepha = useAlepha();
1090
+ useMemo(() => {
1091
+ if (defaultValue != null && alepha.state(key) == null) alepha.state(key, defaultValue);
1092
+ }, [defaultValue]);
1093
+ const [state, setState] = useState(alepha.state(key));
1094
+ useEffect(() => {
1095
+ if (!alepha.isBrowser()) return;
1096
+ return alepha.on("state:mutate", (ev) => {
1097
+ if (ev.key === key) setState(ev.value);
1098
+ });
1099
+ }, []);
1100
+ if (!alepha.isBrowser()) {
1101
+ const value = alepha.context.get(key);
1102
+ if (value !== null) return [value, (_) => {}];
1103
+ }
1104
+ return [state, (value) => {
1105
+ alepha.state(key, value);
1106
+ }];
1025
1107
  };
1026
1108
 
1027
1109
  //#endregion
1028
1110
  //#region src/hooks/useClient.ts
1029
1111
  const useClient = (_scope) => {
1112
+ useStore("user");
1030
1113
  return useInject(LinkProvider).client();
1031
1114
  };
1032
1115
 
1033
1116
  //#endregion
1034
1117
  //#region src/hooks/useQueryParams.ts
1035
1118
  const useQueryParams = (schema, options = {}) => {
1036
- const ctx = useContext(RouterContext);
1037
- if (!ctx) throw new Error("useQueryParams must be used within a RouterProvider");
1119
+ const alepha = useAlepha();
1038
1120
  const key = options.key ?? "q";
1039
1121
  const router = useRouter();
1040
1122
  const querystring = router.query[key];
1041
- const [queryParams, setQueryParams] = useState(decode(ctx.alepha, schema, router.query[key]));
1123
+ const [queryParams, setQueryParams] = useState(decode(alepha, schema, router.query[key]));
1042
1124
  useEffect(() => {
1043
- setQueryParams(decode(ctx.alepha, schema, querystring));
1125
+ setQueryParams(decode(alepha, schema, querystring));
1044
1126
  }, [querystring]);
1045
1127
  return [queryParams, (queryParams$1) => {
1046
1128
  setQueryParams(queryParams$1);
1047
1129
  router.setQueryParams((data) => {
1048
1130
  return {
1049
1131
  ...data,
1050
- [key]: encode(ctx.alepha, schema, queryParams$1)
1132
+ [key]: encode(alepha, schema, queryParams$1)
1051
1133
  };
1052
1134
  });
1053
1135
  }];
@@ -1066,14 +1148,50 @@ const decode = (alepha, schema, data) => {
1066
1148
  //#endregion
1067
1149
  //#region src/hooks/useRouterState.ts
1068
1150
  const useRouterState = () => {
1069
- const ctx = useContext(RouterContext);
1151
+ const router = useContext(RouterContext);
1070
1152
  const layer = useContext(RouterLayerContext);
1071
- if (!ctx || !layer) throw new Error("useRouter must be used within a RouterProvider");
1072
- const [state, setState] = useState(ctx.state);
1153
+ if (!router || !layer) throw new Error("useRouterState must be used within a RouterContext.Provider");
1154
+ const [state, setState] = useState(router.state);
1073
1155
  useRouterEvents({ onEnd: ({ state: state$1 }) => setState({ ...state$1 }) });
1074
1156
  return state;
1075
1157
  };
1076
1158
 
1159
+ //#endregion
1160
+ //#region src/hooks/useSchema.ts
1161
+ const useSchema = (action) => {
1162
+ const name = action.name;
1163
+ const alepha = useAlepha();
1164
+ const httpClient = useInject(HttpClient);
1165
+ const linkProvider = useInject(LinkProvider);
1166
+ const [schema, setSchema] = useState(ssrSchemaLoading(alepha, name));
1167
+ useEffect(() => {
1168
+ if (!schema.loading) return;
1169
+ const opts = { cache: true };
1170
+ httpClient.fetch(`${linkProvider.URL_LINKS}/${name}/schema`, {}, opts).then((it) => setSchema(it.data));
1171
+ }, [name]);
1172
+ return schema;
1173
+ };
1174
+ /**
1175
+ * Get an action schema during server-side rendering (SSR) or client-side rendering (CSR).
1176
+ */
1177
+ const ssrSchemaLoading = (alepha, name) => {
1178
+ if (!alepha.isBrowser()) {
1179
+ const links = alepha.context.get("links")?.links ?? [];
1180
+ const can = links.find((it) => it.name === name);
1181
+ if (can) {
1182
+ const schema$1 = alepha.inject(LinkProvider).links?.find((it) => it.name === name)?.schema;
1183
+ if (schema$1) {
1184
+ can.schema = schema$1;
1185
+ return schema$1;
1186
+ }
1187
+ }
1188
+ return { loading: true };
1189
+ }
1190
+ const schema = alepha.inject(LinkProvider).links?.find((it) => it.name === name)?.schema;
1191
+ if (schema) return schema;
1192
+ return { loading: true };
1193
+ };
1194
+
1077
1195
  //#endregion
1078
1196
  //#region src/index.browser.ts
1079
1197
  const AlephaReact = $module({
@@ -1089,5 +1207,5 @@ const AlephaReact = $module({
1089
1207
  });
1090
1208
 
1091
1209
  //#endregion
1092
- export { $page, AlephaReact, BrowserRouterProvider, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, PageDescriptorProvider, ReactBrowserProvider, RedirectionError, RouterContext, RouterHookApi, RouterLayerContext, isPageRoute, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState };
1210
+ export { $page, AlephaContext, AlephaReact, BrowserRouterProvider, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, PageDescriptorProvider, ReactBrowserProvider, Redirection, RouterContext, RouterHookApi, RouterLayerContext, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
1093
1211
  //# sourceMappingURL=index.browser.js.map