@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
@@ -13,7 +13,7 @@ var ReactAuthProvider = class {
13
13
  handler: async ({ request, state }) => {
14
14
  if (request?.user) {
15
15
  const { token, realm, ...user } = request.user;
16
- this.alepha.state.set("alepha.server.request.user", user);
16
+ this.alepha.store.set("alepha.server.request.user", user);
17
17
  state.user = user;
18
18
  }
19
19
  }
@@ -29,6 +29,7 @@ var ReactAuth = class {
29
29
  log = $logger();
30
30
  alepha = $inject(Alepha);
31
31
  httpClient = $inject(HttpClient);
32
+ linkProvider = $inject(LinkProvider);
32
33
  onBeginTransition = $hook({
33
34
  on: "react:transition:begin",
34
35
  handler: async (event) => {
@@ -47,14 +48,18 @@ var ReactAuth = class {
47
48
  * Alias for `alepha.state.get("user")`
48
49
  */
49
50
  get user() {
50
- return this.alepha.state.get("alepha.server.request.user");
51
+ return this.alepha.store.get("alepha.server.request.user");
51
52
  }
52
53
  async ping() {
53
54
  const { data } = await this.httpClient.fetch(alephaServerAuthRoutes.userinfo, { schema: { response: userinfoResponseSchema } });
54
- this.alepha.state.set("alepha.server.request.apiLinks", data.api);
55
- this.alepha.state.set("alepha.server.request.user", data.user);
55
+ this.alepha.store.set("alepha.server.request.apiLinks", data.api);
56
+ this.alepha.store.set("alepha.server.request.user", data.user);
56
57
  return data.user;
57
58
  }
59
+ can(action) {
60
+ if (!this.user) return false;
61
+ return this.linkProvider.can(action);
62
+ }
58
63
  async login(provider, options) {
59
64
  if (options.username || options.password) {
60
65
  const { data } = await this.httpClient.fetch(`${options.hostname || ""}${alephaServerAuthRoutes.token}?provider=${provider}`, {
@@ -66,8 +71,8 @@ var ReactAuth = class {
66
71
  }),
67
72
  schema: { response: tokenResponseSchema }
68
73
  });
69
- this.alepha.state.set("alepha.server.request.apiLinks", data.api);
70
- this.alepha.state.set("alepha.server.request.user", data.user);
74
+ this.alepha.store.set("alepha.server.request.apiLinks", data.api);
75
+ this.alepha.store.set("alepha.server.request.user", data.user);
71
76
  return data;
72
77
  }
73
78
  if (this.alepha.isBrowser()) {
@@ -116,7 +121,7 @@ const useAuth = () => {
116
121
  */
117
122
  const AlephaReactAuth = $module({
118
123
  name: "alepha.react.auth",
119
- descriptors: [$auth],
124
+ primitives: [$auth],
120
125
  services: [
121
126
  AlephaReact,
122
127
  AlephaServerLinks,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/auth/providers/ReactAuthProvider.ts","../../src/auth/services/ReactAuth.ts","../../src/auth/hooks/useAuth.ts","../../src/auth/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\n\nexport class ReactAuthProvider {\n protected readonly alepha = $inject(Alepha);\n\n public readonly onRender = $hook({\n on: \"react:server:render:begin\",\n handler: async ({ request, state }) => {\n if (request?.user) {\n const { token, realm, ...user } = request.user; // do not send token and realm to the client\n this.alepha.state.set(\"alepha.server.request.user\", user); // for hydration, browser, etc...\n state.user = user;\n }\n },\n });\n}\n","import { ReactBrowserProvider, Redirection } from \"@alepha/react\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport { alephaServerAuthRoutes, tokenResponseSchema, type Tokens, userinfoResponseSchema } from \"alepha/server/auth\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.state.get(\"alepha.server.request.user\");\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(alephaServerAuthRoutes.userinfo, {\n schema: { response: userinfoResponseSchema },\n });\n\n this.alepha.state.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.state.set(\"alepha.server.request.user\", data.user);\n\n return data.user;\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n ...options,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.state.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.state.set(\"alepha.server.request.user\", data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n window.location.href = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n }\n}\n","import { useAlepha, useStore } from \"@alepha/react\";\nimport { type HttpVirtualClient, LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(\"alepha.server.request.user\");\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n can: <Api extends object = any>(\n name: keyof HttpVirtualClient<Api>,\n ): boolean => {\n return alepha.inject(LinkProvider).can(name as string);\n },\n };\n};\n","import { AlephaReact } from \"@alepha/react\";\nimport { $module } from \"alepha\";\nimport type { UserAccount } from \"alepha/security\";\nimport { ReactAuthProvider } from \"./providers/ReactAuthProvider.ts\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\nimport { $auth, AlephaServerAuth } from \"alepha/server/auth\";\nimport { AlephaServerLinks } from \"alepha/server/links\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactAuthProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"@alepha/react\" {\n interface ReactRouterState {\n user?: UserAccount;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * The ReactAuthModule provides authentication services for React applications.\n *\n * @see {@link ReactAuthProvider}\n * @module alepha.react.auth\n */\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n descriptors: [$auth],\n services: [AlephaReact, AlephaServerLinks, AlephaServerAuth, ReactAuthProvider, ReactAuth],\n});\n"],"mappings":";;;;;;;;AAEA,IAAa,oBAAb,MAA+B;CAC7B,AAAmB,SAAS,QAAQ,OAAO;CAE3C,AAAgB,WAAW,MAAM;EAC/B,IAAI;EACJ,SAAS,OAAO,EAAE,SAAS,YAAY;AACrC,OAAI,SAAS,MAAM;IACjB,MAAM,EAAE,OAAO,OAAO,GAAG,SAAS,QAAQ;AAC1C,SAAK,OAAO,MAAM,IAAI,8BAA8B,KAAK;AACzD,UAAM,OAAO;;;EAGlB,CAAC;;;;;;;;ACJJ,IAAa,YAAb,MAAuB;CACrB,AAAmB,MAAM,SAAS;CAClC,AAAmB,SAAS,QAAQ,OAAO;CAC3C,AAAmB,aAAa,QAAQ,WAAW;CAEnD,AAAmB,oBAAoB,MAAM;EAC3C,IAAI;EACJ,SAAS,OAAO,UAAU;AACxB,OAAI,KAAK,OAAO,WAAW,CACzB,QAAO,eAAe,MAAM,OAAO,QAAQ,EACzC,WAAW,KAAK,MACjB,CAAC;;EAGP,CAAC;CAEF,AAAmB,iBAAiB,MAAM;EACxC,IAAI;EACJ,SAAS,OAAO,EAAE,cAAc;AAC9B,OAAI,KAAK,OAAO,WAAW,IAAI,KAAK,KAElC,SAAQ,gBAAgB;;EAG7B,CAAC;;;;;;CAOF,IAAW,OAAqC;AAC9C,SAAO,KAAK,OAAO,MAAM,IAAI,6BAA6B;;CAG5D,MAAa,OAAO;EAClB,MAAM,EAAE,SAAS,MAAM,KAAK,WAAW,MAAM,uBAAuB,UAAU,EAC5E,QAAQ,EAAE,UAAU,wBAAwB,EAC7C,CAAC;AAEF,OAAK,OAAO,MAAM,IAAI,kCAAkC,KAAK,IAAI;AACjE,OAAK,OAAO,MAAM,IAAI,8BAA8B,KAAK,KAAK;AAE9D,SAAO,KAAK;;CAGd,MAAa,MACX,UACA,SAOiB;AACjB,MAAI,QAAQ,YAAY,QAAQ,UAAU;GACxC,MAAM,EAAE,SAAS,MAAM,KAAK,WAAW,MACrC,GAAG,QAAQ,YAAY,KAAK,uBAAuB,MAAM,YAAY,YACrE;IACE,QAAQ;IACR,MAAM,KAAK,UAAU;KACnB,UAAU,QAAQ;KAClB,UAAU,QAAQ;KAClB,GAAG;KACJ,CAAC;IACF,QAAQ,EAAE,UAAU,qBAAqB;IAC1C,CACF;AAED,QAAK,OAAO,MAAM,IAAI,kCAAkC,KAAK,IAAI;AACjE,QAAK,OAAO,MAAM,IAAI,8BAA8B,KAAK,KAAK;AAE9D,UAAO;;AAGT,MAAI,KAAK,OAAO,WAAW,EAAE;GAC3B,MAAM,UAAU,KAAK,OAAO,OAAO,qBAAqB;GACxD,MAAM,WACJ,QAAQ,aACP,QAAQ,gBACL,OAAO,SAAS,SAAS,QAAQ,cAAc,KAC/C,OAAO,SAAS;GAEtB,MAAM,OAAO,GAAG,OAAO,SAAS,SAAS,uBAAuB,MAAM,YAAY,SAAS,gBAAgB,mBAAmB,SAAS;AAEvI,OAAI,QAAQ,cACV,OAAM,IAAI,YAAY,KAAK;QACtB;AACL,WAAO,SAAS,OAAO;AACvB,WAAO,EAAE;;;AAIb,QAAM,IAAI,YACR,GAAG,uBAAuB,MAAM,YAAY,SAAS,gBAAgB,QAAQ,YAAY,MAC1F;;CAGH,AAAO,SAAS;AACd,SAAO,SAAS,OAAO,GAAG,uBAAuB,OAAO,4BAA4B,mBAAmB,OAAO,SAAS,OAAO;;;;;;AC1GlI,MAAa,gBAAwC;CACnD,MAAM,SAAS,WAAW;CAC1B,MAAM,CAAC,QAAQ,SAAS,6BAA6B;AAErD,QAAO;EACL;EACA,cAAc;AACZ,UAAO,OAAO,UAAU,CAAC,QAAQ;;EAEnC,OAAO,OACL,UACA,UAKI,EAAE,KACH;AACH,SAAM,OAAO,OAAO,UAAU,CAAC,MAAM,UAAoB,QAAQ;;EAEnE,MACE,SACY;AACZ,UAAO,OAAO,OAAO,aAAa,CAAC,IAAI,KAAe;;EAEzD;;;;;;;;;;;ACAH,MAAa,kBAAkB,QAAQ;CACrC,MAAM;CACN,aAAa,CAAC,MAAM;CACpB,UAAU;EAAC;EAAa;EAAmB;EAAkB;EAAmB;EAAU;CAC3F,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/auth/providers/ReactAuthProvider.ts","../../src/auth/services/ReactAuth.ts","../../src/auth/hooks/useAuth.ts","../../src/auth/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\n\nexport class ReactAuthProvider {\n protected readonly alepha = $inject(Alepha);\n\n public readonly onRender = $hook({\n on: \"react:server:render:begin\",\n handler: async ({ request, state }) => {\n if (request?.user) {\n const { token, realm, ...user } = request.user; // do not send token and realm to the client\n this.alepha.store.set(\"alepha.server.request.user\", user); // for hydration, browser, etc...\n state.user = user;\n }\n },\n });\n}\n","import { ReactBrowserProvider, Redirection } from \"@alepha/react\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport { alephaServerAuthRoutes, tokenResponseSchema, type Tokens, userinfoResponseSchema } from \"alepha/server/auth\";\nimport { LinkProvider } from \"alepha/server/links\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n protected readonly linkProvider = $inject(LinkProvider);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.store.get(\"alepha.server.request.user\");\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(alephaServerAuthRoutes.userinfo, {\n schema: { response: userinfoResponseSchema },\n });\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(\"alepha.server.request.user\", data.user);\n\n return data.user;\n }\n\n public can(action: string): boolean {\n if (!this.user) {\n return false;\n }\n\n return this.linkProvider.can(action);\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n ...options,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(\"alepha.server.request.user\", data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n window.location.href = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n }\n}\n","import { useAlepha, useStore } from \"@alepha/react\";\nimport { type HttpVirtualClient, LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(\"alepha.server.request.user\");\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n can: <Api extends object = any>(\n name: keyof HttpVirtualClient<Api>,\n ): boolean => {\n return alepha.inject(LinkProvider).can(name as string);\n },\n };\n};\n","import { AlephaReact } from \"@alepha/react\";\nimport { $module } from \"alepha\";\nimport type { UserAccount } from \"alepha/security\";\nimport { ReactAuthProvider } from \"./providers/ReactAuthProvider.ts\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\nimport { $auth, AlephaServerAuth } from \"alepha/server/auth\";\nimport { AlephaServerLinks } from \"alepha/server/links\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactAuthProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"@alepha/react\" {\n interface ReactRouterState {\n user?: UserAccount;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * The ReactAuthModule provides authentication services for React applications.\n *\n * @see {@link ReactAuthProvider}\n * @module alepha.react.auth\n */\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n primitives: [$auth],\n services: [AlephaReact, AlephaServerLinks, AlephaServerAuth, ReactAuthProvider, ReactAuth],\n});\n"],"mappings":"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"}
@@ -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 } from "alepha/server";
4
4
  import { AlephaServerLinks, LinkProvider } from "alepha/server/links";
@@ -19,11 +19,11 @@ var ReactPageService = class {
19
19
  };
20
20
 
21
21
  //#endregion
22
- //#region src/core/descriptors/$page.ts
22
+ //#region src/core/primitives/$page.ts
23
23
  /**
24
- * Main descriptor for defining a React route in the application.
24
+ * Main primitive for defining a React route in the application.
25
25
  *
26
- * The $page descriptor is the core building block for creating type-safe, SSR-enabled React routes.
26
+ * The $page primitive is the core building block for creating type-safe, SSR-enabled React routes.
27
27
  * It provides a declarative way to define pages with powerful features:
28
28
  *
29
29
  * **Routing & Navigation**
@@ -109,9 +109,9 @@ var ReactPageService = class {
109
109
  * ```
110
110
  */
111
111
  const $page = (options) => {
112
- return createDescriptor(PageDescriptor, options);
112
+ return createPrimitive(PagePrimitive, options);
113
113
  };
114
- var PageDescriptor = class extends Descriptor {
114
+ var PagePrimitive = class extends Primitive {
115
115
  reactPageService = $inject(ReactPageService);
116
116
  onInit() {
117
117
  if (this.options.static) this.options.cache ??= { store: {
@@ -141,30 +141,40 @@ var PageDescriptor = class extends Descriptor {
141
141
  return this.options.path || "";
142
142
  }
143
143
  };
144
- $page[KIND] = PageDescriptor;
144
+ $page[KIND] = PagePrimitive;
145
145
 
146
146
  //#endregion
147
147
  //#region src/core/components/NotFound.tsx
148
148
  function NotFoundPage(props) {
149
- return /* @__PURE__ */ jsx("div", {
149
+ return /* @__PURE__ */ jsxs("div", {
150
150
  style: {
151
- height: "100vh",
151
+ width: "100%",
152
+ minHeight: "90vh",
153
+ boxSizing: "border-box",
152
154
  display: "flex",
153
155
  flexDirection: "column",
154
156
  justifyContent: "center",
155
157
  alignItems: "center",
156
158
  textAlign: "center",
157
- fontFamily: "sans-serif",
158
- padding: "1rem",
159
+ fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
160
+ padding: "2rem",
159
161
  ...props.style
160
162
  },
161
- children: /* @__PURE__ */ jsx("h1", {
163
+ children: [/* @__PURE__ */ jsx("div", {
162
164
  style: {
163
- fontSize: "1rem",
164
- marginBottom: "0.5rem"
165
+ fontSize: "6rem",
166
+ fontWeight: 200,
167
+ lineHeight: 1
165
168
  },
166
- children: "404 - This page does not exist"
167
- })
169
+ children: "404"
170
+ }), /* @__PURE__ */ jsx("div", {
171
+ style: {
172
+ fontSize: "0.875rem",
173
+ marginTop: "1rem",
174
+ opacity: .6
175
+ },
176
+ children: "Page not found"
177
+ })]
168
178
  });
169
179
  }
170
180
 
@@ -421,9 +431,9 @@ const useEvents = (opts, deps) => {
421
431
  function useStore(target, defaultValue) {
422
432
  const alepha = useAlepha();
423
433
  useMemo(() => {
424
- if (defaultValue != null && alepha.state.get(target) == null) alepha.state.set(target, defaultValue);
434
+ if (defaultValue != null && alepha.store.get(target) == null) alepha.store.set(target, defaultValue);
425
435
  }, [defaultValue]);
426
- const [state, setState] = useState(alepha.state.get(target));
436
+ const [state, setState] = useState(alepha.store.get(target));
427
437
  useEffect(() => {
428
438
  if (!alepha.isBrowser()) return;
429
439
  const key = target instanceof Atom ? target.key : target;
@@ -432,7 +442,7 @@ function useStore(target, defaultValue) {
432
442
  });
433
443
  }, []);
434
444
  return [state, (value) => {
435
- alepha.state.set(target, value);
445
+ alepha.store.set(target, value);
436
446
  }];
437
447
  }
438
448
 
@@ -508,7 +518,8 @@ const NestedView = (props) => {
508
518
  useEvents({
509
519
  "react:transition:begin": async ({ previous, state: state$1 }) => {
510
520
  const layer = previous.layers[index];
511
- if (`${state$1.url.pathname}/`.startsWith(`${layer?.path}/`)) return;
521
+ if (!layer) return;
522
+ if (`${state$1.url.pathname}/`.startsWith(`${layer.path}/`)) return;
512
523
  const animationExit = parseAnimation(layer.route?.animation, state$1, "exit");
513
524
  if (animationExit) {
514
525
  const duration = animationExit.duration || 200;
@@ -622,6 +633,7 @@ var ReactPageProvider = class {
622
633
  if (!path.includes(":") && !path.includes("*")) pages.push({
623
634
  ...page,
624
635
  name: params[Object.keys(params)[0]],
636
+ staticName: page.name,
625
637
  path,
626
638
  ...entry
627
639
  });
@@ -852,7 +864,7 @@ var ReactPageProvider = class {
852
864
  on: "configure",
853
865
  handler: () => {
854
866
  let hasNotFoundHandler = false;
855
- const pages = this.alepha.descriptors($page);
867
+ const pages = this.alepha.primitives($page);
856
868
  const hasParent = (it) => {
857
869
  if (it.options.parent) return true;
858
870
  for (const page of pages) if ((page.options.children ? Array.isArray(page.options.children) ? page.options.children : page.options.children() : []).includes(it)) return true;
@@ -950,13 +962,14 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
950
962
  };
951
963
  await this.alepha.events.emit("react:action:begin", { type: "transition" });
952
964
  await this.alepha.events.emit("react:transition:begin", {
953
- previous: this.alepha.state.get("alepha.react.router.state"),
965
+ previous: this.alepha.store.get("alepha.react.router.state"),
954
966
  state
955
967
  });
956
968
  try {
957
969
  const { route, params } = this.match(pathname);
958
970
  const query = {};
959
971
  if (search) for (const [key, value] of new URLSearchParams(search).entries()) query[key] = String(value);
972
+ state.name = route?.page.name;
960
973
  state.query = query;
961
974
  state.params = params ?? {};
962
975
  if (isPageRoute(route)) {
@@ -992,7 +1005,7 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
992
1005
  const layer = previous[i];
993
1006
  if (state.layers[i]?.name !== layer.name) this.pageApi.page(layer.name)?.onLeave?.();
994
1007
  }
995
- this.alepha.state.set("alepha.react.router.state", state);
1008
+ this.alepha.store.set("alepha.react.router.state", state);
996
1009
  await this.alepha.events.emit("react:action:end", { type: "transition" });
997
1010
  await this.alepha.events.emit("react:transition:end", { state });
998
1011
  }
@@ -1030,7 +1043,7 @@ var ReactBrowserProvider = class {
1030
1043
  }
1031
1044
  transitioning;
1032
1045
  get state() {
1033
- return this.alepha.state.get("alepha.react.router.state");
1046
+ return this.alepha.store.get("alepha.react.router.state");
1034
1047
  }
1035
1048
  /**
1036
1049
  * Accessor for Document DOM API.
@@ -1147,7 +1160,7 @@ var ReactBrowserProvider = class {
1147
1160
  const hydration = this.getHydrationState();
1148
1161
  const previous = hydration?.layers ?? [];
1149
1162
  if (hydration) {
1150
- for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.state.set(key, value);
1163
+ for (const [key, value] of Object.entries(hydration)) if (key !== "layers") this.alepha.store.set(key, value);
1151
1164
  }
1152
1165
  await this.render({ previous });
1153
1166
  const element = this.router.root(this.state);
@@ -1192,7 +1205,7 @@ var ReactRouter = class {
1192
1205
  alepha = $inject(Alepha);
1193
1206
  pageApi = $inject(ReactPageProvider);
1194
1207
  get state() {
1195
- return this.alepha.state.get("alepha.react.router.state");
1208
+ return this.alepha.store.get("alepha.react.router.state");
1196
1209
  }
1197
1210
  get pages() {
1198
1211
  return this.pageApi.getPages();
@@ -1209,6 +1222,15 @@ var ReactRouter = class {
1209
1222
  if (options.startWith && !isActive) isActive = current.startsWith(href);
1210
1223
  return isActive;
1211
1224
  }
1225
+ node(name, config = {}) {
1226
+ const page = this.pageApi.page(name);
1227
+ return {
1228
+ ...page,
1229
+ label: page.label ?? page.name,
1230
+ href: this.path(name, config),
1231
+ children: void 0
1232
+ };
1233
+ }
1212
1234
  path(name, config = {}) {
1213
1235
  return this.pageApi.pathname(name, {
1214
1236
  params: {
@@ -1686,7 +1708,7 @@ const decode = (alepha, schema, data) => {
1686
1708
  //#region src/core/index.browser.ts
1687
1709
  const AlephaReact = $module({
1688
1710
  name: "alepha.react",
1689
- descriptors: [$page],
1711
+ primitives: [$page],
1690
1712
  services: [
1691
1713
  ReactPageProvider,
1692
1714
  ReactBrowserRouterProvider,
@@ -1699,5 +1721,5 @@ const AlephaReact = $module({
1699
1721
  });
1700
1722
 
1701
1723
  //#endregion
1702
- 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, ReactBrowserRouterProvider, ReactPageProvider, ReactRouter, Redirection, RouterLayerContext, isPageRoute, reactBrowserOptions, ssrSchemaLoading, useAction, useActive, useAlepha, useClient, useEvents, useInject, useQueryParams, useRouter, useRouterState, useSchema, useStore };
1724
+ 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, ReactBrowserRouterProvider, ReactPageProvider, ReactRouter, Redirection, RouterLayerContext, isPageRoute, reactBrowserOptions, ssrSchemaLoading, useAction, useActive, useAlepha, useClient, useEvents, useInject, useQueryParams, useRouter, useRouterState, useSchema, useStore };
1703
1725
  //# sourceMappingURL=index.browser.js.map