@alepha/react 0.13.1 → 0.13.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.
Files changed (54) hide show
  1. package/dist/auth/index.browser.js +10 -5
  2. package/dist/auth/index.browser.js.map +1 -1
  3. package/dist/auth/index.d.ts +401 -330
  4. package/dist/auth/index.js +12 -7
  5. package/dist/auth/index.js.map +1 -1
  6. package/dist/core/index.browser.js +50 -28
  7. package/dist/core/index.browser.js.map +1 -1
  8. package/dist/core/index.d.ts +382 -344
  9. package/dist/core/index.js +65 -37
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/core/index.native.js +381 -0
  12. package/dist/core/index.native.js.map +1 -0
  13. package/dist/form/index.d.ts +2 -2
  14. package/dist/head/index.browser.js +28 -17
  15. package/dist/head/index.browser.js.map +1 -1
  16. package/dist/head/index.d.ts +270 -267
  17. package/dist/head/index.js +29 -17
  18. package/dist/head/index.js.map +1 -1
  19. package/dist/i18n/index.d.ts +20 -20
  20. package/dist/i18n/index.js +12 -12
  21. package/dist/i18n/index.js.map +1 -1
  22. package/dist/websocket/index.d.ts +7 -7
  23. package/dist/websocket/index.js.map +1 -1
  24. package/package.json +21 -12
  25. package/src/auth/index.ts +1 -1
  26. package/src/auth/providers/ReactAuthProvider.ts +1 -1
  27. package/src/auth/services/ReactAuth.ts +15 -5
  28. package/src/core/components/NestedView.tsx +6 -2
  29. package/src/core/components/NotFound.tsx +10 -6
  30. package/src/core/hooks/useStore.ts +4 -4
  31. package/src/core/index.browser.ts +2 -2
  32. package/src/core/index.native.ts +1 -1
  33. package/src/core/index.shared-router.ts +1 -1
  34. package/src/core/index.ts +3 -3
  35. package/src/core/{descriptors → primitives}/$page.ts +20 -20
  36. package/src/core/providers/ReactBrowserProvider.ts +2 -2
  37. package/src/core/providers/ReactBrowserRouterProvider.ts +3 -2
  38. package/src/core/providers/ReactPageProvider.ts +28 -11
  39. package/src/core/providers/ReactServerProvider.ts +34 -23
  40. package/src/core/services/ReactPageServerService.ts +6 -6
  41. package/src/core/services/ReactPageService.ts +6 -6
  42. package/src/core/services/ReactRouter.ts +19 -3
  43. package/src/head/index.browser.ts +3 -3
  44. package/src/head/index.ts +4 -4
  45. package/src/head/interfaces/Head.ts +1 -0
  46. package/src/head/{descriptors → primitives}/$head.ts +10 -7
  47. package/src/head/providers/BrowserHeadProvider.ts +13 -0
  48. package/src/head/providers/HeadProvider.ts +11 -9
  49. package/src/head/providers/ServerHeadProvider.ts +6 -0
  50. package/src/i18n/hooks/useI18n.ts +2 -2
  51. package/src/i18n/index.ts +3 -3
  52. package/src/i18n/{descriptors → primitives}/$dictionary.ts +8 -8
  53. package/src/i18n/providers/I18nProvider.ts +5 -5
  54. package/src/websocket/hooks/useRoom.tsx +3 -3
@@ -1,4 +1,4 @@
1
- import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, Atom, Descriptor, KIND, createDescriptor, t } from "alepha";
1
+ import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, Atom, KIND, Primitive, createPrimitive, t } from "alepha";
2
2
  import { AlephaDateTime, DateTimeProvider } from "alepha/datetime";
3
3
  import { AlephaServer, HttpClient, ServerProvider, ServerRouterProvider, ServerTimingProvider } from "alepha/server";
4
4
  import { AlephaServerCache } from "alepha/server/cache";
@@ -23,11 +23,11 @@ var ReactPageService = class {
23
23
  };
24
24
 
25
25
  //#endregion
