@alepha/react 0.14.4 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +10 -0
  2. package/dist/auth/index.browser.js +603 -242
  3. package/dist/auth/index.browser.js.map +1 -1
  4. package/dist/auth/index.d.ts +2 -2
  5. package/dist/auth/index.d.ts.map +1 -1
  6. package/dist/auth/index.js +1317 -952
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/core/index.d.ts +17 -17
  9. package/dist/core/index.d.ts.map +1 -1
  10. package/dist/core/index.js +20 -20
  11. package/dist/core/index.js.map +1 -1
  12. package/dist/form/index.d.ts +9 -10
  13. package/dist/form/index.d.ts.map +1 -1
  14. package/dist/form/index.js +15 -15
  15. package/dist/form/index.js.map +1 -1
  16. package/dist/head/index.browser.js +20 -0
  17. package/dist/head/index.browser.js.map +1 -1
  18. package/dist/head/index.d.ts +62 -64
  19. package/dist/head/index.d.ts.map +1 -1
  20. package/dist/head/index.js +20 -0
  21. package/dist/head/index.js.map +1 -1
  22. package/dist/i18n/index.d.ts +9 -9
  23. package/dist/i18n/index.d.ts.map +1 -1
  24. package/dist/i18n/index.js.map +1 -1
  25. package/dist/router/index.browser.js +605 -244
  26. package/dist/router/index.browser.js.map +1 -1
  27. package/dist/router/index.d.ts +100 -111
  28. package/dist/router/index.d.ts.map +1 -1
  29. package/dist/router/index.js +1317 -952
  30. package/dist/router/index.js.map +1 -1
  31. package/dist/websocket/index.d.ts +0 -1
  32. package/dist/websocket/index.d.ts.map +1 -1
  33. package/package.json +6 -6
  34. package/src/auth/__tests__/$auth.spec.ts +164 -150
  35. package/src/auth/index.ts +9 -3
  36. package/src/auth/services/ReactAuth.ts +15 -5
  37. package/src/core/hooks/useAction.ts +1 -2
  38. package/src/core/index.ts +4 -4
  39. package/src/form/errors/FormValidationError.ts +4 -6
  40. package/src/form/hooks/useFormState.ts +1 -1
  41. package/src/form/index.ts +1 -1
  42. package/src/form/services/FormModel.ts +31 -25
  43. package/src/head/helpers/SeoExpander.ts +2 -1
  44. package/src/head/hooks/useHead.spec.tsx +2 -2
  45. package/src/head/index.browser.ts +2 -2
  46. package/src/head/index.ts +4 -4
  47. package/src/head/interfaces/Head.ts +15 -3
  48. package/src/head/primitives/$head.ts +2 -5
  49. package/src/head/providers/BrowserHeadProvider.ts +55 -0
  50. package/src/head/providers/HeadProvider.ts +4 -1
  51. package/src/i18n/__tests__/integration.spec.tsx +1 -1
  52. package/src/i18n/components/Localize.spec.tsx +2 -2
  53. package/src/i18n/hooks/useI18n.browser.spec.tsx +2 -2
  54. package/src/i18n/index.ts +1 -1
  55. package/src/i18n/primitives/$dictionary.ts +1 -1
  56. package/src/i18n/providers/I18nProvider.spec.ts +1 -1
  57. package/src/i18n/providers/I18nProvider.ts +1 -1
  58. package/src/router/__tests__/page-head-browser.browser.spec.ts +5 -1
  59. package/src/router/__tests__/page-head.spec.ts +11 -7
  60. package/src/router/__tests__/seo-head.spec.ts +7 -3
  61. package/src/router/atoms/ssrManifestAtom.ts +2 -11
  62. package/src/router/components/ErrorViewer.tsx +626 -167
  63. package/src/router/components/Link.tsx +4 -2
  64. package/src/router/components/NestedView.tsx +7 -9
  65. package/src/router/components/NotFound.tsx +2 -2
  66. package/src/router/hooks/useQueryParams.ts +1 -1
  67. package/src/router/hooks/useRouter.ts +1 -1
  68. package/src/router/hooks/useRouterState.ts +1 -1
  69. package/src/router/index.browser.ts +10 -11
  70. package/src/router/index.shared.ts +7 -7
  71. package/src/router/index.ts +10 -7
  72. package/src/router/primitives/$page.browser.spec.tsx +6 -1
  73. package/src/router/primitives/$page.spec.tsx +7 -1
  74. package/src/router/primitives/$page.ts +5 -9
  75. package/src/router/providers/ReactBrowserProvider.ts +17 -6
  76. package/src/router/providers/ReactBrowserRouterProvider.ts +1 -1
  77. package/src/router/providers/ReactPageProvider.ts +4 -3
  78. package/src/router/providers/ReactServerProvider.ts +32 -50
  79. package/src/router/providers/ReactServerTemplateProvider.ts +336 -155
  80. package/src/router/providers/SSRManifestProvider.ts +17 -60
  81. package/src/router/services/ReactPageService.ts +4 -1
  82. package/src/router/services/ReactRouter.ts +6 -5
