@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.
- package/dist/auth/index.browser.js +5 -0
- package/dist/auth/index.browser.js.map +1 -1
- package/dist/auth/index.d.ts +139 -68
- package/dist/auth/index.js +5 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.browser.js +31 -10
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +113 -83
- package/dist/core/index.js +40 -13
- package/dist/core/index.js.map +1 -1
- package/dist/head/index.browser.js +21 -10
- package/dist/head/index.browser.js.map +1 -1
- package/dist/head/index.d.ts +41 -38
- package/dist/head/index.js +22 -10
- package/dist/head/index.js.map +1 -1
- package/package.json +6 -6
- package/src/auth/services/ReactAuth.ts +10 -0
- package/src/core/components/NestedView.tsx +5 -1
- package/src/core/components/NotFound.tsx +10 -6
- package/src/core/providers/ReactBrowserRouterProvider.ts +1 -0
- package/src/core/providers/ReactPageProvider.ts +3 -0
- package/src/core/providers/ReactServerProvider.ts +23 -12
- package/src/core/services/ReactRouter.ts +16 -0
- package/src/head/interfaces/Head.ts +1 -0
- package/src/head/primitives/$head.ts +4 -1
- package/src/head/providers/BrowserHeadProvider.ts +13 -0
- package/src/head/providers/HeadProvider.ts +11 -9
- package/src/head/providers/ServerHeadProvider.ts +6 -0
|
@@ -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":";;;;;;;;;;;
|
|
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"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
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:
|
|
11
|
-
id:
|
|
12
|
-
name:
|
|
13
|
-
email:
|
|
14
|
-
username:
|
|
15
|
-
picture:
|
|
16
|
-
sessionId:
|
|
17
|
-
organizations:
|
|
18
|
-
roles:
|
|
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:
|
|
24
|
-
error:
|
|
25
|
-
status:
|
|
26
|
-
message:
|
|
27
|
-
details:
|
|
28
|
-
requestId:
|
|
29
|
-
cause:
|
|
30
|
-
name:
|
|
31
|
-
message:
|
|
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:
|
|
271
|
-
level:
|
|
272
|
-
message:
|
|
273
|
-
service:
|
|
274
|
-
module:
|
|
275
|
-
context:
|
|
276
|
-
app:
|
|
277
|
-
data:
|
|
278
|
-
timestamp:
|
|
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:
|
|
294
|
-
protected readonly onStop:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
488
|
-
readonly 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:
|
|
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:
|
|
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:
|
|
892
|
-
SERVER_PORT:
|
|
893
|
-
SERVER_HOST:
|
|
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:
|
|
901
|
-
SERVER_PORT:
|
|
902
|
-
SERVER_HOST:
|
|
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:
|
|
987
|
-
APP_SECRET:
|
|
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
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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:
|
|
1148
|
-
provider:
|
|
1149
|
-
access_token:
|
|
1150
|
-
issued_at:
|
|
1151
|
-
expires_in:
|
|
1152
|
-
refresh_token:
|
|
1153
|
-
refresh_token_expires_in:
|
|
1154
|
-
refresh_expires_in:
|
|
1155
|
-
id_token:
|
|
1156
|
-
scope:
|
|
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
|
|
1226
|
-
protected readonly
|
|
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:
|
|
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:
|
|
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
|
package/dist/auth/index.js
CHANGED
|
@@ -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}`, {
|
package/dist/auth/index.js.map
CHANGED
|
@@ -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":";;;;;;;;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;;;;;;;;
|
|
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__ */
|
|
149
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
150
150
|
style: {
|
|
151
|
-
|
|
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: "
|
|
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("
|
|
163
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
162
164
|
style: {
|
|
163
|
-
fontSize: "
|
|
164
|
-
|
|
165
|
+
fontSize: "6rem",
|
|
166
|
+
fontWeight: 200,
|
|
167
|
+
lineHeight: 1
|
|
165
168
|
},
|
|
166
|
-
children: "404
|
|
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 (
|
|
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: {
|