26
- //#region src/core/descriptors/$page.ts
26
+ //#region src/core/primitives/$page.ts
27
27
  /**
28
- * Main descriptor for defining a React route in the application.
28
+ * Main primitive for defining a React route in the application.
29
29
  *
30
- * The $page descriptor is the core building block for creating type-safe, SSR-enabled React routes.
30
+ * The $page primitive is the core building block for creating type-safe, SSR-enabled React routes.
31
31
  * It provides a declarative way to define pages with powerful features:
32
32
  *
33
33
  * **Routing & Navigation**
@@ -113,9 +113,9 @@ var ReactPageService = class {
113
113
  * ```
114
114
  */
115
115
  const $page = (options) => {
116
- return createDescriptor(PageDescriptor, options);
116
+ return createPrimitive(PagePrimitive, options);
117
117
  };
118
- var PageDescriptor = class extends Descriptor {
118
+ var PagePrimitive = class extends Primitive {
119
119
  reactPageService = $inject(ReactPageService);
120
120
  onInit() {
121
121
  if (this.options.static) this.options.cache ??= { store: {
@@ -145,7 +145,7 @@ var PageDescriptor = class extends Descriptor {
145
145
  return this.options.path || "";
146
146
  }
147
147
  };
148
- $page[KIND] = PageDescriptor;
148
+ $page[KIND] = PagePrimitive;
149
149
 
150
150
  //#endregion
151
151
  //#region src/core/components/ClientOnly.tsx
@@ -400,9 +400,9 @@ const useEvents = (opts, deps) => {
400
400
  function useStore(target, defaultValue) {
401
401
  const alepha = useAlepha();
402
402
  useMemo(() => {
403
- if (defaultValue != null && alepha.state.get(target) == null) alepha.state.set(target, defaultValue);
403
+ if (defaultValue != null && alepha.store.get(target) == null) alepha.store.set(target, defaultValue);
404
404
  }, [defaultValue]);
405
- const [state, setState] = useState(alepha.state.get(target));
405
+ const [state, setState] = useState(alepha.store.get(target));
406
406
  useEffect(() => {
407
407
  if (!alepha.isBrowser()) return;
408
408
  const key = target instanceof Atom ? target.key : target;
@@ -411,7 +411,7 @@ function useStore(target, defaultValue) {
411
411
  });
412
412
  }, []);
413
413
  return [state, (value) => {
414
- alepha.state.set(target, value);
414
+ alepha.store.set(target, value);
415
415
  }];
416
416
  }
417
417
 
@@ -487,7 +487,8 @@ const NestedView = (props) => {
487
487
  useEvents({
488
488
  "react:transition:begin": async ({ previous, state: state$1 }) => {
489
489
  const layer = previous.layers[index];
490
- if (`${state$1.url.pathname}/`.startsWith(`${layer?.path}/`)) return;
490
+ if (!layer) return;
491
+ if (`${state$1.url.pathname}/`.startsWith(`${layer.path}/`)) return;
491
492
  const animationExit = parseAnimation(layer.route?.animation, state$1, "exit");
492
493
  if (animationExit) {
493
494
  const duration = animationExit.duration || 200;
@@ -579,25 +580,35 @@ function parseAnimation(animationLike, state, type = "enter") {
579
580
  //#endregion
580
581
  //#region src/core/components/NotFound.tsx
581
582
  function NotFoundPage(props) {
582
- return /* @__PURE__ */ jsx("div", {
583
+ return /* @__PURE__ */ jsxs("div", {
583
584
  style: {
584
- height: "100vh",
585
+ width: "100%",
586
+ minHeight: "90vh",
587
+ boxSizing: "border-box",
585
588
  display: "flex",
586
589
  flexDirection: "column",
587
590
  justifyContent: "center",
588
591
  alignItems: "center",
589
592
  textAlign: "center",
590
- fontFamily: "sans-serif",
591
- padding: "1rem",
593
+ fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
594
+ padding: "2rem",
592
595
  ...props.style
593
596
  },
594
- children: /* @__PURE__ */ jsx("h1", {
597
+ children: [/* @__PURE__ */ jsx("div", {
595
598
  style: {
596
- fontSize: "1rem",
597
- marginBottom: "0.5rem"
599
+ fontSize: "6rem",
600
+ fontWeight: 200,
601
+ lineHeight: 1
598
602
  },
599
- children: "404 - This page does not exist"
600
- })
603
+ children: "404"
604
+ }), /* @__PURE__ */ jsx("div", {
605
+ style: {
606
+ fontSize: "0.875rem",
607
+ marginTop: "1rem",
608
+ opacity: .6
609
+ },
610
+ children: "Page not found"
611
+ })]
601
612
  });
602
613
  }
603
614
 
@@ -626,6 +637,7 @@ var ReactPageProvider = class {
626
637
  if (!path.includes(":") && !path.includes("*")) pages.push({
627
638
  ...page,
628
639
  name: params[Object.keys(params)[0]],
640
+ staticName: page.name,
629
641
  path,
630
642
  ...entry
631
643
  });
@@ -856,7 +868,7 @@ var ReactPageProvider = class {
856
868
  on: "configure",
857
869
  handler: () => {
858
870
  let hasNotFoundHandler = false;
859
- const pages = this.alepha.descriptors($page);
871
+ const pages = this.alepha.primitives($page);
860
872
  const hasParent = (it) => {
861
873
  if (it.options.parent) return true;
862
874
  for (const page of pages) if ((page.options.children ? Array.isArray(page.options.children) ? page.options.children : page.options.children() : []).includes(it)) return true;
@@ -969,8 +981,8 @@ var ReactServerProvider = class {
969
981
  onConfigure = $hook({
970
982
  on: "configure",
971
983
  handler: async () => {
972
- const ssrEnabled = this.alepha.descriptors($page).length > 0 && this.env.REACT_SSR_ENABLED !== false;
973
- this.alepha.state.set("alepha.react.server.ssr", ssrEnabled);
984
+ const ssrEnabled = this.alepha.primitives($page).length > 0 && this.env.REACT_SSR_ENABLED !== false;
985
+ this.alepha.store.set("alepha.react.server.ssr", ssrEnabled);
974
986
  if (this.alepha.isViteDev()) {
975
987
  await this.configureVite(ssrEnabled);
976
988
  return;
@@ -1011,8 +1023,7 @@ var ReactServerProvider = class {
1011
1023
  async registerPages(templateLoader) {
1012
1024
  const template = await templateLoader();
1013
1025
  if (template) this.preprocessedTemplate = this.preprocessTemplate(template);
1014
- for (const page of this.pageApi.getPages()) {
1015
- if (page.children?.length) continue;
1026
+ for (const page of this.pageApi.getPages()) if (page.component || page.lazy) {
1016
1027
  this.log.debug(`+ ${page.match} -> ${page.name}`);
1017
1028
  this.serverRouterProvider.createRoute({
1018
1029
  ...page,
@@ -1076,7 +1087,7 @@ var ReactServerProvider = class {
1076
1087
  redirect
1077
1088
  };
1078
1089
  if (!options.html) {
1079
- this.alepha.state.set("alepha.react.router.state", state);
1090
+ this.alepha.store.set("alepha.react.router.state", state);
1080
1091
  return {
1081
1092
  state,
1082
1093
  html: renderToString(this.pageApi.root(state))
@@ -1109,13 +1120,15 @@ var ReactServerProvider = class {
1109
1120
  onError: () => null,
1110
1121
  layers: []
1111
1122
  };
1112
- if (this.alepha.has(ServerLinksProvider)) this.alepha.state.set("alepha.server.request.apiLinks", await this.alepha.inject(ServerLinksProvider).getUserApiLinks({
1123
+ state.name = route.name;
1124
+ if (this.alepha.has(ServerLinksProvider)) this.alepha.store.set("alepha.server.request.apiLinks", await this.alepha.inject(ServerLinksProvider).getUserApiLinks({
1113
1125
  user: serverRequest.user,
1114
1126
  authorization: serverRequest.headers.authorization
1115
1127
  }));
1116
1128
  let target = route;
1117
1129
  while (target) {
1118
1130
  if (route.can && !route.can()) {
1131
+ this.log.warn(`Access to page '${route.name}' is forbidden by can() check`);
1119
1132
  reply.status = 403;
1120
1133
  reply.headers["content-type"] = "text/plain";
1121
1134
  return "Forbidden";
@@ -1129,7 +1142,10 @@ var ReactServerProvider = class {
1129
1142
  this.serverTimingProvider.beginTiming("createLayers");
1130
1143
  const { redirect } = await this.pageApi.createLayers(route, state);
1131
1144
  this.serverTimingProvider.endTiming("createLayers");
1132
- if (redirect) return reply.redirect(redirect);
1145
+ if (redirect) {
1146
+ this.log.debug("Resolver resulted in redirection", { redirect });
1147
+ return reply.redirect(redirect);
1148
+ }
1133
1149
  reply.headers["content-type"] = "text/html";
1134
1150
  reply.headers["cache-control"] = "no-store, no-cache, must-revalidate, proxy-revalidate";
1135
1151
  reply.headers.pragma = "no-cache";
@@ -1137,8 +1153,10 @@ var ReactServerProvider = class {
1137
1153
  const html = this.renderToHtml(template, state);
1138
1154
  if (html instanceof Redirection) {
1139
1155
  reply.redirect(typeof html.redirect === "string" ? html.redirect : this.pageApi.href(html.redirect));
1156
+ this.log.debug("Rendering resulted in redirection", { redirect: html.redirect });
1140
1157
  return;
1141
1158
  }
1159
+ this.log.trace("Page rendered to HTML successfully");
1142
1160
  const event = {
1143
1161
  request: serverRequest,
1144
1162
  state,
@@ -1152,7 +1170,7 @@ var ReactServerProvider = class {
1152
1170
  }
1153
1171
  renderToHtml(template, state, hydration = true) {
1154
1172
  const element = this.pageApi.root(state);
1155
- this.alepha.state.set("alepha.react.router.state", state);
1173
+ this.alepha.store.set("alepha.react.router.state", state);
1156
1174
  this.serverTimingProvider.beginTiming("renderToString");
1157
1175
  let app = "";
1158
1176
  try {
@@ -1284,13 +1302,14 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
1284
1302
  };
1285
1303
  await this.alepha.events.emit("react:action:begin", { type: "transition" });
1286
1304
  await this.alepha.events.emit("react:transition:begin", {
1287
- previous: this.alepha.state.get("alepha.react.router.state"),
1305
+ previous: this.alepha.store.get("alepha.react.router.state"),
1288
1306
  state
1289
1307
  });
1290
1308
  try {
1291
1309
  const { route, params } = this.match(pathname);
1292
1310
  const query = {};
1293
1311
  if (search) for (const [key, value] of new URLSearchParams(search).entries()) query[key] = String(value);
1312
+ state.name = route?.page.name;
1294
1313
  state.query = query;
1295
1314
  state.params = params ?? {};
1296
1315
  if (isPageRoute(route)) {
@@ -1326,7 +1345,7 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
1326
1345
  const layer = previous[i];
1327
1346
  if (state.layers[i]?.name !== layer.name) this.pageApi.page(layer.name)?.onLeave?.();
1328
1347
  }
1329
- this.alepha.state.set("alepha.react.router.state", state);
1348
+ this.alepha.store.set("alepha.react.router.state", state);
1330
1349
  await this.alepha.events.emit("react:action:end", { type: "transition" });
1331
1350
  await this.alepha.events.emit("react:transition:end", { state });
1332
1351
  }
@@ -1364,7 +1383,7 @@ var ReactBrowserProvider = class {
1364
1383
  }
1365
1384
  transitioning;
1366
1385
  get state() {
1367
- return this.alepha.state.get("alepha.react.router.state");
1386
+ return this.alepha.store.get("alepha.react.router.state");
1368
1387
  }
1369
1388
  /**
1370
1389
  * Accessor for Document DOM API.
@@ -1481,7 +1500,7 @@ var ReactBrowserProvider = class {
1481
1500
  const hydration = this.getHydrationState();
1482
1501
  const previous = hydration?.layers ?? [];
1483
1502
  if (hydration) {
1484
- for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.state.set(key, value);
1503
+ for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.store.set(key, value);
1485
1504
  }
1486
1505
  await this.render({ previous });
1487
1506
  const element = this.router.root(this.state);
@@ -1506,7 +1525,7 @@ var ReactRouter = class {
1506
1525
  alepha = $inject(Alepha);
1507
1526
  pageApi = $inject(ReactPageProvider);
1508
1527
  get state() {
1509
- return this.alepha.state.get("alepha.react.router.state");
1528
+ return this.alepha.store.get("alepha.react.router.state");
1510
1529
  }
1511
1530
  get pages() {
1512
1531
  return this.pageApi.getPages();
@@ -1523,6 +1542,15 @@ var ReactRouter = class {
1523
1542
  if (options.startWith && !isActive) isActive = current.startsWith(href);
1524
1543
  return isActive;
1525
1544
  }
1545
+ node(name, config = {}) {
1546
+ const page = this.pageApi.page(name);
1547
+ return {
1548
+ ...page,
1549
+ label: page.label ?? page.name,
1550
+ href: this.path(name, config),
1551
+ children: void 0
1552
+ };
1553
+ }
1526
1554
  path(name, config = {}) {
1527
1555
  return this.pageApi.pathname(name, {
1528
1556
  params: {
@@ -2001,7 +2029,7 @@ const decode = (alepha, schema, data) => {
2001
2029
  /**
2002
2030
  * Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.
2003
2031
  *
2004
- * The React module enables building modern React applications using the `$page` descriptor on class properties.
2032
+ * The React module enables building modern React applications using the `$page` primitive on class properties.
2005
2033
  * It delivers seamless server-side rendering, automatic code splitting, and client-side navigation with full
2006
2034
  * type safety and schema validation for route parameters and data.
2007
2035
  *
@@ -2010,7 +2038,7 @@ const decode = (alepha, schema, data) => {
2010
2038
  */
2011
2039
  const AlephaReact = $module({
2012
2040
  name: "alepha.react",
2013
- descriptors: [$page],
2041
+ primitives: [$page],
2014
2042
  services: [
2015
2043
  ReactServerProvider,
2016
2044
  ReactPageProvider,
@@ -2025,5 +2053,5 @@ const AlephaReact = $module({
2025
2053
  });
2026
2054
 
2027
2055
  //#endregion
2028
- export { $page, AlephaContext, AlephaReact, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, ErrorViewer_default as ErrorViewer, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PageDescriptor, ReactBrowserProvider, ReactPageProvider, ReactRouter, ReactServerProvider, Redirection, RouterLayerContext, isPageRoute, reactBrowserOptions, reactServerOptions, ssrSchemaLoading, useAction, useActive, useAlepha, useClient, useEvents, useInject, useQueryParams, useRouter, useRouterState, useSchema, useStore };
2056
+ export { $page, AlephaContext, AlephaReact, ClientOnly_default as ClientOnly, ErrorBoundary_default as ErrorBoundary, ErrorViewer_default as ErrorViewer, Link_default as Link, NestedView_default as NestedView, NotFoundPage as NotFound, PagePrimitive, ReactBrowserProvider, ReactPageProvider, ReactRouter, ReactServerProvider, Redirection, RouterLayerContext, isPageRoute, reactBrowserOptions, reactServerOptions, ssrSchemaLoading, useAction, useActive, useAlepha, useClient, useEvents, useInject, useQueryParams, useRouter, useRouterState, useSchema, useStore };
2029
2057
  //# sourceMappingURL=index.js.map