@absolutejs/auth 0.27.0-beta.11 → 0.27.0-beta.12

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.
@@ -0,0 +1,258 @@
1
+ export type AuthClientError = {
2
+ body: unknown;
3
+ message: string;
4
+ status: number;
5
+ };
6
+ export type AuthClientResult<T> = {
7
+ data: null;
8
+ error: AuthClientError;
9
+ } | {
10
+ data: T;
11
+ error: null;
12
+ };
13
+ export type AuthClientRoutes = {
14
+ emailVerify?: string;
15
+ emailVerifyRequest?: string;
16
+ login?: string;
17
+ magicLinkRequest?: string;
18
+ magicLinkVerify?: string;
19
+ mfaChallenge?: string;
20
+ mfaSetup?: string;
21
+ mfaVerifySetup?: string;
22
+ passkeyAuthenticateOptions?: string;
23
+ passkeyAuthenticateVerify?: string;
24
+ passkeyList?: string;
25
+ passkeyRegisterOptions?: string;
26
+ passkeyRegisterVerify?: string;
27
+ passkeyRemove?: string;
28
+ passwordReset?: string;
29
+ passwordResetRequest?: string;
30
+ register?: string;
31
+ sessions?: string;
32
+ signout?: string;
33
+ };
34
+ export type AuthClientConfig = {
35
+ baseUrl?: string;
36
+ credentials?: RequestCredentials;
37
+ fetch?: typeof fetch;
38
+ routes?: AuthClientRoutes;
39
+ };
40
+ export declare const createAuthClient: ({ baseUrl, credentials, fetch: fetchImpl, routes }?: AuthClientConfig) => {
41
+ emailVerification: {
42
+ request: (body: {
43
+ email: string;
44
+ }) => Promise<{
45
+ data: null;
46
+ error: AuthClientError;
47
+ } | {
48
+ data: {
49
+ ok: true;
50
+ };
51
+ error: null;
52
+ }>;
53
+ verify: (body: {
54
+ token: string;
55
+ }) => Promise<{
56
+ data: null;
57
+ error: AuthClientError;
58
+ } | {
59
+ data: {
60
+ ok: true;
61
+ };
62
+ error: null;
63
+ }>;
64
+ };
65
+ mfa: {
66
+ challenge: (body: {
67
+ code: string;
68
+ }) => Promise<{
69
+ data: null;
70
+ error: AuthClientError;
71
+ } | {
72
+ data: {
73
+ status: "authenticated";
74
+ };
75
+ error: null;
76
+ }>;
77
+ setup: () => Promise<{
78
+ data: null;
79
+ error: AuthClientError;
80
+ } | {
81
+ data: {
82
+ secret: string;
83
+ uri: string;
84
+ };
85
+ error: null;
86
+ }>;
87
+ verifySetup: (body: {
88
+ code: string;
89
+ }) => Promise<{
90
+ data: null;
91
+ error: AuthClientError;
92
+ } | {
93
+ data: {
94
+ backupCodes: string[];
95
+ };
96
+ error: null;
97
+ }>;
98
+ };
99
+ passkeys: {
100
+ authenticateOptions: () => Promise<{
101
+ data: null;
102
+ error: AuthClientError;
103
+ } | {
104
+ data: unknown;
105
+ error: null;
106
+ }>;
107
+ authenticateVerify: (response: unknown) => Promise<{
108
+ data: null;
109
+ error: AuthClientError;
110
+ } | {
111
+ data: {
112
+ status: "authenticated";
113
+ };
114
+ error: null;
115
+ }>;
116
+ list: () => Promise<{
117
+ data: null;
118
+ error: AuthClientError;
119
+ } | {
120
+ data: unknown[];
121
+ error: null;
122
+ }>;
123
+ registerOptions: () => Promise<{
124
+ data: null;
125
+ error: AuthClientError;
126
+ } | {
127
+ data: unknown;
128
+ error: null;
129
+ }>;
130
+ registerVerify: (response: unknown) => Promise<{
131
+ data: null;
132
+ error: AuthClientError;
133
+ } | {
134
+ data: {
135
+ ok: true;
136
+ };
137
+ error: null;
138
+ }>;
139
+ remove: (credentialId: string) => Promise<{
140
+ data: null;
141
+ error: AuthClientError;
142
+ } | {
143
+ data: {
144
+ ok: true;
145
+ };
146
+ error: null;
147
+ }>;
148
+ };
149
+ passwordless: {
150
+ requestMagicLink: (body: {
151
+ email: string;
152
+ }) => Promise<{
153
+ data: null;
154
+ error: AuthClientError;
155
+ } | {
156
+ data: {
157
+ ok: true;
158
+ };
159
+ error: null;
160
+ }>;
161
+ verifyMagicLink: (body: {
162
+ token: string;
163
+ }) => Promise<{
164
+ data: null;
165
+ error: AuthClientError;
166
+ } | {
167
+ data: {
168
+ status: "authenticated";
169
+ };
170
+ error: null;
171
+ }>;
172
+ };
173
+ passwordReset: {
174
+ confirm: (body: {
175
+ password: string;
176
+ token: string;
177
+ }) => Promise<{
178
+ data: null;
179
+ error: AuthClientError;
180
+ } | {
181
+ data: {
182
+ ok: true;
183
+ };
184
+ error: null;
185
+ }>;
186
+ request: (body: {
187
+ email: string;
188
+ }) => Promise<{
189
+ data: null;
190
+ error: AuthClientError;
191
+ } | {
192
+ data: {
193
+ ok: true;
194
+ };
195
+ error: null;
196
+ }>;
197
+ };
198
+ sessions: {
199
+ list: () => Promise<{
200
+ data: null;
201
+ error: AuthClientError;
202
+ } | {
203
+ data: unknown[];
204
+ error: null;
205
+ }>;
206
+ revoke: (sessionId: string) => Promise<{
207
+ data: null;
208
+ error: AuthClientError;
209
+ } | {
210
+ data: {
211
+ ok: true;
212
+ };
213
+ error: null;
214
+ }>;
215
+ };
216
+ signIn: {
217
+ email: (body: {
218
+ email: string;
219
+ password: string;
220
+ }) => Promise<{
221
+ data: null;
222
+ error: AuthClientError;
223
+ } | {
224
+ data: {
225
+ passwordCompromised?: boolean;
226
+ status: "authenticated" | "mfa_required";
227
+ };
228
+ error: null;
229
+ }>;
230
+ };
231
+ signUp: {
232
+ email: (body: {
233
+ email: string;
234
+ password: string;
235
+ [extra: string]: unknown;
236
+ }) => Promise<{
237
+ data: null;
238
+ error: AuthClientError;
239
+ } | {
240
+ data: {
241
+ status: "authenticated";
242
+ } | {
243
+ status: "verification_required";
244
+ };
245
+ error: null;
246
+ }>;
247
+ };
248
+ signOut: () => Promise<{
249
+ data: null;
250
+ error: AuthClientError;
251
+ } | {
252
+ data: {
253
+ ok: true;
254
+ } | null;
255
+ error: null;
256
+ }>;
257
+ };
258
+ export type AuthClient = ReturnType<typeof createAuthClient>;
@@ -0,0 +1 @@
1
+ export * from './createAuthClient';
@@ -0,0 +1,127 @@
1
+ // @bun
2
+ // src/client/createAuthClient.ts
3
+ var DEFAULT_ROUTES = {
4
+ emailVerify: "/auth/verify-email",
5
+ emailVerifyRequest: "/auth/verify-email/request",
6
+ login: "/auth/login",
7
+ magicLinkRequest: "/auth/passwordless/magic-link",
8
+ magicLinkVerify: "/auth/passwordless/magic-link/verify",
9
+ mfaChallenge: "/auth/mfa/totp/challenge",
10
+ mfaSetup: "/auth/mfa/totp/setup",
11
+ mfaVerifySetup: "/auth/mfa/totp/verify",
12
+ passkeyAuthenticateOptions: "/auth/webauthn/authenticate/options",
13
+ passkeyAuthenticateVerify: "/auth/webauthn/authenticate/verify",
14
+ passkeyList: "/auth/webauthn/credentials",
15
+ passkeyRegisterOptions: "/auth/webauthn/register/options",
16
+ passkeyRegisterVerify: "/auth/webauthn/register/verify",
17
+ passkeyRemove: "/auth/webauthn/credentials",
18
+ passwordReset: "/auth/reset-password",
19
+ passwordResetRequest: "/auth/reset-password/request",
20
+ register: "/auth/register",
21
+ sessions: "/auth/sessions",
22
+ signout: "/auth/signout"
23
+ };
24
+ var succeed = (data) => ({
25
+ data,
26
+ error: null
27
+ });
28
+ var fail = (error) => ({
29
+ data: null,
30
+ error
31
+ });
32
+ var errorFor = (response, body) => ({
33
+ body,
34
+ message: typeof body === "string" ? body : readMessage(body) ?? response.statusText,
35
+ status: response.status
36
+ });
37
+ var createAuthClient = ({
38
+ baseUrl = "",
39
+ credentials = "same-origin",
40
+ fetch: fetchImpl = fetch,
41
+ routes
42
+ } = {}) => {
43
+ const resolvedRoutes = {
44
+ ...DEFAULT_ROUTES,
45
+ ...routes
46
+ };
47
+ const request = async (path, init) => {
48
+ try {
49
+ const response = await fetchImpl(`${baseUrl}${path}`, {
50
+ credentials,
51
+ ...init
52
+ });
53
+ const text = await response.text();
54
+ const body = text === "" ? null : safeJson(text);
55
+ if (!response.ok)
56
+ return fail(errorFor(response, body));
57
+ return succeed(body);
58
+ } catch (caught) {
59
+ const message = caught instanceof Error ? caught.message : "network";
60
+ return fail({ body: null, message, status: 0 });
61
+ }
62
+ };
63
+ const post = (path, body, method = "POST") => request(path, {
64
+ body: body === undefined ? undefined : JSON.stringify(body),
65
+ headers: body === undefined ? undefined : { "content-type": "application/json" },
66
+ method
67
+ });
68
+ const get = (path) => request(path, { method: "GET" });
69
+ const del = (path) => request(path, { method: "DELETE" });
70
+ return {
71
+ emailVerification: {
72
+ request: (body) => post(resolvedRoutes.emailVerifyRequest, body),
73
+ verify: (body) => post(resolvedRoutes.emailVerify, body)
74
+ },
75
+ mfa: {
76
+ challenge: (body) => post(resolvedRoutes.mfaChallenge, body),
77
+ setup: () => post(resolvedRoutes.mfaSetup),
78
+ verifySetup: (body) => post(resolvedRoutes.mfaVerifySetup, body)
79
+ },
80
+ passkeys: {
81
+ authenticateOptions: () => post(resolvedRoutes.passkeyAuthenticateOptions),
82
+ authenticateVerify: (response) => post(resolvedRoutes.passkeyAuthenticateVerify, response),
83
+ list: () => get(resolvedRoutes.passkeyList),
84
+ registerOptions: () => post(resolvedRoutes.passkeyRegisterOptions),
85
+ registerVerify: (response) => post(resolvedRoutes.passkeyRegisterVerify, response),
86
+ remove: (credentialId) => del(`${resolvedRoutes.passkeyRemove}/${encodeURIComponent(credentialId)}`)
87
+ },
88
+ passwordless: {
89
+ requestMagicLink: (body) => post(resolvedRoutes.magicLinkRequest, body),
90
+ verifyMagicLink: (body) => post(resolvedRoutes.magicLinkVerify, body)
91
+ },
92
+ passwordReset: {
93
+ confirm: (body) => post(resolvedRoutes.passwordReset, body),
94
+ request: (body) => post(resolvedRoutes.passwordResetRequest, body)
95
+ },
96
+ sessions: {
97
+ list: () => get(resolvedRoutes.sessions),
98
+ revoke: (sessionId) => del(`${resolvedRoutes.sessions}/${encodeURIComponent(sessionId)}`)
99
+ },
100
+ signIn: {
101
+ email: (body) => post(resolvedRoutes.login, body)
102
+ },
103
+ signUp: {
104
+ email: (body) => post(resolvedRoutes.register, body)
105
+ },
106
+ signOut: () => post(resolvedRoutes.signout)
107
+ };
108
+ };
109
+ var safeJson = (text) => {
110
+ try {
111
+ return JSON.parse(text);
112
+ } catch {
113
+ return text;
114
+ }
115
+ };
116
+ var readMessage = (body) => {
117
+ if (typeof body !== "object" || body === null)
118
+ return;
119
+ const message = Reflect.get(body, "message");
120
+ return typeof message === "string" ? message : undefined;
121
+ };
122
+ export {
123
+ createAuthClient
124
+ };
125
+
126
+ //# debugId=AA9996133C04E1BA64756E2164756E21
127
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client/createAuthClient.ts"],
4
+ "sourcesContent": [
5
+ "// Framework-agnostic client SDK over the auth endpoints. Thin fetch wrappers with\n// configurable routes, a uniform `{ data, error }` return, and same-origin cookies on by\n// default — the primitive the React hooks (`./react`) and future Vue/Solid composables wrap.\n// HTMX is the special case (declarative server fragments via `./htmx`); for every other UI\n// framework the natural primitive is this client + your framework's reactivity.\n\nexport type AuthClientError = {\n\tbody: unknown;\n\tmessage: string;\n\tstatus: number;\n};\n\nexport type AuthClientResult<T> =\n\t| { data: null; error: AuthClientError }\n\t| { data: T; error: null };\n\n// Each entry is the URL the consumer's auth() mounted that flow at. Defaults match the\n// package defaults; override to match your own custom routes.\nexport type AuthClientRoutes = {\n\temailVerify?: string;\n\temailVerifyRequest?: string;\n\tlogin?: string;\n\tmagicLinkRequest?: string;\n\tmagicLinkVerify?: string;\n\tmfaChallenge?: string;\n\tmfaSetup?: string;\n\tmfaVerifySetup?: string;\n\tpasskeyAuthenticateOptions?: string;\n\tpasskeyAuthenticateVerify?: string;\n\tpasskeyList?: string;\n\tpasskeyRegisterOptions?: string;\n\tpasskeyRegisterVerify?: string;\n\tpasskeyRemove?: string;\n\tpasswordReset?: string;\n\tpasswordResetRequest?: string;\n\tregister?: string;\n\tsessions?: string;\n\tsignout?: string;\n};\n\nconst DEFAULT_ROUTES: Required<AuthClientRoutes> = {\n\temailVerify: '/auth/verify-email',\n\temailVerifyRequest: '/auth/verify-email/request',\n\tlogin: '/auth/login',\n\tmagicLinkRequest: '/auth/passwordless/magic-link',\n\tmagicLinkVerify: '/auth/passwordless/magic-link/verify',\n\tmfaChallenge: '/auth/mfa/totp/challenge',\n\tmfaSetup: '/auth/mfa/totp/setup',\n\tmfaVerifySetup: '/auth/mfa/totp/verify',\n\tpasskeyAuthenticateOptions: '/auth/webauthn/authenticate/options',\n\tpasskeyAuthenticateVerify: '/auth/webauthn/authenticate/verify',\n\tpasskeyList: '/auth/webauthn/credentials',\n\tpasskeyRegisterOptions: '/auth/webauthn/register/options',\n\tpasskeyRegisterVerify: '/auth/webauthn/register/verify',\n\tpasskeyRemove: '/auth/webauthn/credentials',\n\tpasswordReset: '/auth/reset-password',\n\tpasswordResetRequest: '/auth/reset-password/request',\n\tregister: '/auth/register',\n\tsessions: '/auth/sessions',\n\tsignout: '/auth/signout'\n};\n\nexport type AuthClientConfig = {\n\tbaseUrl?: string;\n\tcredentials?: RequestCredentials;\n\tfetch?: typeof fetch;\n\troutes?: AuthClientRoutes;\n};\n\nconst succeed = <T>(data: T): AuthClientResult<T> => ({\n\tdata,\n\terror: null\n});\n\nconst fail = (error: AuthClientError): AuthClientResult<never> => ({\n\tdata: null,\n\terror\n});\n\nconst errorFor = (response: Response, body: unknown): AuthClientError => ({\n\tbody,\n\tmessage:\n\t\ttypeof body === 'string'\n\t\t\t? body\n\t\t\t: (readMessage(body) ?? response.statusText),\n\tstatus: response.status\n});\n\nexport const createAuthClient = ({\n\tbaseUrl = '',\n\tcredentials = 'same-origin',\n\tfetch: fetchImpl = fetch,\n\troutes\n}: AuthClientConfig = {}) => {\n\tconst resolvedRoutes: Required<AuthClientRoutes> = {\n\t\t...DEFAULT_ROUTES,\n\t\t...routes\n\t};\n\n\tconst request = async <T>(path: string, init: RequestInit) => {\n\t\ttry {\n\t\t\tconst response = await fetchImpl(`${baseUrl}${path}`, {\n\t\t\t\tcredentials,\n\t\t\t\t...init\n\t\t\t});\n\t\t\tconst text = await response.text();\n\t\t\tconst body: unknown = text === '' ? null : safeJson(text);\n\t\t\tif (!response.ok) return fail(errorFor(response, body));\n\n\t\t\t// Trust the caller's expectation at the deserialization boundary.\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- HTTP response is unknown until parsed; the call site declares the expected T\n\t\t\treturn succeed(body as T);\n\t\t} catch (caught) {\n\t\t\tconst message = caught instanceof Error ? caught.message : 'network';\n\n\t\t\treturn fail({ body: null, message, status: 0 });\n\t\t}\n\t};\n\n\tconst post = <T>(path: string, body?: unknown, method = 'POST') =>\n\t\trequest<T>(path, {\n\t\t\tbody: body === undefined ? undefined : JSON.stringify(body),\n\t\t\theaders:\n\t\t\t\tbody === undefined ? undefined : { 'content-type': 'application/json' },\n\t\t\tmethod\n\t\t});\n\n\tconst get = <T>(path: string) => request<T>(path, { method: 'GET' });\n\n\tconst del = <T>(path: string) => request<T>(path, { method: 'DELETE' });\n\n\treturn {\n\t\temailVerification: {\n\t\t\trequest: (body: { email: string }) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.emailVerifyRequest, body),\n\t\t\tverify: (body: { token: string }) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.emailVerify, body)\n\t\t},\n\t\tmfa: {\n\t\t\tchallenge: (body: { code: string }) =>\n\t\t\t\tpost<{ status: 'authenticated' }>(resolvedRoutes.mfaChallenge, body),\n\t\t\tsetup: () =>\n\t\t\t\tpost<{ secret: string; uri: string }>(resolvedRoutes.mfaSetup),\n\t\t\tverifySetup: (body: { code: string }) =>\n\t\t\t\tpost<{ backupCodes: string[] }>(\n\t\t\t\t\tresolvedRoutes.mfaVerifySetup,\n\t\t\t\t\tbody\n\t\t\t\t)\n\t\t},\n\t\tpasskeys: {\n\t\t\tauthenticateOptions: () =>\n\t\t\t\tpost<unknown>(resolvedRoutes.passkeyAuthenticateOptions),\n\t\t\tauthenticateVerify: (response: unknown) =>\n\t\t\t\tpost<{ status: 'authenticated' }>(\n\t\t\t\t\tresolvedRoutes.passkeyAuthenticateVerify,\n\t\t\t\t\tresponse\n\t\t\t\t),\n\t\t\tlist: () => get<unknown[]>(resolvedRoutes.passkeyList),\n\t\t\tregisterOptions: () =>\n\t\t\t\tpost<unknown>(resolvedRoutes.passkeyRegisterOptions),\n\t\t\tregisterVerify: (response: unknown) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.passkeyRegisterVerify, response),\n\t\t\tremove: (credentialId: string) =>\n\t\t\t\tdel<{ ok: true }>(\n\t\t\t\t\t`${resolvedRoutes.passkeyRemove}/${encodeURIComponent(credentialId)}`\n\t\t\t\t)\n\t\t},\n\t\tpasswordless: {\n\t\t\trequestMagicLink: (body: { email: string }) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.magicLinkRequest, body),\n\t\t\tverifyMagicLink: (body: { token: string }) =>\n\t\t\t\tpost<{ status: 'authenticated' }>(\n\t\t\t\t\tresolvedRoutes.magicLinkVerify,\n\t\t\t\t\tbody\n\t\t\t\t)\n\t\t},\n\t\tpasswordReset: {\n\t\t\tconfirm: (body: { password: string; token: string }) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.passwordReset, body),\n\t\t\trequest: (body: { email: string }) =>\n\t\t\t\tpost<{ ok: true }>(resolvedRoutes.passwordResetRequest, body)\n\t\t},\n\t\tsessions: {\n\t\t\tlist: () => get<unknown[]>(resolvedRoutes.sessions),\n\t\t\trevoke: (sessionId: string) =>\n\t\t\t\tdel<{ ok: true }>(\n\t\t\t\t\t`${resolvedRoutes.sessions}/${encodeURIComponent(sessionId)}`\n\t\t\t\t)\n\t\t},\n\t\tsignIn: {\n\t\t\temail: (body: { email: string; password: string }) =>\n\t\t\t\tpost<{\n\t\t\t\t\tpasswordCompromised?: boolean;\n\t\t\t\t\tstatus: 'authenticated' | 'mfa_required';\n\t\t\t\t}>(resolvedRoutes.login, body)\n\t\t},\n\t\tsignUp: {\n\t\t\temail: (body: {\n\t\t\t\temail: string;\n\t\t\t\tpassword: string;\n\t\t\t\t[extra: string]: unknown;\n\t\t\t}) =>\n\t\t\t\tpost<\n\t\t\t\t\t| { status: 'authenticated' }\n\t\t\t\t\t| { status: 'verification_required' }\n\t\t\t\t>(resolvedRoutes.register, body)\n\t\t},\n\t\tsignOut: () => post<{ ok: true } | null>(resolvedRoutes.signout)\n\t};\n};\n\nconst safeJson = (text: string) => {\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- deserialization boundary\n\t\treturn JSON.parse(text) as unknown;\n\t} catch {\n\t\treturn text;\n\t}\n};\n\nconst readMessage = (body: unknown) => {\n\tif (typeof body !== 'object' || body === null) return undefined;\n\tconst message: unknown = Reflect.get(body, 'message');\n\n\treturn typeof message === 'string' ? message : undefined;\n};\n\nexport type AuthClient = ReturnType<typeof createAuthClient>;\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "AA9996133C04E1BA64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,62 @@
1
+ import type { AuthClient, AuthClientError } from './createAuthClient';
2
+ type Mutator<Args, Data> = (args: Args) => Promise<{
3
+ data: Data | null;
4
+ error: AuthClientError | null;
5
+ }>;
6
+ type MutationState<Args, Data> = {
7
+ data: Data | null;
8
+ error: AuthClientError | null;
9
+ isPending: boolean;
10
+ mutate: Mutator<Args, Data>;
11
+ reset: () => void;
12
+ };
13
+ export declare const useMagicLink: (client: AuthClient) => MutationState<{
14
+ email: string;
15
+ }, {
16
+ ok: true;
17
+ }>;
18
+ export declare const useMfaChallenge: (client: AuthClient) => MutationState<{
19
+ code: string;
20
+ }, {
21
+ status: "authenticated";
22
+ }>;
23
+ export declare const usePasswordReset: (client: AuthClient) => MutationState<{
24
+ email: string;
25
+ }, {
26
+ ok: true;
27
+ }>;
28
+ export declare const useSessions: (client: AuthClient) => {
29
+ data: unknown[] | null;
30
+ error: AuthClientError | null;
31
+ isPending: boolean;
32
+ refetch: () => Promise<void>;
33
+ revoke: (sessionId: string) => Promise<{
34
+ data: null;
35
+ error: AuthClientError;
36
+ } | {
37
+ data: {
38
+ ok: true;
39
+ };
40
+ error: null;
41
+ }>;
42
+ };
43
+ export declare const useSignIn: (client: AuthClient) => MutationState<{
44
+ email: string;
45
+ password: string;
46
+ }, {
47
+ passwordCompromised?: boolean;
48
+ status: "authenticated" | "mfa_required";
49
+ }>;
50
+ export declare const useSignOut: (client: AuthClient) => MutationState<unknown, {
51
+ ok: true;
52
+ }>;
53
+ export declare const useSignUp: (client: AuthClient) => MutationState<{
54
+ [extra: string]: unknown;
55
+ email: string;
56
+ password: string;
57
+ }, {
58
+ status: "authenticated";
59
+ } | {
60
+ status: "verification_required";
61
+ }>;
62
+ export {};
@@ -0,0 +1,75 @@
1
+ // @bun
2
+ // src/client/react.ts
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ var useMutation = (run) => {
5
+ const [data, setData] = useState(null);
6
+ const [error, setError] = useState(null);
7
+ const [isPending, setIsPending] = useState(false);
8
+ const mountedRef = useRef(true);
9
+ useEffect(() => () => {
10
+ mountedRef.current = false;
11
+ }, []);
12
+ const mutate = useCallback(async (args) => {
13
+ setIsPending(true);
14
+ setError(null);
15
+ const result = await run(args);
16
+ if (mountedRef.current) {
17
+ setData(result.data);
18
+ setError(result.error);
19
+ setIsPending(false);
20
+ }
21
+ return result;
22
+ }, [run]);
23
+ const reset = useCallback(() => {
24
+ setData(null);
25
+ setError(null);
26
+ setIsPending(false);
27
+ }, []);
28
+ return { data, error, isPending, mutate, reset };
29
+ };
30
+ var useMagicLink = (client) => useMutation(client.passwordless.requestMagicLink);
31
+ var useMfaChallenge = (client) => useMutation(client.mfa.challenge);
32
+ var usePasswordReset = (client) => useMutation(client.passwordReset.request);
33
+ var useSessions = (client) => {
34
+ const [data, setData] = useState(null);
35
+ const [error, setError] = useState(null);
36
+ const [isPending, setIsPending] = useState(true);
37
+ const mountedRef = useRef(true);
38
+ useEffect(() => () => {
39
+ mountedRef.current = false;
40
+ }, []);
41
+ const refetch = useCallback(async () => {
42
+ setIsPending(true);
43
+ const result = await client.sessions.list();
44
+ if (mountedRef.current) {
45
+ setData(result.data);
46
+ setError(result.error);
47
+ setIsPending(false);
48
+ }
49
+ }, [client]);
50
+ useEffect(() => {
51
+ refetch();
52
+ }, [refetch]);
53
+ const revoke = useCallback(async (sessionId) => {
54
+ const result = await client.sessions.revoke(sessionId);
55
+ if (result.error === null)
56
+ await refetch();
57
+ return result;
58
+ }, [client, refetch]);
59
+ return { data, error, isPending, refetch, revoke };
60
+ };
61
+ var useSignIn = (client) => useMutation(client.signIn.email);
62
+ var useSignOut = (client) => useMutation(client.signOut);
63
+ var useSignUp = (client) => useMutation(client.signUp.email);
64
+ export {
65
+ useSignUp,
66
+ useSignOut,
67
+ useSignIn,
68
+ useSessions,
69
+ usePasswordReset,
70
+ useMfaChallenge,
71
+ useMagicLink
72
+ };
73
+
74
+ //# debugId=6E80ACAADF4D834764756E2164756E21
75
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client/react.ts"],
4
+ "sourcesContent": [
5
+ "// Thin React hooks over `createAuthClient`. Same `{ data, error }` shape; the hook adds\n// `isPending` state and a stable mutator. Bring your own form/UI — these are primitives, not\n// components. Composables (Vue/Solid/Svelte) will follow the same pattern over the same client.\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { AuthClient, AuthClientError } from './createAuthClient';\n\ntype Mutator<Args, Data> = (\n\targs: Args\n) => Promise<{ data: Data | null; error: AuthClientError | null }>;\n\ntype MutationState<Args, Data> = {\n\tdata: Data | null;\n\terror: AuthClientError | null;\n\tisPending: boolean;\n\tmutate: Mutator<Args, Data>;\n\treset: () => void;\n};\n\n// Generic mutation hook. The other hooks are 1–2 line specializations of this — kept private\n// here so consumers see the cohesive named API and don't depend on this shape.\nconst useMutation = <Args, Data>(\n\trun: Mutator<Args, Data>\n): MutationState<Args, Data> => {\n\tconst [data, setData] = useState<Data | null>(null);\n\tconst [error, setError] = useState<AuthClientError | null>(null);\n\tconst [isPending, setIsPending] = useState(false);\n\tconst mountedRef = useRef(true);\n\tuseEffect(\n\t\t() => () => {\n\t\t\tmountedRef.current = false;\n\t\t},\n\t\t[]\n\t);\n\n\tconst mutate: Mutator<Args, Data> = useCallback(\n\t\tasync (args) => {\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\t\t\tconst result = await run(args);\n\t\t\tif (mountedRef.current) {\n\t\t\t\tsetData(result.data);\n\t\t\t\tsetError(result.error);\n\t\t\t\tsetIsPending(false);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t\t[run]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetData(null);\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn { data, error, isPending, mutate, reset };\n};\n\nexport const useMagicLink = (client: AuthClient) =>\n\tuseMutation(client.passwordless.requestMagicLink);\n\nexport const useMfaChallenge = (client: AuthClient) =>\n\tuseMutation(client.mfa.challenge);\n\nexport const usePasswordReset = (client: AuthClient) =>\n\tuseMutation(client.passwordReset.request);\n\n// Query hook for the user's active sessions; refetch() reruns it. The shape matches the\n// mutation hooks closely (isPending/error/data) so the consumer can render one way.\nexport const useSessions = (client: AuthClient) => {\n\tconst [data, setData] = useState<unknown[] | null>(null);\n\tconst [error, setError] = useState<AuthClientError | null>(null);\n\tconst [isPending, setIsPending] = useState(true);\n\tconst mountedRef = useRef(true);\n\tuseEffect(\n\t\t() => () => {\n\t\t\tmountedRef.current = false;\n\t\t},\n\t\t[]\n\t);\n\n\tconst refetch = useCallback(async () => {\n\t\tsetIsPending(true);\n\t\tconst result = await client.sessions.list();\n\t\tif (mountedRef.current) {\n\t\t\tsetData(result.data);\n\t\t\tsetError(result.error);\n\t\t\tsetIsPending(false);\n\t\t}\n\t}, [client]);\n\n\tuseEffect(() => {\n\t\tvoid refetch();\n\t}, [refetch]);\n\n\tconst revoke = useCallback(\n\t\tasync (sessionId: string) => {\n\t\t\tconst result = await client.sessions.revoke(sessionId);\n\t\t\tif (result.error === null) await refetch();\n\n\t\t\treturn result;\n\t\t},\n\t\t[client, refetch]\n\t);\n\n\treturn { data, error, isPending, refetch, revoke };\n};\n\nexport const useSignIn = (client: AuthClient) =>\n\tuseMutation(client.signIn.email);\n\nexport const useSignOut = (client: AuthClient) => useMutation(client.signOut);\n\nexport const useSignUp = (client: AuthClient) =>\n\tuseMutation(client.signUp.email);\n"
6
+ ],
7
+ "mappings": ";;AAIA;AAiBA,IAAM,cAAc,CACnB,QAC+B;AAAA,EAC/B,OAAO,MAAM,WAAW,SAAsB,IAAI;AAAA,EAClD,OAAO,OAAO,YAAY,SAAiC,IAAI;AAAA,EAC/D,OAAO,WAAW,gBAAgB,SAAS,KAAK;AAAA,EAChD,MAAM,aAAa,OAAO,IAAI;AAAA,EAC9B,UACC,MAAM,MAAM;AAAA,IACX,WAAW,UAAU;AAAA,KAEtB,CAAC,CACF;AAAA,EAEA,MAAM,SAA8B,YACnC,OAAO,SAAS;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,SAAS,IAAI;AAAA,IACb,MAAM,SAAS,MAAM,IAAI,IAAI;AAAA,IAC7B,IAAI,WAAW,SAAS;AAAA,MACvB,QAAQ,OAAO,IAAI;AAAA,MACnB,SAAS,OAAO,KAAK;AAAA,MACrB,aAAa,KAAK;AAAA,IACnB;AAAA,IAEA,OAAO;AAAA,KAER,CAAC,GAAG,CACL;AAAA,EAEA,MAAM,QAAQ,YAAY,MAAM;AAAA,IAC/B,QAAQ,IAAI;AAAA,IACZ,SAAS,IAAI;AAAA,IACb,aAAa,KAAK;AAAA,KAChB,CAAC,CAAC;AAAA,EAEL,OAAO,EAAE,MAAM,OAAO,WAAW,QAAQ,MAAM;AAAA;AAGzC,IAAM,eAAe,CAAC,WAC5B,YAAY,OAAO,aAAa,gBAAgB;AAE1C,IAAM,kBAAkB,CAAC,WAC/B,YAAY,OAAO,IAAI,SAAS;AAE1B,IAAM,mBAAmB,CAAC,WAChC,YAAY,OAAO,cAAc,OAAO;AAIlC,IAAM,cAAc,CAAC,WAAuB;AAAA,EAClD,OAAO,MAAM,WAAW,SAA2B,IAAI;AAAA,EACvD,OAAO,OAAO,YAAY,SAAiC,IAAI;AAAA,EAC/D,OAAO,WAAW,gBAAgB,SAAS,IAAI;AAAA,EAC/C,MAAM,aAAa,OAAO,IAAI;AAAA,EAC9B,UACC,MAAM,MAAM;AAAA,IACX,WAAW,UAAU;AAAA,KAEtB,CAAC,CACF;AAAA,EAEA,MAAM,UAAU,YAAY,YAAY;AAAA,IACvC,aAAa,IAAI;AAAA,IACjB,MAAM,SAAS,MAAM,OAAO,SAAS,KAAK;AAAA,IAC1C,IAAI,WAAW,SAAS;AAAA,MACvB,QAAQ,OAAO,IAAI;AAAA,MACnB,SAAS,OAAO,KAAK;AAAA,MACrB,aAAa,KAAK;AAAA,IACnB;AAAA,KACE,CAAC,MAAM,CAAC;AAAA,EAEX,UAAU,MAAM;AAAA,IACV,QAAQ;AAAA,KACX,CAAC,OAAO,CAAC;AAAA,EAEZ,MAAM,SAAS,YACd,OAAO,cAAsB;AAAA,IAC5B,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO,SAAS;AAAA,IACrD,IAAI,OAAO,UAAU;AAAA,MAAM,MAAM,QAAQ;AAAA,IAEzC,OAAO;AAAA,KAER,CAAC,QAAQ,OAAO,CACjB;AAAA,EAEA,OAAO,EAAE,MAAM,OAAO,WAAW,SAAS,OAAO;AAAA;AAG3C,IAAM,YAAY,CAAC,WACzB,YAAY,OAAO,OAAO,KAAK;AAEzB,IAAM,aAAa,CAAC,WAAuB,YAAY,OAAO,OAAO;AAErE,IAAM,YAAY,CAAC,WACzB,YAAY,OAAO,OAAO,KAAK;",
8
+ "debugId": "6E80ACAADF4D834764756E2164756E21",
9
+ "names": []
10
+ }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.27.0-beta.11",
2
+ "version": "0.27.0-beta.12",
3
3
  "name": "@absolutejs/auth",
