@lushly-dev/afd-auth 1.0.0 → 2.1.0
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/README.md +201 -0
- package/dist/adapters/better-auth.d.ts +45 -16
- package/dist/adapters/better-auth.d.ts.map +1 -1
- package/dist/adapters/better-auth.js +76 -28
- package/dist/adapters/better-auth.js.map +1 -1
- package/dist/adapters/convex.d.ts +29 -6
- package/dist/adapters/convex.d.ts.map +1 -1
- package/dist/adapters/convex.js +139 -56
- package/dist/adapters/convex.js.map +1 -1
- package/dist/adapters/mock.d.ts +16 -4
- package/dist/adapters/mock.d.ts.map +1 -1
- package/dist/adapters/mock.js +13 -11
- package/dist/adapters/mock.js.map +1 -1
- package/dist/adapters/provider-errors.d.ts +16 -0
- package/dist/adapters/provider-errors.d.ts.map +1 -0
- package/dist/adapters/provider-errors.js +27 -0
- package/dist/adapters/provider-errors.js.map +1 -0
- package/dist/command-names.d.ts +13 -0
- package/dist/command-names.d.ts.map +1 -0
- package/dist/command-names.js +13 -0
- package/dist/command-names.js.map +1 -0
- package/dist/commands.d.ts +11 -2
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +141 -9
- package/dist/commands.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/listeners.d.ts +39 -0
- package/dist/listeners.d.ts.map +1 -0
- package/dist/listeners.js +72 -0
- package/dist/listeners.js.map +1 -0
- package/dist/middleware.d.ts +22 -3
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +32 -14
- package/dist/middleware.js.map +1 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +19 -5
- package/dist/react.js.map +1 -1
- package/dist/session-state.d.ts +19 -0
- package/dist/session-state.d.ts.map +1 -0
- package/dist/session-state.js +42 -0
- package/dist/session-state.js.map +1 -0
- package/dist/session-sync-message.d.ts +29 -0
- package/dist/session-sync-message.d.ts.map +1 -0
- package/dist/session-sync-message.js +27 -0
- package/dist/session-sync-message.js.map +1 -0
- package/dist/session-sync.d.ts +35 -8
- package/dist/session-sync.d.ts.map +1 -1
- package/dist/session-sync.js +178 -44
- package/dist/session-sync.js.map +1 -1
- package/dist/types.d.ts +35 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -16
package/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# @lushly-dev/afd-auth
|
|
2
|
+
|
|
3
|
+
Provider-agnostic authentication adapters for AFD applications. The main
|
|
4
|
+
entrypoint exposes the `AuthAdapter` contract, structured auth errors, the auth
|
|
5
|
+
middleware, multi-tab session synchronization, and the Mock and Better Auth
|
|
6
|
+
adapters.
|
|
7
|
+
|
|
8
|
+
Auth command definitions are available from the optional commands subpath:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createAuthCommands } from '@lushly-dev/afd-auth/commands';
|
|
12
|
+
|
|
13
|
+
const authCommands = createAuthCommands(adapter, { signInTimeoutMs: 10_000 });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
React hooks are available from the optional `@lushly-dev/afd-auth/react`
|
|
17
|
+
subpath:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createAuthHooks, useConvexAuthAdapter } from '@lushly-dev/afd-auth/react';
|
|
21
|
+
|
|
22
|
+
const { useSession, useUser } = createAuthHooks(adapter);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The root import stays usable for server and non-React consumers without
|
|
26
|
+
installing React, `@lushly-dev/afd-server`, or `zod`. Import
|
|
27
|
+
`useConvexAuthAdapter` from `/react` and `createAuthCommands` from `/commands`
|
|
28
|
+
when those integrations are needed.
|
|
29
|
+
|
|
30
|
+
## Middleware
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createAuthMiddleware } from '@lushly-dev/afd-auth';
|
|
34
|
+
|
|
35
|
+
const middleware = createAuthMiddleware(adapter, { exclude: ['public-cmd'] });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Adapter state | Result |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `unauthenticated` | `UNAUTHORIZED`, not retryable |
|
|
41
|
+
| `loading` | `UNAUTHORIZED`, retryable |
|
|
42
|
+
| `authenticated`, `session.expiresAt` at or before now (or not a valid date) | `TOKEN_EXPIRED`, retryable |
|
|
43
|
+
| `authenticated` | sets `context.auth` and runs the command |
|
|
44
|
+
|
|
45
|
+
- The built-in commands `auth-sign-in`, `auth-sign-out` and `auth-session-get`
|
|
46
|
+
(`AUTH_COMMAND_NAMES`) always run, so a signed-out caller can sign in.
|
|
47
|
+
`exclude` adds more commands.
|
|
48
|
+
- The middleware sets or deletes `context.auth` on every call, excluded
|
|
49
|
+
commands included. A handler never sees a `context.auth` that the caller
|
|
50
|
+
supplied.
|
|
51
|
+
- Importing the package types `context.auth` as
|
|
52
|
+
`AuthenticatedSessionState | undefined` through a `CommandContext` module
|
|
53
|
+
augmentation.
|
|
54
|
+
- `Session.expiresAt` is optional. A session without it (Convex) is never
|
|
55
|
+
rejected as expired; the provider manages the token lifetime.
|
|
56
|
+
|
|
57
|
+
## Sign-in results
|
|
58
|
+
|
|
59
|
+
`AuthAdapter.signIn()` may resolve with a `SignInOutcome`:
|
|
60
|
+
`{ kind: 'signed-in' }`, `{ kind: 'redirect', url? }` (OAuth continues at the
|
|
61
|
+
provider) or `{ kind: 'pending' }` (another step, such as email verification).
|
|
62
|
+
Resolving with nothing is still allowed and counts as `signed-in`.
|
|
63
|
+
|
|
64
|
+
`auth-sign-in` uses it to report what happened:
|
|
65
|
+
|
|
66
|
+
- `redirect` / `pending`: returns the current (not yet signed-in) state with
|
|
67
|
+
"Not signed in yet" reasoning and a `SIGN_IN_REDIRECT` or `SIGN_IN_PENDING`
|
|
68
|
+
warning. The redirect URL is in the warning's `details.url`.
|
|
69
|
+
- otherwise: waits for the next non-loading `onAuthStateChange`, up to
|
|
70
|
+
`signInTimeoutMs` (default 10 s), and returns the new session. If the wait
|
|
71
|
+
runs out it returns the current state with a `SIGN_IN_PENDING` warning; if
|
|
72
|
+
the adapter settles on no session it fails with `PROVIDER_ERROR`.
|
|
73
|
+
|
|
74
|
+
## Adapters
|
|
75
|
+
|
|
76
|
+
All adapters accept `onListenerError`. Each `onAuthStateChange` subscriber
|
|
77
|
+
runs in its own `try/catch`: one that throws does not stop the others from
|
|
78
|
+
seeing the change, and does not make `signIn()`/`signOut()` reject. The error
|
|
79
|
+
goes to `onListenerError`, or is rethrown in a microtask when none is set.
|
|
80
|
+
|
|
81
|
+
### Convex
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const adapter = useConvexAuthAdapter({
|
|
85
|
+
useAuthActions,
|
|
86
|
+
useConvexAuth,
|
|
87
|
+
meQuery: () => useQuery(api.users.me),
|
|
88
|
+
passwordProviderId: 'password', // default: the stock Password() provider
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Credentials sign-in calls `signIn(passwordProviderId, { email, password, flow: 'signIn' })`.
|
|
93
|
+
A missing password is rejected with `INVALID_CREDENTIALS`.
|
|
94
|
+
- OAuth sign-in forwards `redirectTo`. `scopes` are rejected with
|
|
95
|
+
`PROVIDER_ERROR`: Convex configures scopes on the provider in
|
|
96
|
+
`convex/auth.ts`.
|
|
97
|
+
- Errors use the same codes as Better Auth: `InvalidAccountId`,
|
|
98
|
+
`InvalidSecret` and `Invalid credentials` become `INVALID_CREDENTIALS`, fetch
|
|
99
|
+
failures `NETWORK_ERROR`, everything else `PROVIDER_ERROR`. Production
|
|
100
|
+
Convex deployments hide server error text unless it is thrown as a
|
|
101
|
+
`ConvexError`, so there bad credentials surface as `PROVIDER_ERROR`.
|
|
102
|
+
- The state is `loading` while `meQuery` returns `undefined`, and
|
|
103
|
+
`unauthenticated` when it returns `null`.
|
|
104
|
+
- The session has no `expiresAt`, because Convex refreshes its token
|
|
105
|
+
internally.
|
|
106
|
+
- The hook returns the same adapter object on every render.
|
|
107
|
+
|
|
108
|
+
### Better Auth
|
|
109
|
+
|
|
110
|
+
`BetterAuthAdapter` forwards OAuth `scopes` and `redirectTo` (as
|
|
111
|
+
`callbackURL`) to `signIn.social`, and reports its redirect URL as a
|
|
112
|
+
`redirect` outcome.
|
|
113
|
+
|
|
114
|
+
## Session sync
|
|
115
|
+
|
|
116
|
+
`SessionSync` exchanges typed `SessionSyncMessage` values: `signed-in`,
|
|
117
|
+
`signed-out`, `session-refreshed`, `profile-updated` (both with an optional
|
|
118
|
+
`userId`) and `visibility-refresh`. Received payloads are validated and reduced
|
|
119
|
+
to those fields; `notifySessionChanged()` throws a `TypeError` for an invalid
|
|
120
|
+
message.
|
|
121
|
+
|
|
122
|
+
Received messages are debounced per type by `debounceMs`. `signed-out` is
|
|
123
|
+
delivered at once and cancels older messages still waiting, so it is never
|
|
124
|
+
coalesced away.
|
|
125
|
+
|
|
126
|
+
`SessionSync.acquireRefreshLock()` and `releaseRefreshLock()` provide a
|
|
127
|
+
synchronous best-effort fallback for coordinating refreshes between tabs. The
|
|
128
|
+
fallback records an instance owner and only that owner can release its current
|
|
129
|
+
lock. `acquireRefreshLockAsync()` waits `lockCheckDelayMs` after writing the
|
|
130
|
+
lock and reads it back before claiming it, which catches most write races. A
|
|
131
|
+
lock timestamp more than one second in the future counts as stale.
|
|
132
|
+
`localStorage` does not provide compare-and-swap, so acquisition remains
|
|
133
|
+
non-atomic under a simultaneous cross-tab race; applications that require
|
|
134
|
+
stronger serialization should use a provider-level refresh mechanism.
|
|
135
|
+
|
|
136
|
+
## Integration evidence
|
|
137
|
+
|
|
138
|
+
`pnpm -F @lushly-dev/afd-auth exec vitest run src/adapters/better-auth.integration.test.ts`
|
|
139
|
+
starts the installed Better Auth provider on an ephemeral loopback port with its memory
|
|
140
|
+
adapter. The actual vanilla client and `BetterAuthAdapter` exercise registration,
|
|
141
|
+
cookie issuance, credential rejection, sign-in, session expiry mapping, independent
|
|
142
|
+
session read-back, sign-out and revocation of the old cookie. A small Node cookie jar
|
|
143
|
+
forwards real `Set-Cookie` values; it does not implement browser cookie policy.
|
|
144
|
+
The test disposes subscriptions, closes sockets and discards all synthetic data.
|
|
145
|
+
Both the real vanilla store and the legacy function accessor are supported.
|
|
146
|
+
|
|
147
|
+
The separate browser suite installs only development tooling and runs without
|
|
148
|
+
provider credentials:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
pnpm -F @lushly-dev/afd-auth exec playwright install chromium
|
|
152
|
+
pnpm -F @lushly-dev/afd-auth test:browser
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`browser/lifecycle.test.ts` starts the actual Better Auth memory provider and
|
|
156
|
+
bundles a small application using `BetterAuthAdapter`, `createAuthHooks` and
|
|
157
|
+
`SessionSync`. Chromium uses its own cookie jar and two real tabs in one fresh
|
|
158
|
+
context. The application explicitly broadcasts auth changes and refetches provider
|
|
159
|
+
state on received AFD messages. The suite checks:
|
|
160
|
+
|
|
161
|
+
- Registration, invalid credentials, sign-in, React session/user rendering and
|
|
162
|
+
restoration after reload; a separate browser context stays signed out.
|
|
163
|
+
- Actual HttpOnly cookie protection from `document.cookie`, SameSite=Lax and path
|
|
164
|
+
attributes, cookie removal on sign-out and expiry, and independent replay of
|
|
165
|
+
revoked or expired synthetic cookies against the provider.
|
|
166
|
+
- Cross-tab sign-in, sign-out and session renewal with BroadcastChannel, then with
|
|
167
|
+
BroadcastChannel unavailable to exercise real localStorage `storage` events.
|
|
168
|
+
- Refresh-lock ownership across tabs: a non-owner cannot acquire or release an
|
|
169
|
+
existing lock, and the next owner can acquire after release.
|
|
170
|
+
- Real wall-clock provider session renewal and expiry. The expiry case first
|
|
171
|
+
observes Chromium remove the cookie while asserting that no provider request
|
|
172
|
+
occurs, then refetches and verifies the signed-out hooks and expired-cookie
|
|
173
|
+
rejection. It uses no fake timers, injected sessions, cookie shim or mocked
|
|
174
|
+
provider endpoints.
|
|
175
|
+
|
|
176
|
+
Each run uses ephemeral loopback ports and synthetic accounts. Teardown closes
|
|
177
|
+
browser contexts, provider connections and servers and clears provider memory,
|
|
178
|
+
including after failed assertions. Session cookies and tokens are never written to
|
|
179
|
+
an evidence file. Startup, test and CI deadlines bound the run. The path-filtered
|
|
180
|
+
`Auth browser integration` workflow runs the same suite on Node 24 with a pinned
|
|
181
|
+
Playwright version and its matching Chromium. It is separate from `pnpm check`,
|
|
182
|
+
so the TypeScript gate does not require a downloaded browser binary.
|
|
183
|
+
|
|
184
|
+
This is local Chromium/provider evidence using HTTP with `Secure=false`. It does
|
|
185
|
+
not establish HTTPS Secure-cookie or cross-site SameSite enforcement, OAuth
|
|
186
|
+
callbacks, refresh of upstream OAuth tokens, simultaneous refresh-lock atomicity,
|
|
187
|
+
other browsers or Convex deployment behavior. Those deployment-specific checks
|
|
188
|
+
remain tracked in [#362](https://github.com/lushly-dev/afd/issues/362).
|
|
189
|
+
|
|
190
|
+
For an optional provider/browser validation run, provision a disposable staging
|
|
191
|
+
application with its HTTPS origin and callback URL registered with the provider,
|
|
192
|
+
a dedicated test account, test OAuth client configuration (or a dedicated Convex
|
|
193
|
+
deployment) and a short session lifetime. Use two tabs in one fresh browser profile:
|
|
194
|
+
complete OAuth through the actual callback, verify the adapter user/session in both
|
|
195
|
+
tabs, trigger provider refresh across expiry, then sign out and verify both tabs
|
|
196
|
+
and an independent session endpoint reject the previous session. Record deployment
|
|
197
|
+
revision, provider/client version, cookie attributes, timing and each observed
|
|
198
|
+
outcome without recording tokens. Revoke test sessions, delete the test account
|
|
199
|
+
and disposable deployment, and close the profile. Missing configuration means
|
|
200
|
+
**not run**; the local test cannot satisfy those checks. Production credentials
|
|
201
|
+
are unnecessary for the default gate.
|
|
@@ -4,29 +4,48 @@
|
|
|
4
4
|
* Bridges better-auth client to the AuthAdapter interface.
|
|
5
5
|
* Types are defined locally to avoid hard dependency on better-auth.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
7
|
+
import { type ListenerErrorHandler } from '../listeners.js';
|
|
8
|
+
import type { AuthAdapter, AuthSessionState, SignInOptions, SignInOutcome } from '../types.js';
|
|
8
9
|
/** Minimal interface for better-auth client — avoids hard import */
|
|
10
|
+
interface BetterAuthErrorResponse {
|
|
11
|
+
message?: string;
|
|
12
|
+
status?: number;
|
|
13
|
+
statusText?: string;
|
|
14
|
+
code?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The small portion of Better Auth's response contract used by this adapter.
|
|
18
|
+
* Better Auth reports provider failures as resolved `{ data, error }` values;
|
|
19
|
+
* they do not necessarily reject the promise.
|
|
20
|
+
*/
|
|
21
|
+
interface BetterAuthMethodResult {
|
|
22
|
+
data?: unknown | null;
|
|
23
|
+
error?: BetterAuthErrorResponse | null;
|
|
24
|
+
}
|
|
25
|
+
type BetterAuthMethodResponse = BetterAuthMethodResult | undefined;
|
|
9
26
|
interface BetterAuthClient {
|
|
10
27
|
signIn: {
|
|
11
28
|
social: (params: {
|
|
12
29
|
provider: string;
|
|
13
30
|
callbackURL?: string;
|
|
14
|
-
|
|
31
|
+
scopes?: string[];
|
|
32
|
+
}) => Promise<BetterAuthMethodResponse>;
|
|
15
33
|
email: (params: {
|
|
16
34
|
email: string;
|
|
17
35
|
password: string;
|
|
18
|
-
}) => Promise<
|
|
36
|
+
}) => Promise<BetterAuthMethodResponse>;
|
|
19
37
|
};
|
|
20
|
-
signOut: () => Promise<
|
|
21
|
-
useSession: () =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
signOut: () => Promise<BetterAuthMethodResponse>;
|
|
39
|
+
useSession: BetterAuthSessionStore | (() => BetterAuthSessionStore);
|
|
40
|
+
}
|
|
41
|
+
interface BetterAuthSessionStore {
|
|
42
|
+
subscribe: (callback: (value: {
|
|
43
|
+
data: BetterAuthSessionData | null;
|
|
44
|
+
isPending: boolean;
|
|
45
|
+
}) => void) => () => void;
|
|
46
|
+
get: () => {
|
|
47
|
+
data: BetterAuthSessionData | null;
|
|
48
|
+
isPending: boolean;
|
|
30
49
|
};
|
|
31
50
|
}
|
|
32
51
|
interface BetterAuthSessionData {
|
|
@@ -38,20 +57,26 @@ interface BetterAuthSessionData {
|
|
|
38
57
|
id: string;
|
|
39
58
|
email: string;
|
|
40
59
|
name?: string;
|
|
41
|
-
image?: string;
|
|
60
|
+
image?: string | null;
|
|
42
61
|
};
|
|
43
62
|
}
|
|
44
63
|
export interface BetterAuthAdapterOptions {
|
|
45
64
|
/** better-auth client instance */
|
|
46
65
|
client: BetterAuthClient;
|
|
66
|
+
/**
|
|
67
|
+
* Receives errors thrown by `onAuthStateChange` subscribers. Without it,
|
|
68
|
+
* they are rethrown in a microtask. Either way the other subscribers still
|
|
69
|
+
* run.
|
|
70
|
+
*/
|
|
71
|
+
onListenerError?: ListenerErrorHandler;
|
|
47
72
|
}
|
|
48
73
|
export declare class BetterAuthAdapter implements AuthAdapter {
|
|
49
74
|
private readonly client;
|
|
50
|
-
private listeners;
|
|
75
|
+
private readonly listeners;
|
|
51
76
|
private currentState;
|
|
52
77
|
private unsubscribeStore;
|
|
53
78
|
constructor(options: BetterAuthAdapterOptions);
|
|
54
|
-
signIn(options: SignInOptions): Promise<
|
|
79
|
+
signIn(options: SignInOptions): Promise<SignInOutcome>;
|
|
55
80
|
signOut(): Promise<void>;
|
|
56
81
|
getSession(): AuthSessionState;
|
|
57
82
|
onAuthStateChange(callback: (state: AuthSessionState) => void): {
|
|
@@ -62,6 +87,10 @@ export declare class BetterAuthAdapter implements AuthAdapter {
|
|
|
62
87
|
*/
|
|
63
88
|
dispose(): void;
|
|
64
89
|
private setupSubscription;
|
|
90
|
+
private updateState;
|
|
91
|
+
private getResolvedProviderError;
|
|
92
|
+
private describeError;
|
|
93
|
+
private mapThrownError;
|
|
65
94
|
private mapToState;
|
|
66
95
|
}
|
|
67
96
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,KAAK,oBAAoB,EAAe,MAAM,iBAAiB,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI/F,oEAAoE;AACpE,UAAU,uBAAuB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,UAAU,sBAAsB;IAC/B,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACvC;AAED,KAAK,wBAAwB,GAAG,sBAAsB,GAAG,SAAS,CAAC;AAEnE,UAAU,gBAAgB;IACzB,MAAM,EAAE;QACP,MAAM,EAAE,CAAC,MAAM,EAAE;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;SAClB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACxC,KAAK,EAAE,CAAC,MAAM,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;KAC1F,CAAC;IACF,OAAO,EAAE,MAAM,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACjD,UAAU,EAAE,sBAAsB,GAAG,CAAC,MAAM,sBAAsB,CAAC,CAAC;CACpE;AAED,UAAU,sBAAsB;IAC/B,SAAS,EAAE,CACV,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,KACjF,MAAM,IAAI,CAAC;IAChB,GAAG,EAAE,MAAM;QAAE,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CACtE;AAED,UAAU,qBAAqB;IAC9B,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAClD,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,wBAAwB;IACxC,kCAAkC;IAClC,MAAM,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,eAAe,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,gBAAgB,CAA6B;gBAEzC,OAAO,EAAE,wBAAwB;IAMvC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IA6BtD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,UAAU,IAAI,gBAAgB;IAI9B,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG;QAAE,WAAW,EAAE,MAAM,IAAI,CAAA;KAAE;IAI3F;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;CA6BlB"}
|
|
@@ -5,57 +5,66 @@
|
|
|
5
5
|
* Types are defined locally to avoid hard dependency on better-auth.
|
|
6
6
|
*/
|
|
7
7
|
import { AuthAdapterError } from '../errors.js';
|
|
8
|
+
import { ListenerSet } from '../listeners.js';
|
|
9
|
+
import { areSessionStatesEqual } from '../session-state.js';
|
|
8
10
|
import { LOADING, UNAUTHENTICATED } from '../types.js';
|
|
11
|
+
import { isKnownNetworkFailure } from './provider-errors.js';
|
|
9
12
|
export class BetterAuthAdapter {
|
|
10
13
|
client;
|
|
11
|
-
listeners
|
|
14
|
+
listeners;
|
|
12
15
|
currentState = LOADING;
|
|
13
16
|
unsubscribeStore = null;
|
|
14
17
|
constructor(options) {
|
|
15
18
|
this.client = options.client;
|
|
19
|
+
this.listeners = new ListenerSet(options.onListenerError);
|
|
16
20
|
this.setupSubscription();
|
|
17
21
|
}
|
|
18
22
|
async signIn(options) {
|
|
19
23
|
try {
|
|
24
|
+
let result;
|
|
20
25
|
if (options.method === 'credentials') {
|
|
21
|
-
await this.client.signIn.email({
|
|
26
|
+
result = await this.client.signIn.email({
|
|
22
27
|
email: options.email,
|
|
23
28
|
password: options.password ?? '',
|
|
24
29
|
});
|
|
25
30
|
}
|
|
26
31
|
else {
|
|
27
|
-
await this.client.signIn.social({
|
|
32
|
+
result = await this.client.signIn.social({
|
|
28
33
|
provider: options.provider,
|
|
29
34
|
callbackURL: options.redirectTo,
|
|
35
|
+
scopes: options.scopes,
|
|
30
36
|
});
|
|
31
37
|
}
|
|
38
|
+
const providerError = this.getResolvedProviderError(result);
|
|
39
|
+
if (providerError) {
|
|
40
|
+
if (options.method === 'credentials' && providerError.status === 401) {
|
|
41
|
+
throw AuthAdapterError.invalidCredentials();
|
|
42
|
+
}
|
|
43
|
+
throw AuthAdapterError.providerError('better-auth', this.describeError(providerError));
|
|
44
|
+
}
|
|
45
|
+
return toSignInOutcome(result);
|
|
32
46
|
}
|
|
33
47
|
catch (error) {
|
|
34
|
-
|
|
35
|
-
throw error;
|
|
36
|
-
throw AuthAdapterError.providerError('better-auth', error instanceof Error ? error.message : String(error));
|
|
48
|
+
throw this.mapThrownError(error);
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
async signOut() {
|
|
40
52
|
try {
|
|
41
|
-
await this.client.signOut();
|
|
53
|
+
const result = await this.client.signOut();
|
|
54
|
+
const providerError = this.getResolvedProviderError(result);
|
|
55
|
+
if (providerError) {
|
|
56
|
+
throw AuthAdapterError.providerError('better-auth', this.describeError(providerError));
|
|
57
|
+
}
|
|
42
58
|
}
|
|
43
59
|
catch (error) {
|
|
44
|
-
|
|
45
|
-
throw error;
|
|
46
|
-
throw AuthAdapterError.providerError('better-auth', error instanceof Error ? error.message : String(error));
|
|
60
|
+
throw this.mapThrownError(error);
|
|
47
61
|
}
|
|
48
62
|
}
|
|
49
63
|
getSession() {
|
|
50
64
|
return this.currentState;
|
|
51
65
|
}
|
|
52
66
|
onAuthStateChange(callback) {
|
|
53
|
-
this.listeners.add(callback);
|
|
54
|
-
return {
|
|
55
|
-
unsubscribe: () => {
|
|
56
|
-
this.listeners.delete(callback);
|
|
57
|
-
},
|
|
58
|
-
};
|
|
67
|
+
return this.listeners.add(callback);
|
|
59
68
|
}
|
|
60
69
|
/**
|
|
61
70
|
* Clean up the nanostore subscription.
|
|
@@ -68,19 +77,46 @@ export class BetterAuthAdapter {
|
|
|
68
77
|
this.listeners.clear();
|
|
69
78
|
}
|
|
70
79
|
setupSubscription() {
|
|
71
|
-
|
|
72
|
-
const store = this.client
|
|
80
|
+
const storeAccessor = this.client.useSession;
|
|
81
|
+
const store = typeof storeAccessor === 'function' ? storeAccessor.call(this.client) : storeAccessor;
|
|
82
|
+
// Read before subscribing so stores that invoke the callback immediately do
|
|
83
|
+
// not replace an equivalent initial snapshot with a new object.
|
|
84
|
+
this.currentState = this.mapToState(store.get());
|
|
73
85
|
this.unsubscribeStore = store.subscribe((value) => {
|
|
74
|
-
|
|
75
|
-
if (newState.status !== this.currentState.status) {
|
|
76
|
-
this.currentState = newState;
|
|
77
|
-
for (const listener of this.listeners) {
|
|
78
|
-
listener(newState);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
86
|
+
this.updateState(value);
|
|
81
87
|
});
|
|
82
|
-
//
|
|
83
|
-
|
|
88
|
+
// A store can change while subscribe() is being attached without calling
|
|
89
|
+
// the callback. Reconcile once more so the adapter never exposes a stale
|
|
90
|
+
// initial snapshot.
|
|
91
|
+
this.updateState(store.get());
|
|
92
|
+
}
|
|
93
|
+
updateState(value) {
|
|
94
|
+
const newState = this.mapToState(value);
|
|
95
|
+
if (areSessionStatesEqual(newState, this.currentState))
|
|
96
|
+
return;
|
|
97
|
+
this.currentState = newState;
|
|
98
|
+
this.listeners.emit(newState);
|
|
99
|
+
}
|
|
100
|
+
getResolvedProviderError(result) {
|
|
101
|
+
return result?.error ?? null;
|
|
102
|
+
}
|
|
103
|
+
describeError(error) {
|
|
104
|
+
if (error.message)
|
|
105
|
+
return error.message;
|
|
106
|
+
if (error.statusText)
|
|
107
|
+
return error.statusText;
|
|
108
|
+
if (error.code)
|
|
109
|
+
return error.code;
|
|
110
|
+
return error.status === undefined ? undefined : `status ${error.status}`;
|
|
111
|
+
}
|
|
112
|
+
mapThrownError(error) {
|
|
113
|
+
if (error instanceof AuthAdapterError)
|
|
114
|
+
return error;
|
|
115
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
116
|
+
if (isKnownNetworkFailure(error, message)) {
|
|
117
|
+
return AuthAdapterError.networkError();
|
|
118
|
+
}
|
|
119
|
+
return AuthAdapterError.providerError('better-auth', message);
|
|
84
120
|
}
|
|
85
121
|
mapToState(value) {
|
|
86
122
|
if (value.isPending) {
|
|
@@ -101,9 +137,21 @@ export class BetterAuthAdapter {
|
|
|
101
137
|
id: value.data.user.id,
|
|
102
138
|
email: value.data.user.email,
|
|
103
139
|
name: value.data.user.name,
|
|
104
|
-
image: value.data.user.image,
|
|
140
|
+
image: value.data.user.image ?? undefined,
|
|
105
141
|
},
|
|
106
142
|
};
|
|
107
143
|
}
|
|
108
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Better Auth answers a social sign-in with `{ url, redirect: true }` and
|
|
147
|
+
* navigates the browser there; the session exists only after the callback.
|
|
148
|
+
*/
|
|
149
|
+
function toSignInOutcome(result) {
|
|
150
|
+
const data = result?.data;
|
|
151
|
+
if (typeof data === 'object' && data !== null && 'redirect' in data && data.redirect === true) {
|
|
152
|
+
const url = 'url' in data && typeof data.url === 'string' ? data.url : undefined;
|
|
153
|
+
return url === undefined ? { kind: 'redirect' } : { kind: 'redirect', url };
|
|
154
|
+
}
|
|
155
|
+
return { kind: 'signed-in' };
|
|
156
|
+
}
|
|
109
157
|
//# sourceMappingURL=better-auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,25 +4,48 @@
|
|
|
4
4
|
* Bridges @convex-dev/auth React hooks to the AuthAdapter interface.
|
|
5
5
|
* This is a React hook — must be called inside a component.
|
|
6
6
|
*/
|
|
7
|
+
import { type ListenerErrorHandler } from '../listeners.js';
|
|
7
8
|
import type { AuthAdapter, User } from '../types.js';
|
|
9
|
+
/** The part of `useAuthActions()` from `@convex-dev/auth/react` that the adapter calls. */
|
|
10
|
+
export interface ConvexAuthActions {
|
|
11
|
+
/** Resolves with `{ signingIn, redirect? }` in @convex-dev/auth. */
|
|
12
|
+
signIn: (provider: string, params?: Record<string, string>) => Promise<unknown>;
|
|
13
|
+
signOut: () => Promise<void>;
|
|
14
|
+
}
|
|
8
15
|
export interface ConvexAuthAdapterOptions {
|
|
9
16
|
/** Return value of useAuthActions() from @convex-dev/auth/react */
|
|
10
|
-
useAuthActions: () =>
|
|
11
|
-
signIn: (provider: string, params?: Record<string, unknown>) => Promise<void>;
|
|
12
|
-
signOut: () => Promise<void>;
|
|
13
|
-
};
|
|
17
|
+
useAuthActions: () => ConvexAuthActions;
|
|
14
18
|
/** Return value of useConvexAuth() from convex/react */
|
|
15
19
|
useConvexAuth: () => {
|
|
16
20
|
isAuthenticated: boolean;
|
|
17
21
|
isLoading: boolean;
|
|
18
22
|
};
|
|
19
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* A Convex query hook that returns the current user, e.g. useQuery(api.users.me).
|
|
25
|
+
* While it returns `undefined` (still loading) the adapter reports `loading`.
|
|
26
|
+
* `null` while Convex is authenticated (no user document) is reported as
|
|
27
|
+
* `unauthenticated`.
|
|
28
|
+
*/
|
|
20
29
|
meQuery: () => User | null | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Id of the Password provider used for `credentials` sign-in (default:
|
|
32
|
+
* `'password'`, the id of the stock `Password()` provider). Set it when the
|
|
33
|
+
* provider is configured with a custom `id`.
|
|
34
|
+
*/
|
|
35
|
+
passwordProviderId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Receives errors thrown by `onAuthStateChange` subscribers. Without it,
|
|
38
|
+
* they are rethrown in a microtask. Either way the other subscribers still
|
|
39
|
+
* run.
|
|
40
|
+
*/
|
|
41
|
+
onListenerError?: ListenerErrorHandler;
|
|
21
42
|
}
|
|
22
43
|
/**
|
|
23
44
|
* React hook that creates an AuthAdapter backed by Convex.
|
|
24
45
|
*
|
|
25
|
-
* Must be called inside a ConvexProvider + ConvexAuthProvider tree.
|
|
46
|
+
* Must be called inside a ConvexProvider + ConvexAuthProvider tree. It returns
|
|
47
|
+
* the same adapter object on every render; the adapter always uses the latest
|
|
48
|
+
* actions and options passed to the hook.
|
|
26
49
|
*/
|
|
27
50
|
export declare function useConvexAuthAdapter(options: ConvexAuthAdapterOptions): AuthAdapter;
|
|
28
51
|
//# sourceMappingURL=convex.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convex.d.ts","sourceRoot":"","sources":["../../src/adapters/convex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"convex.d.ts","sourceRoot":"","sources":["../../src/adapters/convex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,KAAK,oBAAoB,EAAoC,MAAM,iBAAiB,CAAC;AAE9F,OAAO,KAAK,EACX,WAAW,EAIX,IAAI,EACJ,MAAM,aAAa,CAAC;AAOrB,2FAA2F;AAC3F,MAAM,WAAW,iBAAiB;IACjC,oEAAoE;IACpE,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChF,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAwB;IACxC,mEAAmE;IACnE,cAAc,EAAE,MAAM,iBAAiB,CAAC;IACxC,wDAAwD;IACxD,aAAa,EAAE,MAAM;QAAE,eAAe,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACtE;;;;;OAKG;IACH,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,GAAG,WAAW,CAmDnF"}
|