@alepha/react 0.13.2 → 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.
@@ -13,6 +13,7 @@ var ReactAuth = class {
13
13
  log = $logger();
14
14
  alepha = $inject(Alepha);
15
15
  httpClient = $inject(HttpClient);
16
+ linkProvider = $inject(LinkProvider);
16
17
  onBeginTransition = $hook({
17
18
  on: "react:transition:begin",
18
19
  handler: async (event) => {
@@ -39,6 +40,10 @@ var ReactAuth = class {
39
40
  this.alepha.store.set("alepha.server.request.user", data.user);
40
41
  return data.user;
41
42
  }
43
+ can(action) {
44
+ if (!this.user) return false;
45
+ return this.linkProvider.can(action);
46
+ }
42
47
  async login(provider, options) {
43
48
  if (options.username || options.password) {
44
49
  const { data } = await this.httpClient.fetch(`${options.hostname || ""}${alephaServerAuthRoutes.token}?provider=${provider}`, {
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","names":[],"sources":["../../src/auth/services/ReactAuth.ts","../../src/auth/hooks/useAuth.ts","../../src/auth/index.browser.ts"],"sourcesContent":["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.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 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 { $module } from \"alepha\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n services: [ReactAuth],\n});\n"],"mappings":";;;;;;;;;;;AAUA,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;;;;;ACpBH,MAAa,kBAAkB,QAAQ;CACrC,MAAM;CACN,UAAU,CAAC,UAAU;CACtB,CAAC"}
1
+ {"version":3,"file":"index.browser.js","names":[],"sources":["../../src/auth/services/ReactAuth.ts","../../src/auth/hooks/useAuth.ts","../../src/auth/index.browser.ts"],"sourcesContent":["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 { $module } from \"alepha\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n services: [ReactAuth],\n});\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,YAAb,MAAuB;CACrB,AAAmB,MAAM,SAAS;CAClC,AAAmB,SAAS,QAAQ,OAAO;CAC3C,AAAmB,aAAa,QAAQ,WAAW;CACnD,AAAmB,eAAe,QAAQ,aAAa;CAEvD,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,AAAO,IAAI,QAAyB;AAClC,MAAI,CAAC,KAAK,KACR,QAAO;AAGT,SAAO,KAAK,aAAa,IAAI,OAAO;;CAGtC,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;;;;;;ACpHlI,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;;;;;ACpBH,MAAa,kBAAkB,QAAQ;CACrC,MAAM;CACN,UAAU,CAAC,UAAU;CACtB,CAAC"}
@@ -1,4 +1,4 @@
1
- import * as alepha20 from "alepha";
1
+ import * as alepha4 from "alepha";
2
2
  import { Alepha, AlephaError, Async, FileLike, InstantiableClass, LogLevel, LoggerInterface, Primitive, Static, StreamLike, TArray, TFile, TObject, TRecord, TSchema, TStream, TString, TVoid } from "alepha";
3
3
  import { IncomingMessage, Server, ServerResponse } from "node:http";
4
4
  import { Readable } from "node:stream";
@@ -7,28 +7,28 @@ import dayjsDuration from "dayjs/plugin/duration.js";
7
7
  import DayjsApi, { Dayjs, ManipulateType, PluginFunc } from "dayjs";
8
8
 
9
9
  //#region ../alepha/src/security/schemas/userAccountInfoSchema.d.ts
10
- declare const userAccountInfoSchema: alepha20.TObject<{
11
- id: alepha20.TString;
12
- name: alepha20.TOptional<alepha20.TString>;
13
- email: alepha20.TOptional<alepha20.TString>;
14
- username: alepha20.TOptional<alepha20.TString>;
15
- picture: alepha20.TOptional<alepha20.TString>;
16
- sessionId: alepha20.TOptional<alepha20.TString>;
17
- organizations: alepha20.TOptional<alepha20.TArray<alepha20.TString>>;
18
- roles: alepha20.TOptional<alepha20.TArray<alepha20.TString>>;
10
+ declare const userAccountInfoSchema: alepha4.TObject<{
11
+ id: alepha4.TString;
12
+ name: alepha4.TOptional<alepha4.TString>;
13
+ email: alepha4.TOptional<alepha4.TString>;
14
+ username: alepha4.TOptional<alepha4.TString>;
15
+ picture: alepha4.TOptional<alepha4.TString>;
16
+ sessionId: alepha4.TOptional<alepha4.TString>;
17
+ organizations: alepha4.TOptional<alepha4.TArray<alepha4.TString>>;
18
+ roles: alepha4.TOptional<alepha4.TArray<alepha4.TString>>;
19
19
  }>;
20
20
  type UserAccount = Static<typeof userAccountInfoSchema>;
21
21
  //#endregion
22
22
  //#region ../alepha/src/server/schemas/errorSchema.d.ts
23
- declare const errorSchema: alepha20.TObject<{
24
- error: alepha20.TString;
25
- status: alepha20.TInteger;
26
- message: alepha20.TString;
27
- details: alepha20.TOptional<alepha20.TString>;
28
- requestId: alepha20.TOptional<alepha20.TString>;
29
- cause: alepha20.TOptional<alepha20.TObject<{
30
- name: alepha20.TString;
31
- message: alepha20.TString;
23
+ declare const errorSchema: alepha4.TObject<{
24
+ error: alepha4.TString;
25
+ status: alepha4.TInteger;
26
+ message: alepha4.TString;
27
+ details: alepha4.TOptional<alepha4.TString>;
28
+ requestId: alepha4.TOptional<alepha4.TString>;
29
+ cause: alepha4.TOptional<alepha4.TObject<{
30
+ name: alepha4.TString;
31
+ message: alepha4.TString;
32
32
  }>>;
33
33
  }>;
34
34
  type ErrorSchema = Static<typeof errorSchema>;
@@ -267,15 +267,15 @@ interface WebRequestEvent {
267
267
  }
268
268
  //#endregion
269
269
  //#region ../alepha/src/logger/schemas/logEntrySchema.d.ts
270
- declare const logEntrySchema: alepha20.TObject<{
271
- level: alepha20.TUnsafe<"SILENT" | "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR">;
272
- message: alepha20.TString;
273
- service: alepha20.TString;
274
- module: alepha20.TString;
275
- context: alepha20.TOptional<alepha20.TString>;
276
- app: alepha20.TOptional<alepha20.TString>;
277
- data: alepha20.TOptional<alepha20.TAny>;
278
- timestamp: alepha20.TNumber;
270
+ declare const logEntrySchema: alepha4.TObject<{
271
+ level: alepha4.TUnsafe<"SILENT" | "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR">;
272
+ message: alepha4.TString;
273
+ service: alepha4.TString;
274
+ module: alepha4.TString;
275
+ context: alepha4.TOptional<alepha4.TString>;
276
+ app: alepha4.TOptional<alepha4.TString>;
277
+ data: alepha4.TOptional<alepha4.TAny>;
278
+ timestamp: alepha4.TNumber;
279
279
  }>;
280
280
  type LogEntry = Static<typeof logEntrySchema>;
281
281
  //#endregion
@@ -290,8 +290,8 @@ declare class DateTimeProvider {
290
290
  protected readonly timeouts: Timeout[];
291
291
  protected readonly intervals: Interval[];
292
292
  constructor();
293
- protected readonly onStart: alepha20.HookPrimitive<"start">;
294
- protected readonly onStop: alepha20.HookPrimitive<"stop">;
293
+ protected readonly onStart: alepha4.HookPrimitive<"start">;
294
+ protected readonly onStop: alepha4.HookPrimitive<"stop">;
295
295
  setLocale(locale: string): void;
296
296
  isDateTime(value: unknown): value is DateTime;
297
297
  /**
@@ -423,7 +423,7 @@ declare class Logger implements LoggerInterface {
423
423
  }
424
424
  //#endregion
425
425
  //#region ../alepha/src/logger/index.d.ts
426
- declare const envSchema$3: alepha20.TObject<{
426
+ declare const envSchema$3: alepha4.TObject<{
427
427
  /**
428
428
  * Default log level for the application.
429
429
  *
@@ -440,14 +440,14 @@ declare const envSchema$3: alepha20.TObject<{
440
440
  * LOG_LEVEL=my.module.name:debug,info # Set debug level for my.module.name and info for all other modules
441
441
  * LOG_LEVEL=alepha:trace, info # Set trace level for all alepha modules and info for all other modules
442
442
  */
443
- LOG_LEVEL: alepha20.TOptional<alepha20.TString>;
443
+ LOG_LEVEL: alepha4.TOptional<alepha4.TString>;
444
444
  /**
445
445
  * Built-in log formats.
446
446
  * - "json" - JSON format, useful for structured logging and log aggregation. {@link JsonFormatterProvider}
447
447
  * - "pretty" - Simple text format, human-readable, with colors. {@link SimpleFormatterProvider}
448
448
  * - "raw" - Raw format, no formatting, just the message. {@link RawFormatterProvider}
449
449
  */
450
- LOG_FORMAT: alepha20.TOptional<alepha20.TUnsafe<"json" | "pretty" | "raw">>;
450
+ LOG_FORMAT: alepha4.TOptional<alepha4.TUnsafe<"json" | "pretty" | "raw">>;
451
451
  }>;
452
452
  declare module "alepha" {
453
453
  interface Env extends Partial<Static<typeof envSchema$3>> {}
@@ -484,8 +484,8 @@ declare class ServerTimingProvider {
484
484
  prefix: string;
485
485
  disabled: boolean;
486
486
  };
487
- readonly onRequest: alepha20.HookPrimitive<"server:onRequest">;
488
- readonly onResponse: alepha20.HookPrimitive<"server:onResponse">;
487
+ readonly onRequest: alepha4.HookPrimitive<"server:onRequest">;
488
+ readonly onResponse: alepha4.HookPrimitive<"server:onResponse">;
489
489
  protected get handlerName(): string;
490
490
  beginTiming(name: string): void;
491
491
  endTiming(name: string): void;
@@ -549,11 +549,11 @@ declare class ServerProvider {
549
549
  /**
550
550
  * When a Node.js HTTP request is received from outside. (Vercel, AWS Lambda, etc.)
551
551
  */
552
- protected readonly onNodeRequest: alepha20.HookPrimitive<"node:request">;
552
+ protected readonly onNodeRequest: alepha4.HookPrimitive<"node:request">;
553
553
  /**
554
554
  * When a Web (Fetch API) request is received from outside. (Netlify, Cloudflare Workers, etc.)
555
555
  */
556
- protected readonly onWebRequest: alepha20.HookPrimitive<"web:request">;
556
+ protected readonly onWebRequest: alepha4.HookPrimitive<"web:request">;
557
557
  /**
558
558
  * Handle Node.js HTTP request event.
559
559
  *
@@ -888,18 +888,18 @@ type ServerActionHandler<TConfig extends RequestConfigSchema = RequestConfigSche
888
888
  interface ServerActionRequest<TConfig extends RequestConfigSchema> extends ServerRequest<TConfig> {}
889
889
  //#endregion
890
890
  //#region ../alepha/src/server/providers/BunHttpServerProvider.d.ts
891
- declare const envSchema$2: alepha20.TObject<{
892
- SERVER_PORT: alepha20.TInteger;
893
- SERVER_HOST: alepha20.TString;
891
+ declare const envSchema$2: alepha4.TObject<{
892
+ SERVER_PORT: alepha4.TInteger;
893
+ SERVER_HOST: alepha4.TString;
894
894
  }>;
895
895
  declare module "alepha" {
896
896
  interface Env extends Partial<Static<typeof envSchema$2>> {}
897
897
  }
898
898
  //#endregion
899
899
  //#region ../alepha/src/server/providers/NodeHttpServerProvider.d.ts
900
- declare const envSchema$1: alepha20.TObject<{
901
- SERVER_PORT: alepha20.TInteger;
902
- SERVER_HOST: alepha20.TString;
900
+ declare const envSchema$1: alepha4.TObject<{
901
+ SERVER_PORT: alepha4.TInteger;
902
+ SERVER_HOST: alepha4.TString;
903
903
  }>;
904
904
  declare module "alepha" {
905
905
  interface Env extends Partial<Static<typeof envSchema$1>> {}
@@ -983,8 +983,8 @@ interface UserAccountToken extends UserAccount {
983
983
  }
984
984
  //#endregion
985
985
  //#region ../alepha/src/security/providers/SecurityProvider.d.ts
986
- declare const envSchema: alepha20.TObject<{
987
- APP_SECRET: alepha20.TString;
986
+ declare const envSchema: alepha4.TObject<{
987
+ APP_SECRET: alepha4.TString;
988
988
  }>;
989
989
  declare module "alepha" {
990
990
  interface Env extends Partial<Static<typeof envSchema>> {}
@@ -1077,20 +1077,89 @@ declare module "alepha/server" {
1077
1077
  */
1078
1078
  //#endregion
1079
1079
  //#region ../alepha/src/server-links/schemas/apiLinksResponseSchema.d.ts
1080
- declare const apiLinksResponseSchema: alepha20.TObject<{
1081
- prefix: alepha20.TOptional<alepha20.TString>;
1082
- links: alepha20.TArray<alepha20.TObject<{
1083
- name: alepha20.TString;
1084
- group: alepha20.TOptional<alepha20.TString>;
1085
- path: alepha20.TString;
1086
- method: alepha20.TOptional<alepha20.TString>;
1087
- requestBodyType: alepha20.TOptional<alepha20.TString>;
1088
- service: alepha20.TOptional<alepha20.TString>;
1080
+ declare const apiLinkSchema: alepha4.TObject<{
1081
+ name: alepha4.TString;
1082
+ group: alepha4.TOptional<alepha4.TString>;
1083
+ path: alepha4.TString;
1084
+ method: alepha4.TOptional<alepha4.TString>;
1085
+ requestBodyType: alepha4.TOptional<alepha4.TString>;
1086
+ service: alepha4.TOptional<alepha4.TString>;
1087
+ }>;
1088
+ declare const apiLinksResponseSchema: alepha4.TObject<{
1089
+ prefix: alepha4.TOptional<alepha4.TString>;
1090
+ links: alepha4.TArray<alepha4.TObject<{
1091
+ name: alepha4.TString;
1092
+ group: alepha4.TOptional<alepha4.TString>;
1093
+ path: alepha4.TString;
1094
+ method: alepha4.TOptional<alepha4.TString>;
1095
+ requestBodyType: alepha4.TOptional<alepha4.TString>;
1096
+ service: alepha4.TOptional<alepha4.TString>;
1089
1097
  }>>;
1090
1098
  }>;
1091
1099
  type ApiLinksResponse = Static<typeof apiLinksResponseSchema>;
1100
+ type ApiLink = Static<typeof apiLinkSchema>;
1092
1101
  //#endregion
1093
1102
  //#region ../alepha/src/server-links/providers/LinkProvider.d.ts
1103
+ /**
1104
+ * Browser, SSR friendly, service to handle links.
1105
+ */
1106
+ declare class LinkProvider {
1107
+ static path: {
1108
+ apiLinks: string;
1109
+ apiSchema: string;
1110
+ };
1111
+ protected readonly log: Logger;
1112
+ protected readonly alepha: Alepha;
1113
+ protected readonly httpClient: HttpClient;
1114
+ protected serverLinks: Array<HttpClientLink>;
1115
+ /**
1116
+ * Get applicative links registered on the server.
1117
+ * This does not include lazy-loaded remote links.
1118
+ */
1119
+ getServerLinks(): HttpClientLink[];
1120
+ /**
1121
+ * Register a new link for the application.
1122
+ */
1123
+ registerLink(link: HttpClientLink): void;
1124
+ get links(): HttpClientLink[];
1125
+ /**
1126
+ * Force browser to refresh links from the server.
1127
+ */
1128
+ fetchLinks(): Promise<HttpClientLink[]>;
1129
+ /**
1130
+ * Create a virtual client that can be used to call actions.
1131
+ *
1132
+ * Use js Proxy under the hood.
1133
+ */
1134
+ client<T extends object>(scope?: ClientScope): HttpVirtualClient<T>;
1135
+ /**
1136
+ * Check if a link with the given name exists.
1137
+ * @param name
1138
+ */
1139
+ can(name: string): boolean;
1140
+ /**
1141
+ * Resolve a link by its name and call it.
1142
+ * - If link is local, it will call the local handler.
1143
+ * - If link is remote, it will make a fetch request to the remote server.
1144
+ */
1145
+ follow(name: string, config?: Partial<ServerRequestConfigEntry>, options?: ClientRequestOptions & ClientScope): Promise<any>;
1146
+ protected createVirtualAction<T extends RequestConfigSchema>(name: string, scope?: ClientScope): VirtualAction<T>;
1147
+ protected followRemote(link: HttpClientLink, config?: Partial<ServerRequestConfigEntry>, options?: ClientRequestOptions): Promise<FetchResponse>;
1148
+ protected getLinkByName(name: string, options?: ClientScope): Promise<HttpClientLink>;
1149
+ }
1150
+ interface HttpClientLink extends ApiLink {
1151
+ secured?: boolean | ServerRouteSecure;
1152
+ prefix?: string;
1153
+ host?: string;
1154
+ service?: string;
1155
+ schema?: RequestConfigSchema;
1156
+ handler?: (request: ServerRequest, options: ClientRequestOptions) => Async<ServerResponseBody>;
1157
+ }
1158
+ interface ClientScope {
1159
+ group?: string;
1160
+ service?: string;
1161
+ hostname?: string;
1162
+ }
1094
1163
  type HttpVirtualClient<T> = { [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema> ? K : never]: T[K] extends ActionPrimitive<infer Schema> ? VirtualAction<Schema> : never };
1095
1164
  interface VirtualAction<T extends RequestConfigSchema> extends Pick<ActionPrimitive<T>, "name" | "run" | "fetch"> {
1096
1165
  (config?: ClientRequestEntry<T>, opts?: ClientRequestOptions): Promise<ClientRequestResponse<T>>;
@@ -1144,16 +1213,16 @@ declare const useAuth: <T extends object = any>() => {
1144
1213
  };
1145
1214
  //#endregion
1146
1215
  //#region ../alepha/src/server-auth/schemas/tokensSchema.d.ts
1147
- declare const tokensSchema: alepha20.TObject<{
1148
- provider: alepha20.TString;
1149
- access_token: alepha20.TString;
1150
- issued_at: alepha20.TNumber;
1151
- expires_in: alepha20.TOptional<alepha20.TNumber>;
1152
- refresh_token: alepha20.TOptional<alepha20.TString>;
1153
- refresh_token_expires_in: alepha20.TOptional<alepha20.TNumber>;
1154
- refresh_expires_in: alepha20.TOptional<alepha20.TNumber>;
1155
- id_token: alepha20.TOptional<alepha20.TString>;
1156
- scope: alepha20.TOptional<alepha20.TString>;
1216
+ declare const tokensSchema: alepha4.TObject<{
1217
+ provider: alepha4.TString;
1218
+ access_token: alepha4.TString;
1219
+ issued_at: alepha4.TNumber;
1220
+ expires_in: alepha4.TOptional<alepha4.TNumber>;
1221
+ refresh_token: alepha4.TOptional<alepha4.TString>;
1222
+ refresh_token_expires_in: alepha4.TOptional<alepha4.TNumber>;
1223
+ refresh_expires_in: alepha4.TOptional<alepha4.TNumber>;
1224
+ id_token: alepha4.TOptional<alepha4.TString>;
1225
+ scope: alepha4.TOptional<alepha4.TString>;
1157
1226
  }>;
1158
1227
  type Tokens = Static<typeof tokensSchema>;
1159
1228
  //#endregion
@@ -1222,8 +1291,9 @@ declare class ReactAuth {
1222
1291
  protected readonly log: Logger;
1223
1292
  protected readonly alepha: Alepha;
1224
1293
  protected readonly httpClient: HttpClient;
1225
- protected readonly onBeginTransition: alepha20.HookPrimitive<"react:transition:begin">;
1226
- protected readonly onFetchRequest: alepha20.HookPrimitive<"client:onRequest">;
1294
+ protected readonly linkProvider: LinkProvider;
1295
+ protected readonly onBeginTransition: alepha4.HookPrimitive<"react:transition:begin">;
1296
+ protected readonly onFetchRequest: alepha4.HookPrimitive<"client:onRequest">;
1227
1297
  /**
1228
1298
  * Get the current authenticated user.
1229
1299
  *
@@ -1240,6 +1310,7 @@ declare class ReactAuth {
1240
1310
  roles?: string[] | undefined;
1241
1311
  id: string;
1242
1312
  } | undefined>;
1313
+ can(action: string): boolean;
1243
1314
  login(provider: string, options: {
1244
1315
  hostname?: string;
1245
1316
  username?: string;
@@ -1253,7 +1324,7 @@ declare class ReactAuth {
1253
1324
  //#region src/auth/providers/ReactAuthProvider.d.ts
1254
1325
  declare class ReactAuthProvider {
1255
1326
  protected readonly alepha: Alepha;
1256
- readonly onRender: alepha20.HookPrimitive<"react:server:render:begin">;
1327
+ readonly onRender: alepha4.HookPrimitive<"react:server:render:begin">;
1257
1328
  }
1258
1329
  //#endregion
1259
1330
  //#region src/auth/index.d.ts
@@ -1268,7 +1339,7 @@ declare module "@alepha/react" {
1268
1339
  * @see {@link ReactAuthProvider}
1269
1340
  * @module alepha.react.auth
1270
1341
  */
1271
- declare const AlephaReactAuth: alepha20.Service<alepha20.Module>;
1342
+ declare const AlephaReactAuth: alepha4.Service<alepha4.Module>;
1272
1343
  //#endregion
1273
1344
  export { AlephaReactAuth, ReactAuth, ReactAuthProvider, useAuth };
1274
1345
  //# sourceMappingURL=index.d.ts.map
@@ -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) => {
@@ -55,6 +56,10 @@ var ReactAuth = class {
55
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}`, {
@@ -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.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\";\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.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 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
+ {"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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"}
@@ -146,25 +146,35 @@ $page[KIND] = PagePrimitive;
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
 
@@ -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;
@@ -958,6 +969,7 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
958
969
  const { route, params } = this.match(pathname);
959
970
  const query = {};
960
971
  if (search) for (const [key, value] of new URLSearchParams(search).entries()) query[key] = String(value);
972
+ state.name = route?.page.name;
961
973
  state.query = query;
962
974
  state.params = params ?? {};
963
975
  if (isPageRoute(route)) {
@@ -1210,6 +1222,15 @@ var ReactRouter = class {
1210
1222
  if (options.startWith && !isActive) isActive = current.startsWith(href);
1211
1223
  return isActive;
1212
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
+ }
1213
1234
  path(name, config = {}) {
1214
1235
  return this.pageApi.pathname(name, {
1215
1236
  params: {