@beignet/provider-auth-better-auth 0.0.42 → 0.0.44

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @beignet/provider-auth-better-auth
2
2
 
3
+ ## 0.0.44
4
+
5
+ ## 0.0.43
6
+
7
+ ### Patch Changes
8
+
9
+ - 19b9c52: Add a direct Better Auth port adapter and use typed object options for provider setup.
10
+
3
11
  ## 0.0.42
4
12
 
5
13
  ## 0.0.41
package/README.md CHANGED
@@ -17,6 +17,7 @@ schema, and auth routes.
17
17
 
18
18
  - Wraps a Better Auth instance with a simple, stable API
19
19
  - Extends `ports.auth` with `getSession`, `getUser`, and `requireUser` methods
20
+ - Exposes a direct port adapter for custom app wiring
20
21
  - Maintains type safety for your custom User type
21
22
  - Records auth checks in devtools when devtools is installed
22
23
 
@@ -117,7 +118,7 @@ import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
117
118
  import { auth } from "@/lib/better-auth";
118
119
 
119
120
  export const providers = [
120
- createBetterAuthProvider(auth),
121
+ createBetterAuthProvider({ auth }),
121
122
  // ...other providers
122
123
  ];
123
124
  ```
@@ -386,21 +387,53 @@ interface AuthSession<User = unknown, Session = unknown> {
386
387
  }
387
388
  ```
388
389
 
389
- ### `createBetterAuthProvider(auth)`
390
+ ### `createBetterAuthProvider({ auth })`
390
391
 
391
392
  Factory function that creates the provider:
392
393
 
393
394
  ```ts
394
395
  function createBetterAuthProvider<User = unknown, Session = unknown>(
395
- auth: BetterAuthServer<User, Session>
396
- ): ServiceProvider
396
+ options: CreateBetterAuthProviderOptions<User, Session>
397
+ ): BetterAuthProvider<User, Session>
397
398
  ```
398
399
 
399
400
  **Parameters:**
400
- - `auth`: A Better Auth server instance configured in your application
401
+ - `options.auth`: A Better Auth server instance configured in your application
401
402
 
402
403
  **Returns:** A Beignet provider that can be registered with the server
403
404
 
405
+ ### `createBetterAuthPort({ auth, instrumentation? })`
406
+
407
+ Create the shared `AuthPort` directly when an app needs custom provider setup
408
+ around its Better Auth instance:
409
+
410
+ ```ts
411
+ // server/providers.ts
412
+ import { createProvider } from "@beignet/core/providers";
413
+ import { createBetterAuthPort } from "@beignet/provider-auth-better-auth";
414
+ import { auth } from "@/lib/better-auth";
415
+
416
+ export const appAuthProvider = createProvider({
417
+ name: "app-auth",
418
+ setup({ ports }) {
419
+ return {
420
+ ports: {
421
+ auth: createBetterAuthPort({ auth, instrumentation: ports }),
422
+ },
423
+ };
424
+ },
425
+ });
426
+
427
+ export const providers = [appAuthProvider] as const;
428
+ ```
429
+
430
+ Define and register `appAuthProvider` in `server/providers.ts`, where provider
431
+ audit can recognize the lower-level adapter as valid registration, and keep
432
+ `auth` deferred in `infra/port-wiring.ts`. Outside lifecycle provider wiring,
433
+ pass a Beignet provider instrumentation target explicitly when the adapter
434
+ should emit the same redacted auth events. The adapter does not own or stop the
435
+ Better Auth instance.
436
+
404
437
  ## Advanced usage
405
438
 
406
439
  ### Route-scoped authentication
