@next-safe-action/adapter-better-auth 0.1.0 → 0.1.2
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 +8 -8
- package/dist/index.d.mts +13 -14
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<a href="https://github.com/next-safe-action/next-safe-action/packages/adapter-better-auth"><h1>adapter-better-auth</h1></a>
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
|
-
This adapter offers a way to seamlessly integrate [next-safe-action](https://github.com/next-safe-action/next-safe-action) with [Better Auth](https://www.better-auth.com). It provides a `
|
|
6
|
+
This adapter offers a way to seamlessly integrate [next-safe-action](https://github.com/next-safe-action/next-safe-action) with [Better Auth](https://www.better-auth.com). It provides a `betterAuth()` function that fetches the session, blocks unauthenticated requests, and injects fully-typed `{ user, session }` data into the action context.
|
|
7
7
|
|
|
8
8
|
## Requirements
|
|
9
9
|
|
|
@@ -37,12 +37,12 @@ export const auth = betterAuth({
|
|
|
37
37
|
```ts
|
|
38
38
|
// src/lib/safe-action.ts
|
|
39
39
|
import { createSafeActionClient } from "next-safe-action";
|
|
40
|
-
import {
|
|
40
|
+
import { betterAuth } from "@next-safe-action/adapter-better-auth";
|
|
41
41
|
import { auth } from "./auth";
|
|
42
42
|
|
|
43
43
|
export const actionClient = createSafeActionClient();
|
|
44
44
|
|
|
45
|
-
export const authClient = actionClient.use(
|
|
45
|
+
export const authClient = actionClient.use(betterAuth(auth));
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### 3. Use it in your actions
|
|
@@ -71,7 +71,7 @@ export const updateProfile = authClient
|
|
|
71
71
|
|
|
72
72
|
## How it works
|
|
73
73
|
|
|
74
|
-
`
|
|
74
|
+
`betterAuth()` creates a pre-validation middleware for the safe action client's `.use()` chain:
|
|
75
75
|
|
|
76
76
|
1. **Fetches the session** by calling `auth.api.getSession({ headers: await headers() })`
|
|
77
77
|
2. **Blocks unauthenticated requests** by calling `unauthorized()` from `next/navigation` when no session exists
|
|
@@ -100,12 +100,12 @@ Pass an `authorize` callback to customize the authorization flow. The session is
|
|
|
100
100
|
|
|
101
101
|
```ts
|
|
102
102
|
import { unauthorized } from "next/navigation";
|
|
103
|
-
import {
|
|
103
|
+
import { betterAuth } from "@next-safe-action/adapter-better-auth";
|
|
104
104
|
import { auth } from "./auth";
|
|
105
105
|
|
|
106
106
|
// Role-based access
|
|
107
107
|
export const adminClient = actionClient.use(
|
|
108
|
-
|
|
108
|
+
betterAuth(auth, {
|
|
109
109
|
authorize: ({ sessionData, next }) => {
|
|
110
110
|
if (!sessionData || sessionData.user.role !== "admin") {
|
|
111
111
|
unauthorized();
|
|
@@ -143,7 +143,7 @@ export const auth = betterAuth({
|
|
|
143
143
|
|
|
144
144
|
## API reference
|
|
145
145
|
|
|
146
|
-
### `
|
|
146
|
+
### `betterAuth(auth, opts?)`
|
|
147
147
|
|
|
148
148
|
Creates a middleware function for use with the safe action client's `.use()` method.
|
|
149
149
|
|
|
@@ -158,7 +158,7 @@ Creates a middleware function for use with the safe action client's `.use()` met
|
|
|
158
158
|
|
|
159
159
|
- `BetterAuthContext<Options>`: the context shape added by the middleware (`{ auth: { user, session } }`)
|
|
160
160
|
- `AuthorizeFn<Options, NextCtx>`: the `authorize` callback signature
|
|
161
|
-
- `
|
|
161
|
+
- `BetterAuthOpts<Options, NextCtx>`: the options object type for `betterAuth`
|
|
162
162
|
|
|
163
163
|
## Documentation
|
|
164
164
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Auth, BetterAuthOptions } from "better-auth";
|
|
2
1
|
import { MiddlewareFn, MiddlewareResult } from "next-safe-action";
|
|
2
|
+
import { Auth, BetterAuthOptions } from "better-auth";
|
|
3
3
|
|
|
4
4
|
//#region src/index.types.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* The default context shape added by `
|
|
6
|
+
* The default context shape added by `betterAuth`.
|
|
7
7
|
* Contains `auth.user` and `auth.session`, fully typed from the better-auth instance.
|
|
8
8
|
*/
|
|
9
9
|
type BetterAuthContext<O extends BetterAuthOptions> = {
|
|
@@ -11,21 +11,20 @@ type BetterAuthContext<O extends BetterAuthOptions> = {
|
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* Authorize callback signature for custom authorization logic.
|
|
14
|
-
* Receives the
|
|
14
|
+
* Receives the pre-fetched session data, current context, and the `next` function.
|
|
15
15
|
*/
|
|
16
|
-
type AuthorizeFn<O extends BetterAuthOptions, NC extends object> = (args: {
|
|
17
|
-
auth: Auth<O>;
|
|
16
|
+
type AuthorizeFn<O extends BetterAuthOptions, NC extends object, Ctx extends object = object> = (args: {
|
|
18
17
|
sessionData: Auth<O>["$Infer"]["Session"] | null;
|
|
19
|
-
ctx:
|
|
18
|
+
ctx: Ctx;
|
|
20
19
|
next: <C extends object>(opts?: {
|
|
21
20
|
ctx?: C;
|
|
22
21
|
}) => Promise<MiddlewareResult<any, C>>;
|
|
23
22
|
}) => Promise<MiddlewareResult<any, NC>>;
|
|
24
23
|
/**
|
|
25
|
-
* Options for `
|
|
24
|
+
* Options for `betterAuth`.
|
|
26
25
|
*/
|
|
27
|
-
type
|
|
28
|
-
authorize: AuthorizeFn<O, NC>;
|
|
26
|
+
type BetterAuthOpts<O extends BetterAuthOptions, NC extends object, Ctx extends object = object> = {
|
|
27
|
+
authorize: AuthorizeFn<O, NC, Ctx>;
|
|
29
28
|
};
|
|
30
29
|
//#endregion
|
|
31
30
|
//#region src/index.d.ts
|
|
@@ -43,10 +42,10 @@ type BetterAuthMiddlewareOpts<O extends BetterAuthOptions, NC extends object> =
|
|
|
43
42
|
* @example
|
|
44
43
|
* ```ts
|
|
45
44
|
* // Default: fetch session, unauthorized() if absent
|
|
46
|
-
* actionClient.use(
|
|
45
|
+
* actionClient.use(betterAuth(auth));
|
|
47
46
|
*
|
|
48
47
|
* // Custom: check role
|
|
49
|
-
* actionClient.use(
|
|
48
|
+
* actionClient.use(betterAuth(auth, {
|
|
50
49
|
* authorize: ({ sessionData, next }) => {
|
|
51
50
|
* if (!sessionData || sessionData.user.role !== "admin") {
|
|
52
51
|
* unauthorized();
|
|
@@ -56,8 +55,8 @@ type BetterAuthMiddlewareOpts<O extends BetterAuthOptions, NC extends object> =
|
|
|
56
55
|
* }));
|
|
57
56
|
* ```
|
|
58
57
|
*/
|
|
59
|
-
declare function
|
|
60
|
-
declare function
|
|
58
|
+
declare function betterAuth<O extends BetterAuthOptions>(auth: Auth<O>): MiddlewareFn<any, any, object, BetterAuthContext<O>>;
|
|
59
|
+
declare function betterAuth<O extends BetterAuthOptions, NC extends object, Ctx extends object>(auth: Auth<O>, opts: BetterAuthOpts<O, NC, Ctx>): MiddlewareFn<any, any, Ctx, NC>;
|
|
61
60
|
//#endregion
|
|
62
|
-
export { type AuthorizeFn, type BetterAuthContext, type
|
|
61
|
+
export { type AuthorizeFn, type BetterAuthContext, type BetterAuthOpts, betterAuth };
|
|
63
62
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { createMiddleware } from "next-safe-action";
|
|
1
2
|
import { headers } from "next/headers.js";
|
|
2
3
|
import { unauthorized } from "next/navigation.js";
|
|
3
4
|
//#region src/index.ts
|
|
4
|
-
function
|
|
5
|
-
return async ({ ctx, next }) => {
|
|
5
|
+
function betterAuth(auth, opts) {
|
|
6
|
+
return createMiddleware().define(async ({ ctx, next }) => {
|
|
6
7
|
const sessionData = await auth.api.getSession({ headers: await headers() });
|
|
7
8
|
if (opts?.authorize) return opts.authorize({
|
|
8
|
-
auth,
|
|
9
9
|
sessionData,
|
|
10
10
|
ctx,
|
|
11
11
|
next
|
|
@@ -15,9 +15,9 @@ function betterAuthMiddleware(auth, opts) {
|
|
|
15
15
|
user: sessionData.user,
|
|
16
16
|
session: sessionData.session
|
|
17
17
|
} } });
|
|
18
|
-
};
|
|
18
|
+
});
|
|
19
19
|
}
|
|
20
20
|
//#endregion
|
|
21
|
-
export {
|
|
21
|
+
export { betterAuth };
|
|
22
22
|
|
|
23
23
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Auth, BetterAuthOptions } from \"better-auth\";\nimport type { MiddlewareFn } from \"next-safe-action\";\nimport { headers } from \"next/headers\";\nimport { unauthorized } from \"next/navigation\";\nimport type { BetterAuthContext,
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Auth, BetterAuthOptions } from \"better-auth\";\nimport { createMiddleware } from \"next-safe-action\";\nimport type { MiddlewareFn } from \"next-safe-action\";\nimport { headers } from \"next/headers\";\nimport { unauthorized } from \"next/navigation\";\nimport type { BetterAuthContext, BetterAuthOpts } from \"./index.types\";\n\n/**\n * Creates a next-safe-action middleware that integrates with better-auth.\n *\n * Default behavior: fetches the session via `auth.api.getSession()`, calls `unauthorized()` if\n * no session exists, and injects `{ auth: { user, session } }` into the action context.\n *\n * Pass an `authorize` callback to customize the authorization flow. The session is pre-fetched\n * and passed to the callback, so common customizations (e.g. role checks) don't need to re-fetch.\n *\n * Note: `unauthorized()` requires `experimental.authInterrupts: true` in your `next.config.ts` file.\n *\n * @example\n * ```ts\n * // Default: fetch session, unauthorized() if absent\n * actionClient.use(betterAuth(auth));\n *\n * // Custom: check role\n * actionClient.use(betterAuth(auth, {\n * authorize: ({ sessionData, next }) => {\n * if (!sessionData || sessionData.user.role !== \"admin\") {\n * unauthorized();\n * }\n * return next({ ctx: { auth: sessionData } });\n * },\n * }));\n * ```\n */\nexport function betterAuth<O extends BetterAuthOptions>(\n\tauth: Auth<O>\n): MiddlewareFn<any, any, object, BetterAuthContext<O>>;\nexport function betterAuth<O extends BetterAuthOptions, NC extends object, Ctx extends object>(\n\tauth: Auth<O>,\n\topts: BetterAuthOpts<O, NC, Ctx>\n): MiddlewareFn<any, any, Ctx, NC>;\nexport function betterAuth<O extends BetterAuthOptions>(\n\tauth: Auth<O>,\n\topts?: BetterAuthOpts<O, any, any>\n) {\n\treturn createMiddleware().define(async ({ ctx, next }) => {\n\t\tconst sessionData = await auth.api.getSession({ headers: await headers() });\n\n\t\tif (opts?.authorize) {\n\t\t\treturn opts.authorize({ sessionData, ctx, next });\n\t\t}\n\n\t\tif (!sessionData) {\n\t\t\tunauthorized();\n\t\t}\n\n\t\treturn next({ ctx: { auth: { user: sessionData.user, session: sessionData.session } } });\n\t});\n}\n\nexport type { AuthorizeFn, BetterAuthContext, BetterAuthOpts } from \"./index.types\";\n"],"mappings":";;;;AAyCA,SAAgB,WACf,MACA,MACC;AACD,QAAO,kBAAkB,CAAC,OAAO,OAAO,EAAE,KAAK,WAAW;EACzD,MAAM,cAAc,MAAM,KAAK,IAAI,WAAW,EAAE,SAAS,MAAM,SAAS,EAAE,CAAC;AAE3E,MAAI,MAAM,UACT,QAAO,KAAK,UAAU;GAAE;GAAa;GAAK;GAAM,CAAC;AAGlD,MAAI,CAAC,YACJ,eAAc;AAGf,SAAO,KAAK,EAAE,KAAK,EAAE,MAAM;GAAE,MAAM,YAAY;GAAM,SAAS,YAAY;GAAS,EAAE,EAAE,CAAC;GACvF"}
|