@lushly-dev/afd-auth 2.0.0 → 2.2.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 +74 -1
- package/dist/adapters/better-auth.d.ts +11 -10
- package/dist/adapters/better-auth.d.ts.map +1 -1
- package/dist/adapters/better-auth.js +3 -3
- package/dist/adapters/better-auth.js.map +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +15 -1
- package/dist/middleware.js.map +1 -1
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ const middleware = createAuthMiddleware(adapter, { exclude: ['public-cmd'] });
|
|
|
40
40
|
| `unauthenticated` | `UNAUTHORIZED`, not retryable |
|
|
41
41
|
| `loading` | `UNAUTHORIZED`, retryable |
|
|
42
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 |
|
|
43
|
+
| `authenticated` | sets `context.auth`, fills `context.actor` from the session user and runs the command |
|
|
44
44
|
|
|
45
45
|
- The built-in commands `auth-sign-in`, `auth-sign-out` and `auth-session-get`
|
|
46
46
|
(`AUTH_COMMAND_NAMES`) always run, so a signed-out caller can sign in.
|
|
@@ -48,6 +48,10 @@ const middleware = createAuthMiddleware(adapter, { exclude: ['public-cmd'] });
|
|
|
48
48
|
- The middleware sets or deletes `context.auth` on every call, excluded
|
|
49
49
|
commands included. A handler never sees a `context.auth` that the caller
|
|
50
50
|
supplied.
|
|
51
|
+
- With a verified session, a `human` (or missing) `context.actor` becomes
|
|
52
|
+
`{ kind: 'human', id: user.id, label: user.name }`. An `agent`, `service` or
|
|
53
|
+
`script` actor keeps its identity and gets `onBehalfOf: user.id`, replacing any
|
|
54
|
+
`onBehalfOf` the caller set.
|
|
51
55
|
- Importing the package types `context.auth` as
|
|
52
56
|
`AuthenticatedSessionState | undefined` through a `CommandContext` module
|
|
53
57
|
augmentation.
|
|
@@ -132,3 +136,72 @@ lock timestamp more than one second in the future counts as stale.
|
|
|
132
136
|
`localStorage` does not provide compare-and-swap, so acquisition remains
|
|
133
137
|
non-atomic under a simultaneous cross-tab race; applications that require
|
|
134
138
|
stronger serialization should use a provider-level refresh mechanism.
|
|
139
|
+
|
|
140
|
+
## Integration evidence
|
|
141
|
+
|
|
142
|
+
`pnpm -F @lushly-dev/afd-auth exec vitest run src/adapters/better-auth.integration.test.ts`
|
|
143
|
+
starts the installed Better Auth provider on an ephemeral loopback port with its memory
|
|
144
|
+
adapter. The actual vanilla client and `BetterAuthAdapter` exercise registration,
|
|
145
|
+
cookie issuance, credential rejection, sign-in, session expiry mapping, independent
|
|
146
|
+
session read-back, sign-out and revocation of the old cookie. A small Node cookie jar
|
|
147
|
+
forwards real `Set-Cookie` values; it does not implement browser cookie policy.
|
|
148
|
+
The test disposes subscriptions, closes sockets and discards all synthetic data.
|
|
149
|
+
Both the real vanilla store and the legacy function accessor are supported.
|
|
150
|
+
|
|
151
|
+
The separate browser suite installs only development tooling and runs without
|
|
152
|
+
provider credentials:
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
pnpm -F @lushly-dev/afd-auth exec playwright install chromium
|
|
156
|
+
pnpm -F @lushly-dev/afd-auth test:browser
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`browser/lifecycle.test.ts` starts the actual Better Auth memory provider and
|
|
160
|
+
bundles a small application using `BetterAuthAdapter`, `createAuthHooks` and
|
|
161
|
+
`SessionSync`. Chromium uses its own cookie jar and two real tabs in one fresh
|
|
162
|
+
context. The application explicitly broadcasts auth changes and refetches provider
|
|
163
|
+
state on received AFD messages. The suite checks:
|
|
164
|
+
|
|
165
|
+
- Registration, invalid credentials, sign-in, React session/user rendering and
|
|
166
|
+
restoration after reload; a separate browser context stays signed out.
|
|
167
|
+
- Actual HttpOnly cookie protection from `document.cookie`, SameSite=Lax and path
|
|
168
|
+
attributes, cookie removal on sign-out and expiry, and independent replay of
|
|
169
|
+
revoked or expired synthetic cookies against the provider.
|
|
170
|
+
- Cross-tab sign-in, sign-out and session renewal with BroadcastChannel, then with
|
|
171
|
+
BroadcastChannel unavailable to exercise real localStorage `storage` events.
|
|
172
|
+
- Refresh-lock ownership across tabs: a non-owner cannot acquire or release an
|
|
173
|
+
existing lock, and the next owner can acquire after release.
|
|
174
|
+
- Real wall-clock provider session renewal and expiry. The expiry case first
|
|
175
|
+
observes Chromium remove the cookie while asserting that no provider request
|
|
176
|
+
occurs, then refetches and verifies the signed-out hooks and expired-cookie
|
|
177
|
+
rejection. It uses no fake timers, injected sessions, cookie shim or mocked
|
|
178
|
+
provider endpoints.
|
|
179
|
+
|
|
180
|
+
Each run uses ephemeral loopback ports and synthetic accounts. Teardown closes
|
|
181
|
+
browser contexts, provider connections and servers and clears provider memory,
|
|
182
|
+
including after failed assertions. Session cookies and tokens are never written to
|
|
183
|
+
an evidence file. Startup, test and CI deadlines bound the run. The path-filtered
|
|
184
|
+
`Auth browser integration` workflow runs the same suite on Node 24 with a pinned
|
|
185
|
+
Playwright version and its matching Chromium. It is separate from `pnpm check`,
|
|
186
|
+
so the TypeScript gate does not require a downloaded browser binary.
|
|
187
|
+
|
|
188
|
+
This is local Chromium/provider evidence using HTTP with `Secure=false`. It does
|
|
189
|
+
not establish HTTPS Secure-cookie or cross-site SameSite enforcement, OAuth
|
|
190
|
+
callbacks, refresh of upstream OAuth tokens, simultaneous refresh-lock atomicity,
|
|
191
|
+
other browsers or Convex deployment behavior. Those deployment-specific checks
|
|
192
|
+
remain tracked in [#362](https://github.com/lushly-dev/afd/issues/362).
|
|
193
|
+
|
|
194
|
+
The additional [Better Auth HTTPS/OAuth fixture](hosted/better-auth/README.md)
|
|
195
|
+
uses a local test OAuth provider and SQLite-backed Better Auth. It exercises the
|
|
196
|
+
callback, Secure cookies and restart persistence without a hosted account. The
|
|
197
|
+
[Convex fixture](hosted/convex/README.md) bundles actual React/provider SDKs and
|
|
198
|
+
deployable backend functions; its local checks do not execute a Convex deployment.
|
|
199
|
+
|
|
200
|
+
After installing Chromium, run `pnpm test:hosted:local` from the repository root
|
|
201
|
+
on Node 24. It also runs the durable REST/view-state lifecycle. Separate opt-in
|
|
202
|
+
commands `test:hosted:better-auth` and `test:hosted:convex` require the fixture's
|
|
203
|
+
explicit disposable-service configuration and fail preflight when it is missing.
|
|
204
|
+
See the [hosted verification handoff](../../docs/operations/hosted-verification.md)
|
|
205
|
+
for local evidence, provisioning order, receipt requirements and cleanup. External
|
|
206
|
+
OAuth grants, deployment restart and actual Convex authentication remain pending
|
|
207
|
+
under #362; a local fixture pass does not close them.
|
|
@@ -36,15 +36,16 @@ interface BetterAuthClient {
|
|
|
36
36
|
}) => Promise<BetterAuthMethodResponse>;
|
|
37
37
|
};
|
|
38
38
|
signOut: () => Promise<BetterAuthMethodResponse>;
|
|
39
|
-
useSession: () =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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;
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
51
|
interface BetterAuthSessionData {
|
|
@@ -56,7 +57,7 @@ interface BetterAuthSessionData {
|
|
|
56
57
|
id: string;
|
|
57
58
|
email: string;
|
|
58
59
|
name?: string;
|
|
59
|
-
image?: string;
|
|
60
|
+
image?: string | null;
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
export interface BetterAuthAdapterOptions {
|
|
@@ -1 +1 @@
|
|
|
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,MAAM;
|
|
1
|
+
{"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -77,8 +77,8 @@ export class BetterAuthAdapter {
|
|
|
77
77
|
this.listeners.clear();
|
|
78
78
|
}
|
|
79
79
|
setupSubscription() {
|
|
80
|
-
|
|
81
|
-
const store = this.client
|
|
80
|
+
const storeAccessor = this.client.useSession;
|
|
81
|
+
const store = typeof storeAccessor === 'function' ? storeAccessor.call(this.client) : storeAccessor;
|
|
82
82
|
// Read before subscribing so stores that invoke the callback immediately do
|
|
83
83
|
// not replace an equivalent initial snapshot with a new object.
|
|
84
84
|
this.currentState = this.mapToState(store.get());
|
|
@@ -137,7 +137,7 @@ export class BetterAuthAdapter {
|
|
|
137
137
|
id: value.data.user.id,
|
|
138
138
|
email: value.data.user.email,
|
|
139
139
|
name: value.data.user.name,
|
|
140
|
-
image: value.data.user.image,
|
|
140
|
+
image: value.data.user.image ?? undefined,
|
|
141
141
|
},
|
|
142
142
|
};
|
|
143
143
|
}
|
|
@@ -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;AAChD,OAAO,EAA6B,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/adapters/better-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export interface AuthMiddlewareOptions {
|
|
|
28
28
|
* - Unauthenticated → failure with UNAUTHORIZED
|
|
29
29
|
* - Loading → failure with UNAUTHORIZED (retryable)
|
|
30
30
|
* - Authenticated but `expiresAt` reached → failure with TOKEN_EXPIRED (retryable)
|
|
31
|
-
* - Authenticated → sets `context.auth` and calls next()
|
|
31
|
+
* - Authenticated → sets `context.auth`, fills `context.actor` from the session user and calls next()
|
|
32
32
|
*
|
|
33
33
|
* Excluded commands, and the built-in auth commands, always run. They see
|
|
34
34
|
* `context.auth` only when the adapter holds an unexpired session.
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAS,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIrE,OAAO,KAAK,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,QAAQ,sBAAsB,CAAC;IACrC,UAAU,cAAc;QACvB;;;;;WAKG;QACH,IAAI,CAAC,EAAE,yBAAyB,CAAC;KACjC;CACD;AAED,MAAM,WAAW,qBAAqB;IACrC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,qBAA0B,GACjC,iBAAiB,CA8CnB"}
|
package/dist/middleware.js
CHANGED
|
@@ -4,13 +4,26 @@
|
|
|
4
4
|
import { failure } from '@lushly-dev/afd-core';
|
|
5
5
|
import { AUTH_COMMAND_NAMES } from './command-names.js';
|
|
6
6
|
import { isSessionExpired } from './session-state.js';
|
|
7
|
+
/**
|
|
8
|
+
* The actor for a call made with a verified session. A human (or unset) actor becomes the
|
|
9
|
+
* session user (`id`, and `label` from the user's name). An agent, service or script keeps
|
|
10
|
+
* its own identity and acts on behalf of the session user; a caller-supplied `onBehalfOf`
|
|
11
|
+
* is replaced, so it can never name someone other than the verified user.
|
|
12
|
+
*/
|
|
13
|
+
function actorForSession(actor, session) {
|
|
14
|
+
const { user } = session;
|
|
15
|
+
if (!actor || actor.kind === 'human') {
|
|
16
|
+
return { kind: 'human', id: user.id, ...(user.name ? { label: user.name } : {}) };
|
|
17
|
+
}
|
|
18
|
+
return { ...actor, onBehalfOf: user.id };
|
|
19
|
+
}
|
|
7
20
|
/**
|
|
8
21
|
* Create middleware that gates commands behind authentication.
|
|
9
22
|
*
|
|
10
23
|
* - Unauthenticated → failure with UNAUTHORIZED
|
|
11
24
|
* - Loading → failure with UNAUTHORIZED (retryable)
|
|
12
25
|
* - Authenticated but `expiresAt` reached → failure with TOKEN_EXPIRED (retryable)
|
|
13
|
-
* - Authenticated → sets `context.auth` and calls next()
|
|
26
|
+
* - Authenticated → sets `context.auth`, fills `context.actor` from the session user and calls next()
|
|
14
27
|
*
|
|
15
28
|
* Excluded commands, and the built-in auth commands, always run. They see
|
|
16
29
|
* `context.auth` only when the adapter holds an unexpired session.
|
|
@@ -23,6 +36,7 @@ export function createAuthMiddleware(adapter, options = {}) {
|
|
|
23
36
|
// Overwrite or remove whatever the caller put in the context.
|
|
24
37
|
if (verified) {
|
|
25
38
|
context.auth = verified;
|
|
39
|
+
context.actor = actorForSession(context.actor, verified);
|
|
26
40
|
}
|
|
27
41
|
else {
|
|
28
42
|
delete context.auth;
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAwBtD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CACnC,OAAoB,EACpB,UAAiC,EAAE;IAEnC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GACb,KAAK,CAAC,MAAM,KAAK,eAAe,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1F,8DAA8D;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAwBtD;;;;;GAKG;AACH,SAAS,eAAe,CAAC,KAAwB,EAAE,OAAkC;IACpF,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACnF,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CACnC,OAAoB,EACpB,UAAiC,EAAE;IAEnC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GACb,KAAK,CAAC,MAAM,KAAK,eAAe,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1F,8DAA8D;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC;YACxB,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACP,OAAO,OAAO,CAAC,IAAI,CAAC;QACrB,CAAC;QAED,IAAI,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC3C,OAAO,IAAI,EAAE,CAAC;QACf,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC;gBACd,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,iCAAiC;gBAC1C,UAAU,EAAE,mDAAmD;gBAC/D,SAAS,EAAE,IAAI;aACf,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACtC,OAAO,OAAO,CAAC;gBACd,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,qBAAqB;gBAC9B,UAAU,EACT,gGAAgG;gBACjG,SAAS,EAAE,IAAI;aACf,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,OAAO,CAAC;YACd,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,yBAAyB;YAClC,UAAU,EAAE,kDAAkD;YAC9D,SAAS,EAAE,KAAK;SAChB,CAAC,CAAC;IACJ,CAAC,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lushly-dev/afd-auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Provider-agnostic authentication adapter for AFD applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@lushly-dev/afd-core": "2.
|
|
27
|
+
"@lushly-dev/afd-core": "2.2.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@convex-dev/auth": ">=0.0.95",
|
|
31
31
|
"better-auth": "^1.6.22",
|
|
32
32
|
"react": "^18.0.0 || ^19.0.0",
|
|
33
33
|
"zod": "^4.0.0",
|
|
34
|
-
"@lushly-dev/afd-server": "2.
|
|
34
|
+
"@lushly-dev/afd-server": "^2.2.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
37
37
|
"@lushly-dev/afd-server": {
|
|
@@ -54,14 +54,19 @@
|
|
|
54
54
|
"@auth/core": "^0.41.3",
|
|
55
55
|
"@testing-library/react": "^16.3.3",
|
|
56
56
|
"@types/react": "^19.3.0",
|
|
57
|
+
"@types/react-dom": "19.3.0",
|
|
57
58
|
"@vitest/coverage-v8": "^4.1.11",
|
|
59
|
+
"better-auth": "^1.6.22",
|
|
60
|
+
"convex": "1.32.0",
|
|
61
|
+
"esbuild": "0.28.2",
|
|
58
62
|
"jsdom": "^30.1.0",
|
|
63
|
+
"playwright": "1.64.0",
|
|
59
64
|
"react": "^19.3.0",
|
|
60
65
|
"react-dom": "^19.3.0",
|
|
61
66
|
"typescript": "^5.9.3",
|
|
62
67
|
"vitest": "^4.1.11",
|
|
63
|
-
"zod": "^4.
|
|
64
|
-
"@lushly-dev/afd-server": "2.
|
|
68
|
+
"zod": "^4.6.6",
|
|
69
|
+
"@lushly-dev/afd-server": "2.2.0"
|
|
65
70
|
},
|
|
66
71
|
"keywords": [
|
|
67
72
|
"afd",
|
|
@@ -94,6 +99,9 @@
|
|
|
94
99
|
"dev": "tsc --watch",
|
|
95
100
|
"test": "vitest run",
|
|
96
101
|
"test:watch": "vitest",
|
|
97
|
-
"clean": "rm -rf dist"
|
|
102
|
+
"clean": "rm -rf dist",
|
|
103
|
+
"test:browser": "vitest run --config browser/vitest.config.ts",
|
|
104
|
+
"test:hosted:better-auth": "node hosted/better-auth/run.mjs --hosted",
|
|
105
|
+
"test:hosted:convex": "node hosted/convex/run.mjs --hosted"
|
|
98
106
|
}
|
|
99
107
|
}
|