@@ -462,8 +495,8 @@ export const requireAuth = async (
462
495
  Configure multiple strategies through Better Auth when its plugins cover the
463
496
  required session, bearer, or API-key behavior. When an app needs authentication
464
497
  outside Better Auth, compose that logic in an app-owned `AuthPort` adapter or
465
- HTTP auth hook; this package intentionally exports only the Better Auth
466
- provider.
498
+ HTTP auth hook. Use `createBetterAuthPort(...)` when the app needs direct
499
+ wiring for its existing Better Auth instance.
467
500
 
468
501
  ## Type safety
469
502
 
@@ -476,7 +509,7 @@ type MyUser = {
476
509
  role: "admin" | "user";
477
510
  };
478
511
 
479
- const authProvider = createBetterAuthProvider<MyUser>(auth);
512
+ const authProvider = createBetterAuthProvider<MyUser>({ auth });
480
513
 
481
514
  // Later, in your routes:
482
515
  const user = await ctx.ports.auth.requireUser(req);
@@ -544,7 +577,7 @@ const auth = betterAuth({ database: db });
544
577
 
545
578
  const server = await createNextServer({
546
579
  ports: initialPorts,
547
- providers: [createBetterAuthProvider(auth)],
580
+ providers: [createBetterAuthProvider({ auth })],
548
581
  context: appContext,
549
582
  routes,
550
583
  });
@@ -568,7 +601,7 @@ const authHook = {
568
601
 
569
602
  const server = await createNextServer({
570
603
  ports: initialPorts,
571
- providers: [createBetterAuthProvider(auth)],
604
+ providers: [createBetterAuthProvider({ auth })],
572
605
  hooks: [authHook],
573
606
  context: appContext,
574
607
  routes,
package/dist/index.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * @beignet/provider-auth-better-auth
3
3
  *
4
- * Better Auth provider that extends ports with authentication capabilities.
5
- * This provider wraps an already-configured Better Auth server instance
6
- * and exposes the shared Beignet AuthPort on ctx.ports.auth.
4
+ * Better Auth adapters for Beignet's shared authentication port.
7
5
  *
8
6
  * The provider does NOT own:
9
7
  * - Database schema
@@ -15,60 +13,20 @@
15
13
  *
16
14
  * @example
17
15
  * ```ts
18
- * // 1. Configure Better Auth in your app
16
+ * // Configure Better Auth in your app.
19
17
  * import { betterAuth } from "better-auth";
18
+ * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
20
19
  * import { db } from "./db";
21
20
  *
22
21
  * export const auth = betterAuth({
23
22
  * database: db,
24
- * // ...other Better Auth config
25
- * });
26
- *
27
- * // Own this shape in your app instead of exporting provider-inferred types.
28
- * export type AuthUser = {
29
- * id: string;
30
- * name?: string | null;
31
- * email?: string | null;
32
- * image?: string | null;
33
- * };
34
- *
35
- * // 2. Define your ports type
36
- * import type { AuthPort } from "@beignet/core/ports";
37
- *
38
- * export type AppPorts = {
39
- * auth: AuthPort<AuthUser>;
40
- * // ...other ports
41
- * };
42
- *
43
- * // 3. Wire the provider into Beignet
44
- * import { createNextServer } from "@beignet/next";
45
- * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
46
- *
47
- * const server = await createNextServer({
48
- * ports: basePorts,
49
- * providers: [
50
- * createBetterAuthProvider(auth),
51
- * // ...other providers
52
- * ],
53
- * });
54
- *
55
- * // 4. Use the auth port through route-scoped auth hooks
56
- * import { createAuthHooks } from "@beignet/core/server";
57
- *
58
- * const auth = createAuthHooks<AppContext>()({
59
- * resolve: ({ ctx }) => {
60
- * return ctx.auth ? { user: ctx.auth.user } : null;
61
- * },
62
23
  * });
63
24
  *
64
- * const server = await createNextServer({
65
- * ports: basePorts,
66
- * providers: [createBetterAuthProvider(auth)],
67
- * context: async ({ ports }) => ({ ports }),
68
- * });
25
+ * export const authProvider = createBetterAuthProvider({ auth });
69
26
  * ```
70
27
  */
71
- import { type AuthPort, type AuthRequestLike } from "@beignet/core/ports";
28
+ import { type AuthPort } from "@beignet/core/ports";
29
+ import { type AnyProviderConfigSchema, type ProviderInstrumentationTarget, type ServiceProvider } from "@beignet/core/providers";
72
30
  /**
73
31
  * Minimal type representing a Better Auth server instance.
74
32
  * This is the interface we expect from the Better Auth library.
@@ -96,32 +54,59 @@ export type BetterAuthServer<User = unknown, Session = unknown> = {
96
54
  };
97
55
  };
98
56
  /**
99
- * Create a Beignet provider for Better Auth.
100
- *
101
- * This factory accepts an already-configured Better Auth server instance
102
- * and returns a provider that can be registered with Beignet.
103
- *
104
- * The provider extends ports.auth with an AuthPort that wraps the
105
- * Better Auth instance with a simple, stable API.
57
+ * Options for adapting an existing Better Auth server to Beignet's auth port.
58
+ */
59
+ export interface CreateBetterAuthPortOptions<User = unknown, Session = unknown> {
60
+ /**
61
+ * Better Auth server instance configured and owned by the application.
62
+ */
63
+ auth: BetterAuthServer<User, Session>;
64
+ /**
65
+ * Optional provider instrumentation target.
66
+ */
67
+ instrumentation?: ProviderInstrumentationTarget;
68
+ }
69
+ /**
70
+ * Options for installing an existing Better Auth server as a Beignet provider.
71
+ */
72
+ export interface CreateBetterAuthProviderOptions<User = unknown, Session = unknown> {
73
+ /**
74
+ * Better Auth server instance configured and owned by the application.
75
+ */
76
+ auth: BetterAuthServer<User, Session>;
77
+ }
78
+ /**
79
+ * Ports contributed by `createBetterAuthProvider`.
80
+ */
81
+ export interface BetterAuthProviderPorts<User = unknown, Session = unknown> {
82
+ /**
83
+ * Beignet auth port backed by Better Auth.
84
+ */
85
+ auth: AuthPort<User, Session>;
86
+ }
87
+ /**
88
+ * Better Auth lifecycle provider with stable contributed-port typing.
89
+ */
90
+ export type BetterAuthProvider<User = unknown, Session = unknown> = ServiceProvider<unknown, AnyProviderConfigSchema<void>, Pick<BetterAuthProviderPorts<User, Session>, keyof BetterAuthProviderPorts<User, Session>>>;
91
+ /**
92
+ * Create a Beignet auth port backed by an existing Better Auth server.
106
93
  *
107
- * @param auth - A Better Auth server instance configured in the application
108
- * @returns A Beignet provider that extends ports.auth
94
+ * Use this for custom app wiring. The adapter does not own the Better Auth
95
+ * instance or add lifecycle hooks.
96
+ */
97
+ export declare function createBetterAuthPort<User = unknown, Session = unknown>({ auth, instrumentation: instrumentationTarget, }: CreateBetterAuthPortOptions<User, Session>): AuthPort<User, Session>;
98
+ /**
99
+ * Create a Beignet provider for an existing Better Auth server.
109
100
  *
110
101
  * @example
111
102
  * ```ts
112
103
  * import { betterAuth } from "better-auth";
113
104
  * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
114
- * import { createNextServer } from "@beignet/next";
105
+ * import { db } from "./db";
115
106
  *
116
107
  * const auth = betterAuth({ database: db });
117
- *
118
- * const server = await createNextServer({
119
- * ports: basePorts,
120
- * providers: [createBetterAuthProvider(auth)],
121
- * });
108
+ * const provider = createBetterAuthProvider({ auth });
122
109
  * ```
123
110
  */
124
- export declare function createBetterAuthProvider<User = unknown, Session = unknown>(auth: BetterAuthServer<User, Session>): import("@beignet/core/providers").ServiceProvider<unknown, import("@standard-schema/spec").StandardSchemaV1<void, void>, {
125
- auth: AuthPort<User, Session, AuthRequestLike>;
126
- }, unknown, void>;
111
+ export declare function createBetterAuthProvider<User = unknown, Session = unknown>({ auth, }: CreateBetterAuthProviderOptions<User, Session>): BetterAuthProvider<User, Session>;
127
112
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAEH,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,qBAAqB,CAAC;AAM7B;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IAChE;;;OAGG;IACH,GAAG,EAAE;QACH;;;;WAIG;QACH,UAAU,CAAC,OAAO,EAAE;YAClB,OAAO,EAAE,OAAO,CAAC;SAClB,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,IAAI,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;KACtD,CAAC;CACH,CAAC;AAMF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACxE,IAAI,EAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC;;kBAsItC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EACL,KAAK,QAAQ,EAGd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,uBAAuB,EAG5B,KAAK,6BAA6B,EAClC,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IAChE;;;OAGG;IACH,GAAG,EAAE;QACH;;;;WAIG;QACH,UAAU,CAAC,OAAO,EAAE;YAClB,OAAO,EAAE,OAAO,CAAC;SAClB,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,IAAI,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;KACtD,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,2BAA2B,CAC1C,IAAI,GAAG,OAAO,EACd,OAAO,GAAG,OAAO;IAEjB;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC;;OAEG;IACH,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,+BAA+B,CAC9C,IAAI,GAAG,OAAO,EACd,OAAO,GAAG,OAAO;IAEjB;;OAEG;IACH,IAAI,EAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IACxE;;OAEG;IACH,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAC5B,IAAI,GAAG,OAAO,EACd,OAAO,GAAG,OAAO,IACf,eAAe,CACjB,OAAO,EACP,uBAAuB,CAAC,IAAI,CAAC,EAC7B,IAAI,CACF,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,EACtC,MAAM,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,CAC7C,CACF,CAAC;AAMF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EACtE,IAAI,EACJ,eAAe,EAAE,qBAAqB,GACvC,EAAE,2BAA2B,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CA6HtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EAC1E,IAAI,GACL,EAAE,+BAA+B,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,kBAAkB,CACpE,IAAI,EACJ,OAAO,CACR,CAiBA"}
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * @beignet/provider-auth-better-auth
3
3
  *
4
- * Better Auth provider that extends ports with authentication capabilities.
5
- * This provider wraps an already-configured Better Auth server instance
6
- * and exposes the shared Beignet AuthPort on ctx.ports.auth.
4
+ * Better Auth adapters for Beignet's shared authentication port.
7
5
  *
8
6
  * The provider does NOT own:
9
7
  * - Database schema
@@ -15,57 +13,16 @@
15
13
  *
16
14
  * @example
17
15
  * ```ts
18
- * // 1. Configure Better Auth in your app
16
+ * // Configure Better Auth in your app.
19
17
  * import { betterAuth } from "better-auth";
18
+ * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
20
19
  * import { db } from "./db";
21
20
  *
22
21
  * export const auth = betterAuth({
23
22
  * database: db,
24
- * // ...other Better Auth config
25
- * });
26
- *
27
- * // Own this shape in your app instead of exporting provider-inferred types.
28
- * export type AuthUser = {
29
- * id: string;
30
- * name?: string | null;
31
- * email?: string | null;
32
- * image?: string | null;
33
- * };
34
- *
35
- * // 2. Define your ports type
36
- * import type { AuthPort } from "@beignet/core/ports";
37
- *
38
- * export type AppPorts = {
39
- * auth: AuthPort<AuthUser>;
40
- * // ...other ports
41
- * };
42
- *
43
- * // 3. Wire the provider into Beignet
44
- * import { createNextServer } from "@beignet/next";
45
- * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
46
- *
47
- * const server = await createNextServer({
48
- * ports: basePorts,
49
- * providers: [
50
- * createBetterAuthProvider(auth),
51
- * // ...other providers
52
- * ],
53
- * });
54
- *
55
- * // 4. Use the auth port through route-scoped auth hooks
56
- * import { createAuthHooks } from "@beignet/core/server";
57
- *
58
- * const auth = createAuthHooks<AppContext>()({
59
- * resolve: ({ ctx }) => {
60
- * return ctx.auth ? { user: ctx.auth.user } : null;
61
- * },
62
23
  * });
63
24
  *
64
- * const server = await createNextServer({
65
- * ports: basePorts,
66
- * providers: [createBetterAuthProvider(auth)],
67
- * context: async ({ ports }) => ({ ports }),
68
- * });
25
+ * export const authProvider = createBetterAuthProvider({ auth });
69
26
  * ```
70
27
  */
71
28
  import { AuthUnauthorizedError, } from "@beignet/core/ports";
@@ -74,148 +31,152 @@ function errorMessage(error) {
74
31
  return error instanceof Error ? error.message : String(error);
75
32
  }
76
33
  /**
77
- * Create a Beignet provider for Better Auth.
34
+ * Create a Beignet auth port backed by an existing Better Auth server.
78
35
  *
79
- * This factory accepts an already-configured Better Auth server instance
80
- * and returns a provider that can be registered with Beignet.
81
- *
82
- * The provider extends ports.auth with an AuthPort that wraps the
83
- * Better Auth instance with a simple, stable API.
84
- *
85
- * @param auth - A Better Auth server instance configured in the application
86
- * @returns A Beignet provider that extends ports.auth
36
+ * Use this for custom app wiring. The adapter does not own the Better Auth
37
+ * instance or add lifecycle hooks.
38
+ */
39
+ export function createBetterAuthPort({ auth, instrumentation: instrumentationTarget, }) {
40
+ const instrumentation = createProviderInstrumentation(instrumentationTarget, {
41
+ providerName: "auth-better-auth",
42
+ watcher: "auth",
43
+ });
44
+ async function resolveSession(req) {
45
+ const session = await auth.api.getSession({
46
+ headers: req.headers,
47
+ });
48
+ if (!session) {
49
+ return null;
50
+ }
51
+ return {
52
+ user: session.user,
53
+ session: session.session,
54
+ };
55
+ }
56
+ function recordAuthEvent(event) {
57
+ instrumentation.custom({
58
+ name: `auth.${event.operation}`,
59
+ label: `Auth ${event.operation}`,
60
+ summary: event.summary,
61
+ details: {
62
+ operation: event.operation,
63
+ authenticated: event.authenticated,
64
+ durationMs: event.durationMs,
65
+ ...(event.error ? { error: event.error } : {}),
66
+ },
67
+ });
68
+ }
69
+ return {
70
+ async getSession(req) {
71
+ const startedAt = Date.now();
72
+ try {
73
+ const session = await resolveSession(req);
74
+ recordAuthEvent({
75
+ operation: "getSession",
76
+ authenticated: session != null,
77
+ summary: session ? "Session found" : "No session",
78
+ durationMs: Date.now() - startedAt,
79
+ });
80
+ return session;
81
+ }
82
+ catch (error) {
83
+ recordAuthEvent({
84
+ operation: "getSession.failed",
85
+ authenticated: false,
86
+ summary: "Session lookup failed",
87
+ durationMs: Date.now() - startedAt,
88
+ error: errorMessage(error),
89
+ });
90
+ throw error;
91
+ }
92
+ },
93
+ async getUser(req) {
94
+ const startedAt = Date.now();
95
+ try {
96
+ const session = await resolveSession(req);
97
+ recordAuthEvent({
98
+ operation: "getUser",
99
+ authenticated: session != null,
100
+ summary: session ? "User found" : "No user",
101
+ durationMs: Date.now() - startedAt,
102
+ });
103
+ return session?.user ?? null;
104
+ }
105
+ catch (error) {
106
+ recordAuthEvent({
107
+ operation: "getUser.failed",
108
+ authenticated: false,
109
+ summary: "User lookup failed",
110
+ durationMs: Date.now() - startedAt,
111
+ error: errorMessage(error),
112
+ });
113
+ throw error;
114
+ }
115
+ },
116
+ async requireUser(req) {
117
+ const startedAt = Date.now();
118
+ try {
119
+ const session = await resolveSession(req);
120
+ if (!session) {
121
+ recordAuthEvent({
122
+ operation: "requireUser",
123
+ authenticated: false,
124
+ summary: "Unauthorized",
125
+ durationMs: Date.now() - startedAt,
126
+ });
127
+ throw new AuthUnauthorizedError();
128
+ }
129
+ recordAuthEvent({
130
+ operation: "requireUser",
131
+ authenticated: true,
132
+ summary: "Authorized",
133
+ durationMs: Date.now() - startedAt,
134
+ });
135
+ return session.user;
136
+ }
137
+ catch (error) {
138
+ if (error instanceof AuthUnauthorizedError) {
139
+ throw error;
140
+ }
141
+ recordAuthEvent({
142
+ operation: "requireUser.failed",
143
+ authenticated: false,
144
+ summary: "Required user lookup failed",
145
+ durationMs: Date.now() - startedAt,
146
+ error: errorMessage(error),
147
+ });
148
+ throw error;
149
+ }
150
+ },
151
+ };
152
+ }
153
+ /**
154
+ * Create a Beignet provider for an existing Better Auth server.
87
155
  *
88
156
  * @example
89
157
  * ```ts
90
158
  * import { betterAuth } from "better-auth";
91
159
  * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
92
- * import { createNextServer } from "@beignet/next";
160
+ * import { db } from "./db";
93
161
  *
94
162
  * const auth = betterAuth({ database: db });
95
- *
96
- * const server = await createNextServer({
97
- * ports: basePorts,
98
- * providers: [createBetterAuthProvider(auth)],
99
- * });
163
+ * const provider = createBetterAuthProvider({ auth });
100
164
  * ```
101
165
  */
102
- export function createBetterAuthProvider(auth) {
166
+ export function createBetterAuthProvider({ auth, }) {
103
167
  return createProvider({
104
168
  name: "auth-better-auth",
169
+ metadata: {
170
+ packageName: "@beignet/provider-auth-better-auth",
171
+ ports: ["auth"],
172
+ watchers: ["auth"],
173
+ },
105
174
  async setup({ ports }) {
106
- const instrumentation = createProviderInstrumentation(ports, {
107
- providerName: "auth-better-auth",
108
- watcher: "auth",
109
- });
110
- async function resolveSession(req) {
111
- const session = await auth.api.getSession({
112
- headers: req.headers,
113
- });
114
- if (!session) {
115
- return null;
116
- }
117
- return {
118
- user: session.user,
119
- session: session.session,
120
- };
121
- }
122
- function recordAuthEvent(event) {
123
- instrumentation.custom({
124
- name: `auth.${event.operation}`,
125
- label: `Auth ${event.operation}`,
126
- summary: event.summary,
127
- details: {
128
- operation: event.operation,
129
- authenticated: event.authenticated,
130
- durationMs: event.durationMs,
131
- ...(event.error ? { error: event.error } : {}),
132
- },
133
- });
134
- }
135
- const authPort = {
136
- async getSession(req) {
137
- const startedAt = Date.now();
138
- try {
139
- const session = await resolveSession(req);
140
- recordAuthEvent({
141
- operation: "getSession",
142
- authenticated: session != null,
143
- summary: session ? "Session found" : "No session",
144
- durationMs: Date.now() - startedAt,
145
- });
146
- return session;
147
- }
148
- catch (error) {
149
- recordAuthEvent({
150
- operation: "getSession.failed",
151
- authenticated: false,
152
- summary: "Session lookup failed",
153
- durationMs: Date.now() - startedAt,
154
- error: errorMessage(error),
155
- });
156
- throw error;
157
- }
158
- },
159
- async getUser(req) {
160
- const startedAt = Date.now();
161
- try {
162
- const session = await resolveSession(req);
163
- recordAuthEvent({
164
- operation: "getUser",
165
- authenticated: session != null,
166
- summary: session ? "User found" : "No user",
167
- durationMs: Date.now() - startedAt,
168
- });
169
- return session?.user ?? null;
170
- }
171
- catch (error) {
172
- recordAuthEvent({
173
- operation: "getUser.failed",
174
- authenticated: false,
175
- summary: "User lookup failed",
176
- durationMs: Date.now() - startedAt,
177
- error: errorMessage(error),
178
- });
179
- throw error;
180
- }
181
- },
182
- async requireUser(req) {
183
- const startedAt = Date.now();
184
- try {
185
- const session = await resolveSession(req);
186
- if (!session) {
187
- recordAuthEvent({
188
- operation: "requireUser",
189
- authenticated: false,
190
- summary: "Unauthorized",
191
- durationMs: Date.now() - startedAt,
192
- });
193
- throw new AuthUnauthorizedError();
194
- }
195
- recordAuthEvent({
196
- operation: "requireUser",
197
- authenticated: true,
198
- summary: "Authorized",
199
- durationMs: Date.now() - startedAt,
200
- });
201
- return session.user;
202
- }
203
- catch (error) {
204
- if (error instanceof AuthUnauthorizedError) {
205
- throw error;
206
- }
207
- recordAuthEvent({
208
- operation: "requireUser.failed",
209
- authenticated: false,
210
- summary: "Required user lookup failed",
211
- durationMs: Date.now() - startedAt,
212
- error: errorMessage(error),
213
- });
214
- throw error;
215
- }
175
+ return {
176
+ ports: {
177
+ auth: createBetterAuthPort({ auth, instrumentation: ports }),
216
178
  },
217
179
  };
218
- return { ports: { auth: authPort } };
219
180
  },
220
181
  });
221
182
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beignet/provider-auth-better-auth",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "type": "module",
5
5
  "description": "Better Auth provider for Beignet - adds auth port for authentication and session management",
6
6
  "main": "./dist/index.js",
@@ -86,7 +86,8 @@
86
86
  "registration": {
87
87
  "required": true,
88
88
  "tokens": [
89
- "createBetterAuthProvider"
89
+ "createBetterAuthProvider",
90
+ "createBetterAuthPort"
90
91
  ]
91
92
  }
92
93
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: auth-provider
3
- description: "Wire Beignet Better Auth integration with @beignet/provider-auth-better-auth: app-owned Better Auth config, auth routes, AuthPort typing, deferred auth port registration, server context, createAuthHooks, requireUser helpers, policies, devtools auth instrumentation, tests, and doctor drift. Use when adding, fixing, or reviewing Better Auth provider setup in a Beignet app."
3
+ description: "Wire Beignet Better Auth integration with @beignet/provider-auth-better-auth: app-owned Better Auth config, createBetterAuthProvider and createBetterAuthPort wiring, auth routes, AuthPort typing, server context, createAuthHooks, requireUser helpers, policies, devtools auth instrumentation, tests, and doctor drift. Use when adding, fixing, or reviewing Better Auth setup in a Beignet app."
4
4
  ---
5
5
 
6
6
  # Beignet Better Auth Provider
@@ -35,11 +35,39 @@ Create Better Auth in an app-local module, then register the provider in
35
35
  import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
36
36
  import { auth } from "@/lib/better-auth";
37
37
 
38
- export const providers = [createBetterAuthProvider(auth)] as const;
38
+ export const providers = [createBetterAuthProvider({ auth })] as const;
39
39
  ```
40
40
 
41
- Add `auth` to `definePorts(...)` as a deferred port because the provider
42
- contributes it at startup.
41
+ For custom provider setup, adapt the same caller-owned instance inside an
42
+ app-local provider:
43
+
44
+ ```ts
45
+ // server/providers.ts
46
+ import { createProvider } from "@beignet/core/providers";
47
+ import { createBetterAuthPort } from "@beignet/provider-auth-better-auth";
48
+ import { auth } from "@/lib/better-auth";
49
+
50
+ export const appAuthProvider = createProvider({
51
+ name: "app-auth",
52
+ setup({ ports }) {
53
+ return {
54
+ ports: {
55
+ auth: createBetterAuthPort({ auth, instrumentation: ports }),
56
+ },
57
+ };
58
+ },
59
+ });
60
+
61
+ export const providers = [appAuthProvider] as const;
62
+ ```
63
+
64
+ Keep `appAuthProvider` in `server/providers.ts` and register it in that file's
65
+ exported provider list. Provider audit recognizes the direct-adapter token, and
66
+ `auth` remains deferred because the app-local provider contributes it during
67
+ startup. Neither factory owns or closes `auth`.
68
+
69
+ Add `auth` to `definePorts(...)` as a deferred port when either the convenience
70
+ provider or the app-local provider contributes it at startup.
43
71
 
44
72
  ```ts
45
73
  export const initialPorts = definePorts<AppPorts>()({
package/src/index.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * @beignet/provider-auth-better-auth
3
3
  *
4
- * Better Auth provider that extends ports with authentication capabilities.
5
- * This provider wraps an already-configured Better Auth server instance
6
- * and exposes the shared Beignet AuthPort on ctx.ports.auth.
4
+ * Better Auth adapters for Beignet's shared authentication port.
7
5
  *
8
6
  * The provider does NOT own:
9
7
  * - Database schema
@@ -15,57 +13,16 @@
15
13
  *
16
14
  * @example
17
15
  * ```ts
18
- * // 1. Configure Better Auth in your app
16
+ * // Configure Better Auth in your app.
19
17
  * import { betterAuth } from "better-auth";
18
+ * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
20
19
  * import { db } from "./db";
21
20
  *
22
21
  * export const auth = betterAuth({
23
22
  * database: db,
24
- * // ...other Better Auth config
25
- * });
26
- *
27
- * // Own this shape in your app instead of exporting provider-inferred types.
28
- * export type AuthUser = {
29
- * id: string;
30
- * name?: string | null;
31
- * email?: string | null;
32
- * image?: string | null;
33
- * };
34
- *
35
- * // 2. Define your ports type
36
- * import type { AuthPort } from "@beignet/core/ports";
37
- *
38
- * export type AppPorts = {
39
- * auth: AuthPort<AuthUser>;
40
- * // ...other ports
41
- * };
42
- *
43
- * // 3. Wire the provider into Beignet
44
- * import { createNextServer } from "@beignet/next";
45
- * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
46
- *
47
- * const server = await createNextServer({
48
- * ports: basePorts,
49
- * providers: [
50
- * createBetterAuthProvider(auth),
51
- * // ...other providers
52
- * ],
53
- * });
54
- *
55
- * // 4. Use the auth port through route-scoped auth hooks
56
- * import { createAuthHooks } from "@beignet/core/server";
57
- *
58
- * const auth = createAuthHooks<AppContext>()({
59
- * resolve: ({ ctx }) => {
60
- * return ctx.auth ? { user: ctx.auth.user } : null;
61
- * },
62
23
  * });
63
24
  *
64
- * const server = await createNextServer({
65
- * ports: basePorts,
66
- * providers: [createBetterAuthProvider(auth)],
67
- * context: async ({ ports }) => ({ ports }),
68
- * });
25
+ * export const authProvider = createBetterAuthProvider({ auth });
69
26
  * ```
70
27
  */
71
28
 
@@ -75,8 +32,11 @@ import {
75
32
  AuthUnauthorizedError,
76
33
  } from "@beignet/core/ports";
77
34
  import {
35
+ type AnyProviderConfigSchema,
78
36
  createProvider,
79
37
  createProviderInstrumentation,
38
+ type ProviderInstrumentationTarget,
39
+ type ServiceProvider,
80
40
  } from "@beignet/core/providers";
81
41
 
82
42
  /**
@@ -103,169 +63,234 @@ export type BetterAuthServer<User = unknown, Session = unknown> = {
103
63
  };
104
64
  };
105
65
 
66
+ /**
67
+ * Options for adapting an existing Better Auth server to Beignet's auth port.
68
+ */
69
+ export interface CreateBetterAuthPortOptions<
70
+ User = unknown,
71
+ Session = unknown,
72
+ > {
73
+ /**
74
+ * Better Auth server instance configured and owned by the application.
75
+ */
76
+ auth: BetterAuthServer<User, Session>;
77
+ /**
78
+ * Optional provider instrumentation target.
79
+ */
80
+ instrumentation?: ProviderInstrumentationTarget;
81
+ }
82
+
83
+ /**
84
+ * Options for installing an existing Better Auth server as a Beignet provider.
85
+ */
86
+ export interface CreateBetterAuthProviderOptions<
87
+ User = unknown,
88
+ Session = unknown,
89
+ > {
90
+ /**
91
+ * Better Auth server instance configured and owned by the application.
92
+ */
93
+ auth: BetterAuthServer<User, Session>;
94
+ }
95
+
96
+ /**
97
+ * Ports contributed by `createBetterAuthProvider`.
98
+ */
99
+ export interface BetterAuthProviderPorts<User = unknown, Session = unknown> {
100
+ /**
101
+ * Beignet auth port backed by Better Auth.
102
+ */
103
+ auth: AuthPort<User, Session>;
104
+ }
105
+
106
+ /**
107
+ * Better Auth lifecycle provider with stable contributed-port typing.
108
+ */
109
+ export type BetterAuthProvider<
110
+ User = unknown,
111
+ Session = unknown,
112
+ > = ServiceProvider<
113
+ unknown,
114
+ AnyProviderConfigSchema<void>,
115
+ Pick<
116
+ BetterAuthProviderPorts<User, Session>,
117
+ keyof BetterAuthProviderPorts<User, Session>
118
+ >
119
+ >;
120
+
106
121
  function errorMessage(error: unknown): string {
107
122
  return error instanceof Error ? error.message : String(error);
108
123
  }
109
124
 
110
125
  /**
111
- * Create a Beignet provider for Better Auth.
112
- *
113
- * This factory accepts an already-configured Better Auth server instance
114
- * and returns a provider that can be registered with Beignet.
115
- *
116
- * The provider extends ports.auth with an AuthPort that wraps the
117
- * Better Auth instance with a simple, stable API.
118
- *
119
- * @param auth - A Better Auth server instance configured in the application
120
- * @returns A Beignet provider that extends ports.auth
121
- *
122
- * @example
123
- * ```ts
124
- * import { betterAuth } from "better-auth";
125
- * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
126
- * import { createNextServer } from "@beignet/next";
126
+ * Create a Beignet auth port backed by an existing Better Auth server.
127
127
  *
128
- * const auth = betterAuth({ database: db });
129
- *
130
- * const server = await createNextServer({
131
- * ports: basePorts,
132
- * providers: [createBetterAuthProvider(auth)],
133
- * });
134
- * ```
128
+ * Use this for custom app wiring. The adapter does not own the Better Auth
129
+ * instance or add lifecycle hooks.
135
130
  */
136
- export function createBetterAuthProvider<User = unknown, Session = unknown>(
137
- auth: BetterAuthServer<User, Session>,
138
- ) {
139
- return createProvider({
140
- name: "auth-better-auth",
131
+ export function createBetterAuthPort<User = unknown, Session = unknown>({
132
+ auth,
133
+ instrumentation: instrumentationTarget,
134
+ }: CreateBetterAuthPortOptions<User, Session>): AuthPort<User, Session> {
135
+ const instrumentation = createProviderInstrumentation(instrumentationTarget, {
136
+ providerName: "auth-better-auth",
137
+ watcher: "auth",
138
+ });
141
139
 
142
- async setup({ ports }) {
143
- const instrumentation = createProviderInstrumentation(ports, {
144
- providerName: "auth-better-auth",
145
- watcher: "auth",
146
- });
140
+ async function resolveSession(req: AuthRequestLike) {
141
+ const session = await auth.api.getSession({
142
+ headers: req.headers,
143
+ });
144
+ if (!session) {
145
+ return null;
146
+ }
147
+
148
+ return {
149
+ user: session.user,
150
+ session: session.session,
151
+ };
152
+ }
147
153
 
148
- async function resolveSession(req: AuthRequestLike) {
149
- const session = await auth.api.getSession({
150
- headers: req.headers,
154
+ function recordAuthEvent(event: {
155
+ operation: string;
156
+ authenticated: boolean;
157
+ summary: string;
158
+ durationMs: number;
159
+ error?: string;
160
+ }) {
161
+ instrumentation.custom({
162
+ name: `auth.${event.operation}`,
163
+ label: `Auth ${event.operation}`,
164
+ summary: event.summary,
165
+ details: {
166
+ operation: event.operation,
167
+ authenticated: event.authenticated,
168
+ durationMs: event.durationMs,
169
+ ...(event.error ? { error: event.error } : {}),
170
+ },
171
+ });
172
+ }
173
+
174
+ return {
175
+ async getSession(req) {
176
+ const startedAt = Date.now();
177
+ try {
178
+ const session = await resolveSession(req);
179
+ recordAuthEvent({
180
+ operation: "getSession",
181
+ authenticated: session != null,
182
+ summary: session ? "Session found" : "No session",
183
+ durationMs: Date.now() - startedAt,
151
184
  });
152
- if (!session) {
153
- return null;
154
- }
155
185
 
156
- return {
157
- user: session.user,
158
- session: session.session,
159
- };
186
+ return session;
187
+ } catch (error) {
188
+ recordAuthEvent({
189
+ operation: "getSession.failed",
190
+ authenticated: false,
191
+ summary: "Session lookup failed",
192
+ durationMs: Date.now() - startedAt,
193
+ error: errorMessage(error),
194
+ });
195
+ throw error;
160
196
  }
197
+ },
161
198
 
162
- function recordAuthEvent(event: {
163
- operation: string;
164
- authenticated: boolean;
165
- summary: string;
166
- durationMs: number;
167
- error?: string;
168
- }) {
169
- instrumentation.custom({
170
- name: `auth.${event.operation}`,
171
- label: `Auth ${event.operation}`,
172
- summary: event.summary,
173
- details: {
174
- operation: event.operation,
175
- authenticated: event.authenticated,
176
- durationMs: event.durationMs,
177
- ...(event.error ? { error: event.error } : {}),
178
- },
199
+ async getUser(req) {
200
+ const startedAt = Date.now();
201
+ try {
202
+ const session = await resolveSession(req);
203
+ recordAuthEvent({
204
+ operation: "getUser",
205
+ authenticated: session != null,
206
+ summary: session ? "User found" : "No user",
207
+ durationMs: Date.now() - startedAt,
179
208
  });
209
+ return session?.user ?? null;
210
+ } catch (error) {
211
+ recordAuthEvent({
212
+ operation: "getUser.failed",
213
+ authenticated: false,
214
+ summary: "User lookup failed",
215
+ durationMs: Date.now() - startedAt,
216
+ error: errorMessage(error),
217
+ });
218
+ throw error;
180
219
  }
220
+ },
181
221
 
182
- const authPort: AuthPort<User, Session> = {
183
- async getSession(req) {
184
- const startedAt = Date.now();
185
- try {
186
- const session = await resolveSession(req);
187
- recordAuthEvent({
188
- operation: "getSession",
189
- authenticated: session != null,
190
- summary: session ? "Session found" : "No session",
191
- durationMs: Date.now() - startedAt,
192
- });
193
-
194
- return session;
195
- } catch (error) {
196
- recordAuthEvent({
197
- operation: "getSession.failed",
198
- authenticated: false,
199
- summary: "Session lookup failed",
200
- durationMs: Date.now() - startedAt,
201
- error: errorMessage(error),
202
- });
203
- throw error;
204
- }
205
- },
222
+ async requireUser(req) {
223
+ const startedAt = Date.now();
224
+ try {
225
+ const session = await resolveSession(req);
226
+ if (!session) {
227
+ recordAuthEvent({
228
+ operation: "requireUser",
229
+ authenticated: false,
230
+ summary: "Unauthorized",
231
+ durationMs: Date.now() - startedAt,
232
+ });
233
+ throw new AuthUnauthorizedError();
234
+ }
206
235
 
207
- async getUser(req) {
208
- const startedAt = Date.now();
209
- try {
210
- const session = await resolveSession(req);
211
- recordAuthEvent({
212
- operation: "getUser",
213
- authenticated: session != null,
214
- summary: session ? "User found" : "No user",
215
- durationMs: Date.now() - startedAt,
216
- });
217
- return session?.user ?? null;
218
- } catch (error) {
219
- recordAuthEvent({
220
- operation: "getUser.failed",
221
- authenticated: false,
222
- summary: "User lookup failed",
223
- durationMs: Date.now() - startedAt,
224
- error: errorMessage(error),
225
- });
226
- throw error;
227
- }
228
- },
236
+ recordAuthEvent({
237
+ operation: "requireUser",
238
+ authenticated: true,
239
+ summary: "Authorized",
240
+ durationMs: Date.now() - startedAt,
241
+ });
242
+ return session.user;
243
+ } catch (error) {
244
+ if (error instanceof AuthUnauthorizedError) {
245
+ throw error;
246
+ }
229
247
 
230
- async requireUser(req) {
231
- const startedAt = Date.now();
232
- try {
233
- const session = await resolveSession(req);
234
- if (!session) {
235
- recordAuthEvent({
236
- operation: "requireUser",
237
- authenticated: false,
238
- summary: "Unauthorized",
239
- durationMs: Date.now() - startedAt,
240
- });
241
- throw new AuthUnauthorizedError();
242
- }
248
+ recordAuthEvent({
249
+ operation: "requireUser.failed",
250
+ authenticated: false,
251
+ summary: "Required user lookup failed",
252
+ durationMs: Date.now() - startedAt,
253
+ error: errorMessage(error),
254
+ });
255
+ throw error;
256
+ }
257
+ },
258
+ };
259
+ }
243
260
 
244
- recordAuthEvent({
245
- operation: "requireUser",
246
- authenticated: true,
247
- summary: "Authorized",
248
- durationMs: Date.now() - startedAt,
249
- });
250
- return session.user;
251
- } catch (error) {
252
- if (error instanceof AuthUnauthorizedError) {
253
- throw error;
254
- }
261
+ /**
262
+ * Create a Beignet provider for an existing Better Auth server.
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * import { betterAuth } from "better-auth";
267
+ * import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";
268
+ * import { db } from "./db";
269
+ *
270
+ * const auth = betterAuth({ database: db });
271
+ * const provider = createBetterAuthProvider({ auth });
272
+ * ```
273
+ */
274
+ export function createBetterAuthProvider<User = unknown, Session = unknown>({
275
+ auth,
276
+ }: CreateBetterAuthProviderOptions<User, Session>): BetterAuthProvider<
277
+ User,
278
+ Session
279
+ > {
280
+ return createProvider({
281
+ name: "auth-better-auth",
282
+ metadata: {
283
+ packageName: "@beignet/provider-auth-better-auth",
284
+ ports: ["auth"],
285
+ watchers: ["auth"],
286
+ },
255
287
 
256
- recordAuthEvent({
257
- operation: "requireUser.failed",
258
- authenticated: false,
259
- summary: "Required user lookup failed",
260
- durationMs: Date.now() - startedAt,
261
- error: errorMessage(error),
262
- });
263
- throw error;
264
- }
265
- },
288
+ async setup({ ports }) {
289
+ return {
290
+ ports: {
291
+ auth: createBetterAuthPort({ auth, instrumentation: ports }),
292
+ } satisfies BetterAuthProviderPorts<User, Session>,
266
293
  };
267
-
268
- return { ports: { auth: authPort } };
269
294
  },
270
295
  });
271
296
  }