4
4
  "description": "An authorization library for absolutejs",
5
5
  "repository": {
@@ -10,7 +10,7 @@
10
10
  "license": "CC BY-NC 4.0",
11
11
  "author": "Alex Kahn",
12
12
  "scripts": {
13
- "build": "rm -rf dist && bun build src/index.ts src/htmx/index.ts --outdir dist --sourcemap --target=bun --external elysia && tsc --emitDeclarationOnly --project tsconfig.json",
13
+ "build": "rm -rf dist && bun build src/index.ts src/htmx/index.ts src/client/index.ts src/client/react.ts --outdir dist --sourcemap --target=bun --external elysia --external react && tsc --emitDeclarationOnly --project tsconfig.json",
14
14
  "config": "absolute config",
15
15
  "test": "bun test",
16
16
  "format": "absolute prettier --write",
@@ -27,7 +27,13 @@
27
27
  ],
28
28
  "types": "./dist/index.d.ts",
29
29
  "peerDependencies": {
30
- "elysia": ">= 1.4.26"
30
+ "elysia": ">= 1.4.26",
31
+ "react": ">=18 <20"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "react": {
35
+ "optional": true
36
+ }
31
37
  },
32
38
  "dependencies": {
33
39
  "@absolutejs/linked-providers": "0.0.2",
@@ -40,6 +46,7 @@
40
46
  "@eslint/js": "^10.0.1",
41
47
  "@stylistic/eslint-plugin": "^5.10.0",
42
48
  "@types/bun": "1.2.9",
49
+ "@types/react": "^19.0.0",
43
50
  "@typescript-eslint/parser": "^8.57.2",
44
51
  "elysia": "1.4.26",
45
52
  "eslint": "^10.1.0",
@@ -57,9 +64,17 @@
57
64
  "import": "./dist/index.js",
58
65
  "types": "./dist/index.d.ts"
59
66
  },
67
+ "./client": {
68
+ "import": "./dist/client/index.js",
69
+ "types": "./dist/client/index.d.ts"
70
+ },
60
71
  "./htmx": {
61
72
  "import": "./dist/htmx/index.js",
62
73
  "types": "./dist/htmx/index.d.ts"
74
+ },
75
+ "./react": {
76
+ "import": "./dist/client/react.js",
77
+ "types": "./dist/client/react.d.ts"
63
78
  }
64
79
  },
65
80
  "type": "module",