@@ -2,7 +2,6 @@ import { ChannelPrimitive, TWSObject } from "alepha/websocket";
2
2
  import { Static } from "alepha";
3
3
 
4
4
  //#region ../../src/websocket/hooks/useRoom.d.ts
5
-
6
5
  /**
7
6
  * UseRoom options
8
7
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/websocket/hooks/useRoom.tsx"],"sourcesContent":[],"mappings":";;;;;;;AASA;AACkB,UADD,cACC,CAAA,gBAAA,SAAA,EAAA,gBACA,SADA,CAAA,CAAA;EACA;;;EAUP,MAAA,EAAA,MAAA;EAKiB;;;EAuCH,OAAA,EA5Cd,gBA4Cc,CA5CG,OA4CH,EA5CY,OA4CZ,CAAA;EAMR;;;EAIC,OAAA,EAAA,CAAA,OAAA,EAjDG,MAiDH,CAjDU,OAiDV,CAAA,EAAA,GAAA,IAAA;EAAoB;;;AA4DtC;EAAwC,GAAA,CAAA,EAAA,MAAA;EAA2B;;;;EAGlD,aAAA,CAAA,EAAA,OAAA;EAAd;;;;;;;;;;;;;;;;;;;;;oBAzEiB;;;;;UAMH,8BAA8B;;;;kBAI7B,OAAO,aAAa;;;;;;;;;;;;;;;;UAoB5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCG,0BAA2B,2BAA2B,oBACxD,eAAe,SAAS,8BAEhC,cAAc"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/websocket/hooks/useRoom.tsx"],"mappings":";;;;;;AASA;UAAiB,cAAA,iBACC,SAAA,kBACA,SAAA;EAFa;;;EAO7B,MAAA;EAKmC;;;EAAnC,OAAA,EAAS,gBAAA,CAAiB,OAAA,EAAS,OAAA;EA4CjB;;;EAvClB,OAAA,GAAU,OAAA,EAAS,MAAA,CAAO,OAAA;EAhBV;;;;EAsBhB,GAAA;EAXS;;;;EAiBT,aAAA;EAZ0B;;;;EAkB1B,iBAAA;EAMA;;;;EAAA,oBAAA;EAeW;;;EAVX,SAAA;EAgB4B;;;EAX5B,YAAA;EAegB;;;EAVhB,OAAA,IAAW,KAAA,EAAO,KAAA;AAAA;;;;UAMH,aAAA,iBAA8B,SAAA;EAItB;;;EAAvB,IAAA,GAAO,OAAA,EAAS,MAAA,CAAO,OAAA,MAAa,OAAA;EAUpC;;;EALA,WAAA;EAoBA;;;EAfA,YAAA;EAkDW;;;EA7CX,OAAA;EA6CiE;;;EAxCjE,KAAA,GAAQ,KAAA;EA2CO;;;EAtCf,SAAA;EAmCsB;;;EA9BtB,UAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8BW,OAAA,mBAA2B,SAAA,kBAA2B,SAAA,EACjE,OAAA,EAAS,cAAA,CAAe,OAAA,EAAS,OAAA,GACjC,IAAA,gBACC,aAAA,CAAc,OAAA"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@alepha/react",
3
3
  "description": "React components and hooks for building Alepha applications.",
4
4
  "author": "Nicolas Foures",
5
- "version": "0.14.4",
5
+ "version": "0.15.1",
6
6
  "type": "module",
7
7
  "engines": {
8
8
  "node": ">=22.0.0"
@@ -20,19 +20,19 @@
20
20
  "react-dom": "^19"
21
21
  },
22
22
  "devDependencies": {
23
- "@biomejs/biome": "^2.3.11",
23
+ "@biomejs/biome": "^2.3.12",
24
24
  "@testing-library/dom": "^10.4.1",
25
- "@testing-library/react": "^16.3.1",
25
+ "@testing-library/react": "^16.3.2",
26
26
  "@types/react": "^19",
27
27
  "@types/react-dom": "^19",
28
- "alepha": "0.14.4",
28
+ "alepha": "0.15.1",
29
29
  "jsdom": "^27.4.0",
30
30
  "react": "^19.2.3",
31
31
  "typescript": "^5.9.3",
32
- "vitest": "^4.0.16"
32
+ "vitest": "^4.0.18"
33
33
  },
34
34
  "peerDependencies": {
35
- "alepha": "0.14.4",
35
+ "alepha": "0.15.1",
36
36
  "react": "^19"
37
37
  },
38
38
  "scripts": {
@@ -1,188 +1,202 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { Alepha } from "alepha";
3
3
  import { DateTimeProvider } from "alepha/datetime";
4
- import { $realm } from "alepha/security";
5
- import { HttpClient, ServerProvider } from "alepha/server";
6
- import { $client } from "alepha/server/links";
7
- import { AlephaServerSecurity } from "alepha/server/security";
8
- import { describe, test } from "vitest";
4
+ import { $issuer, AlephaSecurity } from "alepha/security";
5
+ import { AlephaServer, HttpClient, ServerProvider } from "alepha/server";
9
6
  import {
10
7
  $auth,
11
8
  alephaServerAuthRoutes,
12
9
  type TokenResponse,
13
10
  tokenResponseSchema,
14
- tokensSchema
11
+ tokensSchema,
15
12
  } from "alepha/server/auth";
16
- import { ReactAuth, ReactAuthProvider } from "../index.ts";
13
+ import { $client } from "alepha/server/links";
14
+ import { describe, test } from "vitest";
15
+ import { ReactAuth, type ReactAuthProvider } from "../index.ts";
17
16
 
18
17
  describe("$auth", () => {
19
- const user = {
20
- id: randomUUID(),
21
- name: "John Doe",
22
- username: "john",
23
- password: "***",
24
- roles: ["admin"],
25
- };
26
-
27
- class App {
28
- realm = $realm({
29
- secret: "my-secret-key",
30
- roles: [
31
- {
32
- name: "admin",
33
- permissions: [{ name: "*" }],
34
- },
35
- ],
36
- });
37
-
38
- auth = $auth({
39
- realm: this.realm,
40
- credentials: {
41
- account: () => user,
18
+ const user = {
19
+ id: randomUUID(),
20
+ name: "John Doe",
21
+ username: "john",
22
+ password: "***",
23
+ roles: ["admin"],
24
+ };
25
+
26
+ class App {
27
+ issuer = $issuer({
28
+ secret: "my-secret-key",
29
+ roles: [
30
+ {
31
+ name: "admin",
32
+ permissions: [{ name: "*" }],
42
33
  },
43
- });
44
-
45
- api = $client<ReactAuthProvider>();
46
- }
47
-
48
- const userinfo = (alepha: Alepha, token?: string) =>
49
- alepha
50
- .inject(HttpClient)
51
- .fetch(
52
- `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.userinfo}`,
53
- {
54
- method: "GET",
55
- headers: {
56
- authorization: `Bearer ${token}`,
57
- },
34
+ ],
35
+ });
36
+
37
+ auth = $auth({
38
+ issuer: this.issuer,
39
+ credentials: {
40
+ account: () => user,
41
+ },
42
+ });
43
+
44
+ api = $client<ReactAuthProvider>();
45
+ }
46
+
47
+ const userinfo = (alepha: Alepha, token?: string) =>
48
+ alepha
49
+ .inject(HttpClient)
50
+ .fetch(
51
+ `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.userinfo}`,
52
+ {
53
+ method: "GET",
54
+ headers: {
55
+ authorization: `Bearer ${token}`,
58
56
  },
59
- )
60
- .then((it) => it.data);
61
-
62
- const login = (alepha: Alepha) =>
63
- alepha
64
- .inject(HttpClient)
65
- .fetch(
66
- `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.token}?provider=auth`,
67
- {
68
- method: "POST",
69
- body: JSON.stringify({
70
- username: user.username,
71
- password: user.password,
72
- }),
73
- schema: {
74
- response: tokenResponseSchema,
75
- },
57
+ },
58
+ )
59
+ .then((it) => it.data);
60
+
61
+ const login = (alepha: Alepha) =>
62
+ alepha
63
+ .inject(HttpClient)
64
+ .fetch(
65
+ `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.token}?provider=auth`,
66
+ {
67
+ method: "POST",
68
+ body: JSON.stringify({
69
+ username: user.username,
70
+ password: user.password,
71
+ }),
72
+ schema: {
73
+ response: tokenResponseSchema,
76
74
  },
77
- );
78
-
79
- const refresh = (alepha: Alepha, tokens: TokenResponse) =>
80
- alepha
81
- .inject(HttpClient)
82
- .fetch(
83
- `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.refresh}?provider=auth`,
84
- {
85
- method: "POST",
86
- body: JSON.stringify({
87
- refresh_token: tokens.refresh_token!,
88
- access_token: tokens.access_token,
89
- }),
90
- schema: {
91
- response: tokensSchema,
92
- },
75
+ },
76
+ );
77
+
78
+ const refresh = (alepha: Alepha, tokens: TokenResponse) =>
79
+ alepha
80
+ .inject(HttpClient)
81
+ .fetch(
82
+ `${alepha.inject(ServerProvider).hostname}${alephaServerAuthRoutes.refresh}?provider=auth`,
83
+ {
84
+ method: "POST",
85
+ body: JSON.stringify({
86
+ refresh_token: tokens.refresh_token!,
87
+ access_token: tokens.access_token,
88
+ }),
89
+ schema: {
90
+ response: tokensSchema,
93
91
  },
94
- );
92
+ },
93
+ );
94
+
95
+ test("should login with credentials", async ({ expect }) => {
96
+ const alepha = Alepha.create()
97
+ .with(AlephaServer)
98
+ .with(AlephaSecurity)
99
+ .with(App);
100
+ const auth = alepha.inject(ReactAuth);
101
+ await alepha.start();
102
+
103
+ expect(auth.user).toBeUndefined();
104
+ await auth.login("auth", {
105
+ username: user.username,
106
+ password: user.password,
107
+ hostname: alepha.inject(ServerProvider).hostname,
108
+ });
109
+ expect(auth.user).toEqual({
110
+ id: user.id,
111
+ name: user.name,
112
+ roles: user.roles,
113
+ username: user.username,
114
+ });
115
+ });
95
116
 
96
- test("should login with credentials", async ({ expect }) => {
97
- const alepha = Alepha.create().with(App).with(AlephaServerSecurity);
98
- const auth = alepha.inject(ReactAuth);
99
- await alepha.start();
117
+ test("should get userinfo", async ({ expect }) => {
118
+ const alepha = Alepha.create()
119
+ .with(AlephaServer)
120
+ .with(AlephaSecurity)
121
+ .with(App);
122
+ await alepha.start();
100
123
 
101
- expect(auth.user).toBeUndefined();
102
- await auth.login("auth", {
103
- username: user.username,
104
- password: user.password,
105
- hostname: alepha.inject(ServerProvider).hostname,
106
- });
107
- expect(auth.user).toEqual({
124
+ const { data: tokens } = await login(alepha);
125
+
126
+ expect(await userinfo(alepha, tokens.access_token)).toEqual({
127
+ user: {
108
128
  id: user.id,
109
129
  name: user.name,
110
130
  roles: user.roles,
111
131
  username: user.username,
112
- });
113
- });
114
-
115
- test("should get userinfo", async ({ expect }) => {
116
- const alepha = Alepha.create().with(App).with(AlephaServerSecurity);
117
- await alepha.start();
118
-
119
- const { data: tokens } = await login(alepha);
120
-
121
- expect(await userinfo(alepha, tokens.access_token)).toEqual({
122
- user: {
123
- id: user.id,
124
- name: user.name,
125
- roles: user.roles,
126
- username: user.username,
127
- sessionId: expect.any(String),
128
- },
129
- api: {
130
- prefix: "/api",
131
- links: [],
132
- },
133
- });
132
+ sessionId: expect.any(String),
133
+ },
134
+ api: {
135
+ prefix: "/api",
136
+ links: [],
137
+ },
134
138
  });
139
+ });
135
140
 
136
- test("should reject expired token", async ({ expect }) => {
137
- const alepha = Alepha.create().with(App);
138
- await alepha.start();
141
+ test("should reject expired token", async ({ expect }) => {
142
+ const alepha = Alepha.create()
143
+ .with(AlephaServer)
144
+ .with(AlephaSecurity)
145
+ .with(App);
146
+ await alepha.start();
139
147
 
140
- const { data: tokens } = await login(alepha);
148
+ const { data: tokens } = await login(alepha);
141
149
 
142
- await alepha.inject(DateTimeProvider).travel(1, "hour");
150
+ await alepha.inject(DateTimeProvider).travel(1, "hour");
143
151
 
144
- expect(await userinfo(alepha, tokens.access_token)).toEqual({
145
- api: {
146
- prefix: "/api",
147
- links: [],
148
- },
149
- });
152
+ expect(await userinfo(alepha, tokens.access_token)).toEqual({
153
+ api: {
154
+ prefix: "/api",
155
+ links: [],
156
+ },
150
157
  });
158
+ });
151
159
 
152
- test("should refresh expired token", async ({ expect }) => {
153
- const alepha = Alepha.create().with(App);
154
- await alepha.start();
160
+ test("should refresh expired token", async ({ expect }) => {
161
+ const alepha = Alepha.create()
162
+ .with(AlephaServer)
163
+ .with(AlephaSecurity)
164
+ .with(App);
165
+ await alepha.start();
155
166
 
156
- const { data: tokens } = await login(alepha);
167
+ const { data: tokens } = await login(alepha);
157
168
 
158
- await alepha.inject(DateTimeProvider).travel(1, "hour");
169
+ await alepha.inject(DateTimeProvider).travel(1, "hour");
159
170
 
160
- const { data: tokens2 } = await refresh(alepha, tokens);
171
+ const { data: tokens2 } = await refresh(alepha, tokens);
161
172
 
162
- expect(await userinfo(alepha, tokens2.access_token)).toEqual({
163
- user: {
164
- id: user.id,
165
- name: user.name,
166
- roles: user.roles,
167
- username: user.username,
168
- },
169
- api: {
170
- prefix: "/api",
171
- links: [],
172
- },
173
- });
173
+ expect(await userinfo(alepha, tokens2.access_token)).toEqual({
174
+ user: {
175
+ id: user.id,
176
+ name: user.name,
177
+ roles: user.roles,
178
+ username: user.username,
179
+ },
180
+ api: {
181
+ prefix: "/api",
182
+ links: [],
183
+ },
174
184
  });
185
+ });
175
186
 
176
- test("should reject expired refresh token", async ({ expect }) => {
177
- const alepha = Alepha.create().with(App);
178
- await alepha.start();
187
+ test("should reject expired refresh token", async ({ expect }) => {
188
+ const alepha = Alepha.create()
189
+ .with(AlephaServer)
190
+ .with(AlephaSecurity)
191
+ .with(App);
192
+ await alepha.start();
179
193
 
180
- const { data: tokens } = await login(alepha);
194
+ const { data: tokens } = await login(alepha);
181
195
 
182
- await alepha.inject(DateTimeProvider).travel(40, "days");
196
+ await alepha.inject(DateTimeProvider).travel(40, "days");
183
197
 
184
- await expect(refresh(alepha, tokens)).rejects.toThrowError(
185
- "Failed to refresh access token using the refresh token (realm)",
186
- );
187
- });
198
+ await expect(refresh(alepha, tokens)).rejects.toThrowError(
199
+ "Failed to refresh access token using the refresh token (issuer)",
200
+ );
201
+ });
188
202
  });
package/src/auth/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { AlephaReact } from "@alepha/react";
2
2
  import { $module } from "alepha";
3
3
  import type { UserAccount } from "alepha/security";
4
- import { ReactAuthProvider } from "./providers/ReactAuthProvider.ts";
5
- import { ReactAuth } from "./services/ReactAuth.ts";
6
4
  import { $auth, AlephaServerAuth } from "alepha/server/auth";
7
5
  import { AlephaServerLinks } from "alepha/server/links";
6
+ import { ReactAuthProvider } from "./providers/ReactAuthProvider.ts";
7
+ import { ReactAuth } from "./services/ReactAuth.ts";
8
8
 
9
9
  // ---------------------------------------------------------------------------------------------------------------------
10
10
 
@@ -30,5 +30,11 @@ declare module "@alepha/react/router" {
30
30
  export const AlephaReactAuth = $module({
31
31
  name: "alepha.react.auth",
32
32
  primitives: [$auth],
33
- services: [AlephaReact, AlephaServerLinks, AlephaServerAuth, ReactAuthProvider, ReactAuth],
33
+ services: [
34
+ AlephaReact,
35
+ AlephaServerLinks,
36
+ AlephaServerAuth,
37
+ ReactAuthProvider,
38
+ ReactAuth,
39
+ ],
34
40
  });
@@ -3,7 +3,12 @@ import { $hook, $inject, Alepha } from "alepha";
3
3
  import { $logger } from "alepha/logger";
4
4
  import type { UserAccountToken } from "alepha/security";
5
5
  import { HttpClient } from "alepha/server";
6
- import { alephaServerAuthRoutes, tokenResponseSchema, type Tokens, userinfoResponseSchema } from "alepha/server/auth";
6
+ import {
7
+ alephaServerAuthRoutes,
8
+ type Tokens,
9
+ tokenResponseSchema,
10
+ userinfoResponseSchema,
11
+ } from "alepha/server/auth";
7
12
  import { LinkProvider } from "alepha/server/links";
8
13
 
9
14
  /**
@@ -46,9 +51,12 @@ export class ReactAuth {
46
51
  }
47
52
 
48
53
  public async ping() {
49
- const { data } = await this.httpClient.fetch(alephaServerAuthRoutes.userinfo, {
50
- schema: { response: userinfoResponseSchema },
51
- });
54
+ const { data } = await this.httpClient.fetch(
55
+ alephaServerAuthRoutes.userinfo,
56
+ {
57
+ schema: { response: userinfoResponseSchema },
58
+ },
59
+ );
52
60
 
53
61
  this.alepha.store.set("alepha.server.request.apiLinks", data.api);
54
62
  this.alepha.store.set("alepha.server.request.user", data.user);
@@ -75,7 +83,9 @@ export class ReactAuth {
75
83
  [extra: string]: any;
76
84
  },
77
85
  ): Promise<Tokens> {
78
- const realmParam = options.realm ? `&realm=${encodeURIComponent(options.realm)}` : "";
86
+ const realmParam = options.realm
87
+ ? `&realm=${encodeURIComponent(options.realm)}`
88
+ : "";
79
89
 
80
90
  if (options.username || options.password) {
81
91
  const { data } = await this.httpClient.fetch(
@@ -1,3 +1,4 @@
1
+ import type { Async } from "alepha";
1
2
  import {
2
3
  DateTimeProvider,
3
4
  type DurationLike,
@@ -13,7 +14,6 @@ import {
13
14
  } from "react";
14
15
  import { useAlepha } from "./useAlepha.ts";
15
16
  import { useInject } from "./useInject.ts";
16
- import type { Async } from "alepha";
17
17
 
18
18
  /**
19
19
  * Hook for handling async actions with automatic error handling and event emission.
@@ -207,7 +207,6 @@ export function useAction<Args extends any[], Result = void>(
207
207
  await options.onSuccess(result);
208
208
  }
209
209
 
210
-
211
210
  return result;
212
211
  } catch (err) {
213
212
  // Ignore abort errors
package/src/core/index.ts CHANGED
@@ -2,17 +2,17 @@ import { $module } from "alepha";
2
2
 
3
3
  // ---------------------------------------------------------------------------------------------------------------------
4
4
 
5
- export { default as ClientOnly } from "./components/ClientOnly.tsx";
6
5
  export type * from "./components/ClientOnly.tsx";
7
- export { default as ErrorBoundary } from "./components/ErrorBoundary.tsx";
6
+ export { default as ClientOnly } from "./components/ClientOnly.tsx";
8
7
  export type * from "./components/ErrorBoundary.tsx";
9
- export * from "./contexts/AlephaProvider.tsx";
8
+ export { default as ErrorBoundary } from "./components/ErrorBoundary.tsx";
10
9
  export * from "./contexts/AlephaContext.ts";
10
+ export * from "./contexts/AlephaProvider.tsx";
11
11
  export * from "./hooks/useAction.ts";
12
12
  export * from "./hooks/useAlepha.ts";
13
+ export * from "./hooks/useClient.ts";
13
14
  export * from "./hooks/useEvents.ts";
14
15
  export * from "./hooks/useInject.ts";
15
- export * from "./hooks/useClient.ts";
16
16
  export * from "./hooks/useStore.ts";
17
17
 
18
18
  // ---------------------------------------------------------------------------------------------------------------------
@@ -3,12 +3,10 @@ import { TypeBoxError } from "alepha";
3
3
  export class FormValidationError extends TypeBoxError {
4
4
  readonly name = "ValidationError";
5
5
 
6
- constructor(
7
- options: {
8
- message: string;
9
- path: string;
10
- }
11
- ) {
6
+ constructor(options: {
7
+ message: string;
8
+ path: string;
9
+ }) {
12
10
  super({
13
11
  message: options.message,
14
12
  instancePath: options.path,
@@ -1,7 +1,7 @@
1
1
  import { useAlepha } from "@alepha/react";
2
- import type { FormModel } from "../services/FormModel.ts";
3
2
  import { type TObject, TypeBoxError } from "alepha";
4
3
  import { useEffect, useState } from "react";
4
+ import type { FormModel } from "../services/FormModel.ts";
5
5
 
6
6
  export interface UseFormStateReturn {
7
7
  loading: boolean;
package/src/form/index.ts CHANGED
@@ -3,10 +3,10 @@ import { $module } from "alepha";
3
3
  // ---------------------------------------------------------------------------------------------------------------------
4
4
 
5
5
  export { default as FormState } from "./components/FormState.tsx";
6
+ export * from "./errors/FormValidationError.ts";
6
7
  export * from "./hooks/useForm.ts";
7
8
  export * from "./hooks/useFormState.ts";
8
9
  export * from "./services/FormModel.ts";
9
- export * from "./errors/FormValidationError.ts";
10
10
 
11
11
  // ---------------------------------------------------------------------------------------------------------------------
12
12
 
@@ -1,5 +1,12 @@
1
1
  import type { TArray } from "alepha";
2
- import { $inject, Alepha, type Static, t, type TObject, type TSchema, } from "alepha";
2
+ import {
3
+ $inject,
4
+ Alepha,
5
+ type Static,
6
+ type TObject,
7
+ type TSchema,
8
+ t,
9
+ } from "alepha";
3
10
  import { $logger } from "alepha/logger";
4
11
  import type { ChangeEvent, InputHTMLAttributes } from "react";
5
12
 
@@ -217,7 +224,6 @@ export class FormModel<T extends TObject> {
217
224
  }
218
225
 
219
226
  if (prop in schema.properties) {
220
-
221
227
  // // it's a nested object, create another proxy
222
228
  // if (t.schema.isObject(schema.properties[prop])) {
223
229
  // return this.createProxyFromSchema(
@@ -284,13 +290,17 @@ export class FormModel<T extends TObject> {
284
290
  options.onChange(key, typedValue, context.store);
285
291
  }
286
292
 
287
- this.alepha.events.emit("form:change", {
288
- id: this.id,
289
- path: path,
290
- value: typedValue,
291
- }, {
292
- catch: true
293
- });
293
+ this.alepha.events.emit(
294
+ "form:change",
295
+ {
296
+ id: this.id,
297
+ path: path,
298
+ value: typedValue,
299
+ },
300
+ {
301
+ catch: true,
302
+ },
303
+ );
294
304
 
295
305
  if (sync) {
296
306
  const inputElement = window.document.querySelector(
@@ -408,14 +418,10 @@ export class FormModel<T extends TObject> {
408
418
  set,
409
419
  form: this,
410
420
  required,
411
- items: this.createProxyFromSchema(
412
- options,
413
- field,
414
- {
415
- parent: key,
416
- store: context.store,
417
- },
418
- )
421
+ items: this.createProxyFromSchema(options, field, {
422
+ parent: key,
423
+ store: context.store,
424
+ }),
419
425
  } as ObjectInputField<any>;
420
426
  }
421
427
 
@@ -460,7 +466,8 @@ export class FormModel<T extends TObject> {
460
466
  // Handle string representations from Select components (Yes/No dropdown)
461
467
  if (input === "true") return true;
462
468
  if (input === "false") return false;
463
- if (input === "" || input === null || input === undefined) return undefined;
469
+ if (input === "" || input === null || input === undefined)
470
+ return undefined;
464
471
  // Handle actual boolean values
465
472
  return !!input;
466
473
  }
@@ -520,12 +527,11 @@ export interface FormEventLike {
520
527
  stopPropagation?: () => void;
521
528
  }
522
529
 
523
- export type InputField<T extends TSchema> =
524
- T extends TObject
525
- ? ObjectInputField<T>
526
- : T extends TArray<infer U>
527
- ? ArrayInputField<U>
528
- : BaseInputField;
530
+ export type InputField<T extends TSchema> = T extends TObject
531
+ ? ObjectInputField<T>
532
+ : T extends TArray<infer U>
533
+ ? ArrayInputField<U>
534
+ : BaseInputField;
529
535
 
530
536
  export interface BaseInputField {
531
537
  path: string;
@@ -542,7 +548,7 @@ export interface ObjectInputField<T extends TObject> extends BaseInputField {
542
548
  }
543
549
 
544
550
  export interface ArrayInputField<T extends TSchema> extends BaseInputField {
545
- items: Array<InputField<T>>
551
+ items: Array<InputField<T>>;
546
552
  }
547
553
 
548
554
  export type InputHTMLAttributesLike = Pick<
@@ -113,7 +113,8 @@ export class SeoExpander {
113
113
  meta.push({
114
114
  name: "twitter:card",
115
115
  content:
116
- head.twitter?.card ?? (twitterImage ? "summary_large_image" : "summary"),
116
+ head.twitter?.card ??
117
+ (twitterImage ? "summary_large_image" : "summary"),
117
118
  });
118
119
  }
119
120
  if (head.url) {