@murumets-ee/auth 0.2.0 → 0.3.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/dist/client.d.mts +68 -3
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +1 -1
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/plugin-DlfYYNXb.d.mts +71 -0
- package/dist/plugin-DlfYYNXb.d.mts.map +1 -0
- package/dist/plugin.d.mts +1 -1
- package/dist/plugin.mjs.map +1 -1
- package/dist/schema-Je6e5yt2.mjs.map +1 -1
- package/dist/schema.d.mts +1 -1
- package/dist/server-B7Gdv2He.mjs.map +1 -1
- package/dist/{plugin-BS-ho4BN.d.mts → types-Dxs8Jhxs.d.mts} +25 -44
- package/dist/types-Dxs8Jhxs.d.mts.map +1 -0
- package/package.json +13 -13
- package/LICENSE +0 -94
- package/dist/plugin-BS-ho4BN.d.mts.map +0 -1
package/dist/client.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as AdminUser } from "./types-Dxs8Jhxs.mjs";
|
|
1
2
|
import { createAuthClient } from "better-auth/react";
|
|
2
3
|
|
|
3
4
|
//#region src/client.d.ts
|
|
@@ -32,8 +33,72 @@ interface AuthClientOptions {
|
|
|
32
33
|
* const { data: session } = authClient.useSession()
|
|
33
34
|
* ```
|
|
34
35
|
*/
|
|
35
|
-
declare function createClient(options?: AuthClientOptions): ReturnType<typeof createAuthClient
|
|
36
|
-
|
|
36
|
+
declare function createClient(options?: AuthClientOptions): ReturnType<typeof createAuthClient> & AuthClientWithAdmin;
|
|
37
|
+
/**
|
|
38
|
+
* Better-auth's client response shape: discriminated union with data or error.
|
|
39
|
+
* Defined here so we don't depend on better-auth's internal response types.
|
|
40
|
+
*/
|
|
41
|
+
interface BetterAuthResponse<T = unknown> {
|
|
42
|
+
data?: T;
|
|
43
|
+
error?: {
|
|
44
|
+
message?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Structural interface for the admin client methods we use.
|
|
49
|
+
*
|
|
50
|
+
* better-auth's `createAuthClient({ plugins: [adminClient()] })` adds an
|
|
51
|
+
* `admin` namespace at runtime with these methods. The widened return type
|
|
52
|
+
* annotation on `createClient()` loses them (TS2742), so we define just the
|
|
53
|
+
* shape we need. TypeScript verifies at call sites that the passed client
|
|
54
|
+
* structurally matches.
|
|
55
|
+
*/
|
|
56
|
+
interface AuthClientWithAdmin {
|
|
57
|
+
admin: {
|
|
58
|
+
listUsers: (opts: {
|
|
59
|
+
query: {
|
|
60
|
+
limit: number;
|
|
61
|
+
offset: number;
|
|
62
|
+
sortBy?: string;
|
|
63
|
+
sortDirection?: 'asc' | 'desc';
|
|
64
|
+
searchValue?: string;
|
|
65
|
+
searchField?: string;
|
|
66
|
+
searchOperator?: string;
|
|
67
|
+
};
|
|
68
|
+
}) => Promise<BetterAuthResponse<{
|
|
69
|
+
users: AdminUser[];
|
|
70
|
+
total: number;
|
|
71
|
+
}>>;
|
|
72
|
+
createUser: (opts: {
|
|
73
|
+
name: string;
|
|
74
|
+
email: string;
|
|
75
|
+
password: string;
|
|
76
|
+
role: string;
|
|
77
|
+
}) => Promise<BetterAuthResponse>;
|
|
78
|
+
updateUser: (opts: {
|
|
79
|
+
userId: string;
|
|
80
|
+
data: Record<string, unknown>;
|
|
81
|
+
}) => Promise<BetterAuthResponse>;
|
|
82
|
+
removeUser: (opts: {
|
|
83
|
+
userId: string;
|
|
84
|
+
}) => Promise<BetterAuthResponse>;
|
|
85
|
+
setRole: (opts: {
|
|
86
|
+
userId: string;
|
|
87
|
+
role: string;
|
|
88
|
+
}) => Promise<BetterAuthResponse>;
|
|
89
|
+
banUser: (opts: {
|
|
90
|
+
userId: string;
|
|
91
|
+
banReason?: string;
|
|
92
|
+
banExpiresIn?: number;
|
|
93
|
+
}) => Promise<BetterAuthResponse>;
|
|
94
|
+
unbanUser: (opts: {
|
|
95
|
+
userId: string;
|
|
96
|
+
}) => Promise<BetterAuthResponse>;
|
|
97
|
+
revokeUserSessions: (opts: {
|
|
98
|
+
userId: string;
|
|
99
|
+
}) => Promise<BetterAuthResponse>;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
37
102
|
interface UsersListQuery {
|
|
38
103
|
limit: number;
|
|
39
104
|
offset: number;
|
|
@@ -72,7 +137,7 @@ interface NormalizedUser {
|
|
|
72
137
|
* <UsersManagement api={usersApi} currentUserId={session.user.id} />
|
|
73
138
|
* ```
|
|
74
139
|
*/
|
|
75
|
-
declare function createUsersApi(client:
|
|
140
|
+
declare function createUsersApi(client: AuthClientWithAdmin): {
|
|
76
141
|
list(query: UsersListQuery): Promise<{
|
|
77
142
|
users: NormalizedUser[];
|
|
78
143
|
total: number;
|
package/dist/client.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;UAWiB,iBAAA;EAgCD;EA9Bd,OAAA;;EAEA,aAAA;AAAA;;;;;;;;;;;;AAsCD;;;;;;;;;;;AAYkB;;;iBAtBH,YAAA,CACd,OAAA,GAAU,iBAAA,GACT,UAAA,QAAkB,gBAAA,IAAoB,mBAAA;;;;;UAkB/B,kBAAA;EACR,IAAA,GAAO,CAAA;EACP,KAAA;IAAU,OAAA;EAAA;AAAA;;;;;;;;;;UAYF,mBAAA;EACR,KAAA;IACE,SAAA,GAAY,IAAA;MACV,KAAA;QACE,KAAA;QACA,MAAA;QACA,MAAA;QACA,aAAA;QACA,WAAA;QACA,WAAA;QACA,cAAA;MAAA;IAAA,MAEE,OAAA,CAAQ,kBAAA;MAAqB,KAAA,EAAO,SAAA;MAAa,KAAA;IAAA;IACvD,UAAA,GAAa,IAAA;MACX,IAAA;MACA,KAAA;MACA,QAAA;MACA,IAAA;IAAA,MACI,OAAA,CAAQ,kBAAA;IACd,UAAA,GAAa,IAAA;MACX,MAAA;MACA,IAAA,EAAM,MAAA;IAAA,MACF,OAAA,CAAQ,kBAAA;IACd,UAAA,GAAa,IAAA;MAAQ,MAAA;IAAA,MAAqB,OAAA,CAAQ,kBAAA;IAClD,OAAA,GAAU,IAAA;MAAQ,MAAA;MAAgB,IAAA;IAAA,MAAmB,OAAA,CAAQ,kBAAA;IAC7D,OAAA,GAAU,IAAA;MACR,MAAA;MACA,SAAA;MACA,YAAA;IAAA,MACI,OAAA,CAAQ,kBAAA;IACd,SAAA,GAAY,IAAA;MAAQ,MAAA;IAAA,MAAqB,OAAA,CAAQ,kBAAA;IACjD,kBAAA,GAAqB,IAAA;MAAQ,MAAA;IAAA,MAAqB,OAAA,CAAQ,kBAAA;EAAA;AAAA;AAAA,UAIpD,cAAA;EACR,KAAA;EACA,MAAA;EACA,MAAA;EACA,aAAA;EACA,WAAA;EACA,WAAA;EACA,cAAA;AAAA;AAAA,UAGQ,cAAA;EACR,EAAA;EACA,IAAA;EACA,KAAA;EACA,aAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,IAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;AAAA;;;;;;;AAdc;;;;;;;;;;iBAiCA,cAAA,CAAe,MAAA,EAAQ,mBAAA;cAYjB,cAAA,GAAiB,OAAA;IAAU,KAAA,EAAO,cAAA;IAAkB,KAAA;EAAA;;IAsBjD,IAAA;IAAc,KAAA;IAAe,QAAA;IAAkB,IAAA;EAAA,IAAc,OAAA;yBAUvD,IAAA;IAAU,IAAA;EAAA,IAAe,OAAA;0BAKzB,OAAA;0BAKC,IAAA,WAAc,OAAA;sBAKlB,OAAA;IAAc,MAAA;IAAiB,SAAA;EAAA,IAAoB,OAAA;yBASjD,OAAA;kCAKS,OAAA;AAAA"}
|
package/dist/client.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{adminClient as e,organizationClient as t}from"better-auth/client/plugins";import{createAuthClient as n}from"better-auth/react";function r(r){return n({baseURL:r?.baseURL,plugins:[e(),...r?.organizations?[t()]:[]]})}function i(e){function t(e){if(e.error)throw Error(e.error.message??`Unknown error`);return e.data}return{async list(n){let r=t(await e.admin.listUsers({query:{limit:n.limit,offset:n.offset,...n.sortBy?{sortBy:n.sortBy,sortDirection:n.sortDirection}:{},...n.searchValue?{searchValue:n.searchValue,searchField:n.searchField??`email`,searchOperator:n.searchOperator??`contains`}:{}}}));return{users:(r.users??[]).map(a),total:r.total??0}},async create(n){t(await e.admin.createUser({name:n.name,email:n.email,password:n.password,role:n.role}))},async update(n,r){t(await e.admin.updateUser({userId:n,data:r}))},async remove(n){t(await e.admin.removeUser({userId:n}))},async setRole(n,r){t(await e.admin.setRole({userId:n,role:r}))},async ban(n,r){t(await e.admin.banUser({userId:n,...r?.reason?{banReason:r.reason}:{},...r?.expiresIn?{banExpiresIn:r.expiresIn}:{}}))},async unban(n){t(await e.admin.unbanUser({userId:n}))},async revokeSessions(n){t(await e.admin.revokeUserSessions({userId:n}))}}}function a(e){
|
|
1
|
+
import{adminClient as e,organizationClient as t}from"better-auth/client/plugins";import{createAuthClient as n}from"better-auth/react";function r(r){return n({baseURL:r?.baseURL,plugins:[e(),...r?.organizations?[t()]:[]]})}function i(e){function t(e){if(e.error)throw Error(e.error.message??`Unknown error`);return e.data}return{async list(n){let r=t(await e.admin.listUsers({query:{limit:n.limit,offset:n.offset,...n.sortBy?{sortBy:n.sortBy,sortDirection:n.sortDirection}:{},...n.searchValue?{searchValue:n.searchValue,searchField:n.searchField??`email`,searchOperator:n.searchOperator??`contains`}:{}}}));return{users:(r.users??[]).map(a),total:r.total??0}},async create(n){t(await e.admin.createUser({name:n.name,email:n.email,password:n.password,role:n.role}))},async update(n,r){t(await e.admin.updateUser({userId:n,data:r}))},async remove(n){t(await e.admin.removeUser({userId:n}))},async setRole(n,r){t(await e.admin.setRole({userId:n,role:r}))},async ban(n,r){t(await e.admin.banUser({userId:n,...r?.reason?{banReason:r.reason}:{},...r?.expiresIn?{banExpiresIn:r.expiresIn}:{}}))},async unban(n){t(await e.admin.unbanUser({userId:n}))},async revokeSessions(n){t(await e.admin.revokeUserSessions({userId:n}))}}}function a(e){return{id:e.id,name:e.name??``,email:e.email,emailVerified:e.emailVerified??!1,image:e.image??null,createdAt:e.createdAt instanceof Date?e.createdAt.toISOString():String(e.createdAt??``),updatedAt:e.updatedAt instanceof Date?e.updatedAt.toISOString():String(e.updatedAt??``),role:e.role??null,banned:e.banned??null,banReason:e.banReason??null,banExpires:e.banExpires instanceof Date?e.banExpires.toISOString():e.banExpires?String(e.banExpires):null}}export{r as createClient,i as createUsersApi};
|
|
2
2
|
//# sourceMappingURL=client.mjs.map
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["/**\n * Browser-safe auth client factory.\n *\n * This module has NO server-only imports and is safe to use in React components.\n * Import from '@murumets-ee/auth/client'.\n */\n\nimport { adminClient, organizationClient } from 'better-auth/client/plugins'\nimport { createAuthClient } from 'better-auth/react'\n\nexport interface AuthClientOptions {\n /** Base URL of the auth API. Defaults to window.location.origin. */\n baseURL?: string\n /** Enable organization client plugin (must match server config) */\n organizations?: boolean\n}\n\n/**\n * Create a typed auth client for use in React components.\n *\n * The explicit `ReturnType<typeof createAuthClient>` annotation is required\n * because better-auth 1.6's client return type references internal modules\n * (`client/path-to-object`, `client/query`) and zod@4 types that tsdown's\n * dts generator cannot name portably across pnpm's symlink paths (TS2742).\n *\n * Widening to the base `createAuthClient` return type loses the plugin-\n * specific client fields (`client.admin.listUsers`, etc.) at type level.\n * Consumers who need typed access to admin endpoints should use\n * `createUsersApi(client)` which bridges to a stable `UsersApi` interface\n * the `@murumets-ee/admin-ui/users` package expects.\n *\n * @example\n * ```typescript\n * // lib/auth-client.ts\n * import { createClient } from '@murumets-ee/auth/client'\n *\n * export const authClient = createClient()\n *\n * // In a component:\n * const { data: session } = authClient.useSession()\n * ```\n */\nexport function createClient(options?: AuthClientOptions): ReturnType<typeof createAuthClient> {\n return createAuthClient({\n baseURL: options?.baseURL,\n plugins: [adminClient(), ...(options?.organizations ? [organizationClient()] : [])],\n })\n}\n\n// ---------------------------------------------------------------------------\n// UsersApi adapter — bridges better-auth admin client → @murumets-ee/admin-ui/users\n// ---------------------------------------------------------------------------\n\n// biome-ignore lint/suspicious/noExplicitAny: client.admin.* methods live on a\n// plugin-extended type that our explicit annotation on `createClient` loses.\n// `createUsersApi` casts through `any` and validates the shape at call sites.\ntype AuthClient = any\n\ninterface UsersListQuery {\n limit: number\n offset: number\n sortBy?: string\n sortDirection?: 'asc' | 'desc'\n searchValue?: string\n searchField?: 'email' | 'name'\n searchOperator?: 'contains' | 'starts_with' | 'ends_with'\n}\n\ninterface NormalizedUser {\n id: string\n name: string\n email: string\n emailVerified: boolean\n image: string | null\n createdAt: string\n updatedAt: string\n role: string | null\n banned: boolean | null\n banReason: string | null\n banExpires: string | null\n}\n\n/**\n * Create a users API adapter from a better-auth client that includes the\n * `adminClient()` plugin. The returned object is structurally compatible\n * with the `UsersApi` interface from `@murumets-ee/admin-ui/users`.\n *\n * @example\n * ```tsx\n * import { createClient, createUsersApi } from '@murumets-ee/auth/client'\n * import { UsersManagement } from '@murumets-ee/admin-ui/users'\n *\n * const authClient = createClient()\n * const usersApi = createUsersApi(authClient)\n *\n * <UsersManagement api={usersApi} currentUserId={session.user.id} />\n * ```\n */\nexport function createUsersApi(client: AuthClient) {\n /**\n * Unwrap better-auth's discriminated union response.\n * On error branch, `error` exists with optional `message`.\n * On success branch, `data` exists.\n */\n function unwrap<T>(res: { data?: T; error?: { message?: string } }): T {\n if (res.error) throw new Error(res.error.message ?? 'Unknown error')\n return res.data as T\n }\n\n return {\n async list(query: UsersListQuery): Promise<{ users: NormalizedUser[]; total: number }> {\n const res = await client.admin.listUsers({\n query: {\n limit: query.limit,\n offset: query.offset,\n ...(query.sortBy ? { sortBy: query.sortBy, sortDirection: query.sortDirection } : {}),\n ...(query.searchValue\n ? {\n searchValue: query.searchValue,\n searchField: query.searchField ?? 'email',\n searchOperator: query.searchOperator ?? 'contains',\n }\n : {}),\n },\n })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth's union return type doesn't match a simple generic pattern\n const data = unwrap<{ users: unknown[]; total: number }>(res as any)\n return {\n users: (data.users ?? []).map(mapUser),\n total: data.total ?? 0,\n }\n },\n\n async create(data: { name: string; email: string; password: string; role: string }) {\n const res = await client.admin.createUser({\n name: data.name,\n email: data.email,\n password: data.password,\n // better-auth admin plugin types role as a narrow union; cast is safe\n // because server validates the role against configured access control\n role: data.role as 'admin',\n })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async update(userId: string, data: { name?: string }) {\n const res = await client.admin.updateUser({ userId, data })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async remove(userId: string) {\n const res = await client.admin.removeUser({ userId })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async setRole(userId: string, role: string) {\n const res = await client.admin.setRole({\n userId,\n role: role as 'admin',\n })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async ban(userId: string, options?: { reason?: string; expiresIn?: number }) {\n const res = await client.admin.banUser({\n userId,\n ...(options?.reason ? { banReason: options.reason } : {}),\n ...(options?.expiresIn ? { banExpiresIn: options.expiresIn } : {}),\n })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async unban(userId: string) {\n const res = await client.admin.unbanUser({ userId })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n\n async revokeSessions(userId: string) {\n const res = await client.admin.revokeUserSessions({ userId })\n // biome-ignore lint/suspicious/noExplicitAny: better-auth union return type\n unwrap(res as any)\n },\n }\n}\n\n/** Normalize a better-auth user record to a consistent shape. */\nfunction mapUser(u: unknown): NormalizedUser {\n const r = u as Record<string, unknown>\n return {\n id: r.id as string,\n name: (r.name as string) ?? '',\n email: r.email as string,\n emailVerified: (r.emailVerified as boolean) ?? false,\n image: (r.image as string) ?? null,\n createdAt: String(r.createdAt ?? ''),\n updatedAt: String(r.updatedAt ?? ''),\n role: (r.role as string) ?? null,\n banned: (r.banned as boolean) ?? null,\n banReason: (r.banReason as string) ?? null,\n banExpires: r.banExpires ? String(r.banExpires) : null,\n }\n}\n"],"mappings":"sIA0CA,SAAgB,EAAa,EAAkE,CAC7F,OAAO,EAAiB,CACtB,QAAS,GAAS,QAClB,QAAS,CAAC,GAAa,CAAE,GAAI,GAAS,cAAgB,CAAC,GAAoB,CAAC,CAAG,EAAE,CAAE,CACpF,CAAC,CAoDJ,SAAgB,EAAe,EAAoB,CAMjD,SAAS,EAAU,EAAoD,CACrE,GAAI,EAAI,MAAO,MAAU,MAAM,EAAI,MAAM,SAAW,gBAAgB,CACpE,OAAO,EAAI,KAGb,MAAO,CACL,MAAM,KAAK,EAA4E,CAgBrF,IAAM,EAAO,EAfD,MAAM,EAAO,MAAM,UAAU,CACvC,MAAO,CACL,MAAO,EAAM,MACb,OAAQ,EAAM,OACd,GAAI,EAAM,OAAS,CAAE,OAAQ,EAAM,OAAQ,cAAe,EAAM,cAAe,CAAG,EAAE,CACpF,GAAI,EAAM,YACN,CACE,YAAa,EAAM,YACnB,YAAa,EAAM,aAAe,QAClC,eAAgB,EAAM,gBAAkB,WACzC,CACD,EAAE,CACP,CACF,CAAC,CAEkE,CACpE,MAAO,CACL,OAAQ,EAAK,OAAS,EAAE,EAAE,IAAI,EAAQ,CACtC,MAAO,EAAK,OAAS,EACtB,EAGH,MAAM,OAAO,EAAuE,CAUlF,EATY,MAAM,EAAO,MAAM,WAAW,CACxC,KAAM,EAAK,KACX,MAAO,EAAK,MACZ,SAAU,EAAK,SAGf,KAAM,EAAK,KACZ,CAAC,CAEgB,EAGpB,MAAM,OAAO,EAAgB,EAAyB,CAGpD,EAFY,MAAM,EAAO,MAAM,WAAW,CAAE,SAAQ,OAAM,CAAC,CAEzC,EAGpB,MAAM,OAAO,EAAgB,CAG3B,EAFY,MAAM,EAAO,MAAM,WAAW,CAAE,SAAQ,CAAC,CAEnC,EAGpB,MAAM,QAAQ,EAAgB,EAAc,CAM1C,EALY,MAAM,EAAO,MAAM,QAAQ,CACrC,SACM,OACP,CAAC,CAEgB,EAGpB,MAAM,IAAI,EAAgB,EAAmD,CAO3E,EANY,MAAM,EAAO,MAAM,QAAQ,CACrC,SACA,GAAI,GAAS,OAAS,CAAE,UAAW,EAAQ,OAAQ,CAAG,EAAE,CACxD,GAAI,GAAS,UAAY,CAAE,aAAc,EAAQ,UAAW,CAAG,EAAE,CAClE,CAAC,CAEgB,EAGpB,MAAM,MAAM,EAAgB,CAG1B,EAFY,MAAM,EAAO,MAAM,UAAU,CAAE,SAAQ,CAAC,CAElC,EAGpB,MAAM,eAAe,EAAgB,CAGnC,EAFY,MAAM,EAAO,MAAM,mBAAmB,CAAE,SAAQ,CAAC,CAE3C,EAErB,CAIH,SAAS,EAAQ,EAA4B,CAC3C,IAAM,EAAI,EACV,MAAO,CACL,GAAI,EAAE,GACN,KAAO,EAAE,MAAmB,GAC5B,MAAO,EAAE,MACT,cAAgB,EAAE,eAA6B,GAC/C,MAAQ,EAAE,OAAoB,KAC9B,UAAW,OAAO,EAAE,WAAa,GAAG,CACpC,UAAW,OAAO,EAAE,WAAa,GAAG,CACpC,KAAO,EAAE,MAAmB,KAC5B,OAAS,EAAE,QAAsB,KACjC,UAAY,EAAE,WAAwB,KACtC,WAAY,EAAE,WAAa,OAAO,EAAE,WAAW,CAAG,KACnD"}
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["/**\n * Browser-safe auth client factory.\n *\n * This module has NO server-only imports and is safe to use in React components.\n * Import from '@murumets-ee/auth/client'.\n */\n\nimport { adminClient, organizationClient } from 'better-auth/client/plugins'\nimport { createAuthClient } from 'better-auth/react'\nimport type { AdminUser } from './types.js'\n\nexport interface AuthClientOptions {\n /** Base URL of the auth API. Defaults to window.location.origin. */\n baseURL?: string\n /** Enable organization client plugin (must match server config) */\n organizations?: boolean\n}\n\n/**\n * Create a typed auth client for use in React components.\n *\n * The explicit `ReturnType<typeof createAuthClient>` annotation is required\n * because better-auth 1.6's client return type references internal modules\n * (`client/path-to-object`, `client/query`) and zod@4 types that tsdown's\n * dts generator cannot name portably across pnpm's symlink paths (TS2742).\n *\n * Widening to the base `createAuthClient` return type loses the plugin-\n * specific client fields (`client.admin.listUsers`, etc.) at type level.\n * Consumers who need typed access to admin endpoints should use\n * `createUsersApi(client)` which bridges to a stable `UsersApi` interface\n * the `@murumets-ee/admin-ui/users` package expects.\n *\n * @example\n * ```typescript\n * // lib/auth-client.ts\n * import { createClient } from '@murumets-ee/auth/client'\n *\n * export const authClient = createClient()\n *\n * // In a component:\n * const { data: session } = authClient.useSession()\n * ```\n */\nexport function createClient(\n options?: AuthClientOptions,\n): ReturnType<typeof createAuthClient> & AuthClientWithAdmin {\n // The intersection adds admin methods to the widened base type.\n // Safe: adminClient() plugin adds these methods at runtime — the\n // base annotation just can't declare them (TS2742 on internals).\n return createAuthClient({\n baseURL: options?.baseURL,\n plugins: [adminClient(), ...(options?.organizations ? [organizationClient()] : [])],\n }) as ReturnType<typeof createAuthClient> & AuthClientWithAdmin\n}\n\n// ---------------------------------------------------------------------------\n// UsersApi adapter — bridges better-auth admin client → @murumets-ee/admin-ui/users\n// ---------------------------------------------------------------------------\n\n/**\n * Better-auth's client response shape: discriminated union with data or error.\n * Defined here so we don't depend on better-auth's internal response types.\n */\ninterface BetterAuthResponse<T = unknown> {\n data?: T\n error?: { message?: string }\n}\n\n/**\n * Structural interface for the admin client methods we use.\n *\n * better-auth's `createAuthClient({ plugins: [adminClient()] })` adds an\n * `admin` namespace at runtime with these methods. The widened return type\n * annotation on `createClient()` loses them (TS2742), so we define just the\n * shape we need. TypeScript verifies at call sites that the passed client\n * structurally matches.\n */\ninterface AuthClientWithAdmin {\n admin: {\n listUsers: (opts: {\n query: {\n limit: number\n offset: number\n sortBy?: string\n sortDirection?: 'asc' | 'desc'\n searchValue?: string\n searchField?: string\n searchOperator?: string\n }\n }) => Promise<BetterAuthResponse<{ users: AdminUser[]; total: number }>>\n createUser: (opts: {\n name: string\n email: string\n password: string\n role: string\n }) => Promise<BetterAuthResponse>\n updateUser: (opts: {\n userId: string\n data: Record<string, unknown>\n }) => Promise<BetterAuthResponse>\n removeUser: (opts: { userId: string }) => Promise<BetterAuthResponse>\n setRole: (opts: { userId: string; role: string }) => Promise<BetterAuthResponse>\n banUser: (opts: {\n userId: string\n banReason?: string\n banExpiresIn?: number\n }) => Promise<BetterAuthResponse>\n unbanUser: (opts: { userId: string }) => Promise<BetterAuthResponse>\n revokeUserSessions: (opts: { userId: string }) => Promise<BetterAuthResponse>\n }\n}\n\ninterface UsersListQuery {\n limit: number\n offset: number\n sortBy?: string\n sortDirection?: 'asc' | 'desc'\n searchValue?: string\n searchField?: 'email' | 'name'\n searchOperator?: 'contains' | 'starts_with' | 'ends_with'\n}\n\ninterface NormalizedUser {\n id: string\n name: string\n email: string\n emailVerified: boolean\n image: string | null\n createdAt: string\n updatedAt: string\n role: string | null\n banned: boolean | null\n banReason: string | null\n banExpires: string | null\n}\n\n/**\n * Create a users API adapter from a better-auth client that includes the\n * `adminClient()` plugin. The returned object is structurally compatible\n * with the `UsersApi` interface from `@murumets-ee/admin-ui/users`.\n *\n * @example\n * ```tsx\n * import { createClient, createUsersApi } from '@murumets-ee/auth/client'\n * import { UsersManagement } from '@murumets-ee/admin-ui/users'\n *\n * const authClient = createClient()\n * const usersApi = createUsersApi(authClient)\n *\n * <UsersManagement api={usersApi} currentUserId={session.user.id} />\n * ```\n */\nexport function createUsersApi(client: AuthClientWithAdmin) {\n /**\n * Unwrap better-auth's discriminated union response.\n * On error branch, `error` exists with optional `message`.\n * On success branch, `data` exists.\n */\n function unwrap<T>(res: BetterAuthResponse<T>): T {\n if (res.error) throw new Error(res.error.message ?? 'Unknown error')\n return res.data as T\n }\n\n return {\n async list(query: UsersListQuery): Promise<{ users: NormalizedUser[]; total: number }> {\n const res = await client.admin.listUsers({\n query: {\n limit: query.limit,\n offset: query.offset,\n ...(query.sortBy ? { sortBy: query.sortBy, sortDirection: query.sortDirection } : {}),\n ...(query.searchValue\n ? {\n searchValue: query.searchValue,\n searchField: query.searchField ?? 'email',\n searchOperator: query.searchOperator ?? 'contains',\n }\n : {}),\n },\n })\n const data = unwrap(res)\n return {\n users: (data.users ?? []).map(mapUser),\n total: data.total ?? 0,\n }\n },\n\n async create(data: { name: string; email: string; password: string; role: string }) {\n const res = await client.admin.createUser({\n name: data.name,\n email: data.email,\n password: data.password,\n role: data.role,\n })\n unwrap(res)\n },\n\n async update(userId: string, data: { name?: string }) {\n const res = await client.admin.updateUser({ userId, data })\n unwrap(res)\n },\n\n async remove(userId: string) {\n const res = await client.admin.removeUser({ userId })\n unwrap(res)\n },\n\n async setRole(userId: string, role: string) {\n const res = await client.admin.setRole({ userId, role })\n unwrap(res)\n },\n\n async ban(userId: string, options?: { reason?: string; expiresIn?: number }) {\n const res = await client.admin.banUser({\n userId,\n ...(options?.reason ? { banReason: options.reason } : {}),\n ...(options?.expiresIn ? { banExpiresIn: options.expiresIn } : {}),\n })\n unwrap(res)\n },\n\n async unban(userId: string) {\n const res = await client.admin.unbanUser({ userId })\n unwrap(res)\n },\n\n async revokeSessions(userId: string) {\n const res = await client.admin.revokeUserSessions({ userId })\n unwrap(res)\n },\n }\n}\n\n/** Normalize a better-auth admin user to a serializable shape (Dates → strings). */\nfunction mapUser(u: AdminUser): NormalizedUser {\n return {\n id: u.id,\n name: u.name ?? '',\n email: u.email,\n emailVerified: u.emailVerified ?? false,\n image: u.image ?? null,\n createdAt: u.createdAt instanceof Date ? u.createdAt.toISOString() : String(u.createdAt ?? ''),\n updatedAt: u.updatedAt instanceof Date ? u.updatedAt.toISOString() : String(u.updatedAt ?? ''),\n role: u.role ?? null,\n banned: u.banned ?? null,\n banReason: u.banReason ?? null,\n banExpires: u.banExpires instanceof Date ? u.banExpires.toISOString() : u.banExpires ? String(u.banExpires) : null,\n }\n}\n"],"mappings":"sIA2CA,SAAgB,EACd,EAC2D,CAI3D,OAAO,EAAiB,CACtB,QAAS,GAAS,QAClB,QAAS,CAAC,GAAa,CAAE,GAAI,GAAS,cAAgB,CAAC,GAAoB,CAAC,CAAG,EAAE,CAAE,CACpF,CAAC,CAoGJ,SAAgB,EAAe,EAA6B,CAM1D,SAAS,EAAU,EAA+B,CAChD,GAAI,EAAI,MAAO,MAAU,MAAM,EAAI,MAAM,SAAW,gBAAgB,CACpE,OAAO,EAAI,KAGb,MAAO,CACL,MAAM,KAAK,EAA4E,CAerF,IAAM,EAAO,EAdD,MAAM,EAAO,MAAM,UAAU,CACvC,MAAO,CACL,MAAO,EAAM,MACb,OAAQ,EAAM,OACd,GAAI,EAAM,OAAS,CAAE,OAAQ,EAAM,OAAQ,cAAe,EAAM,cAAe,CAAG,EAAE,CACpF,GAAI,EAAM,YACN,CACE,YAAa,EAAM,YACnB,YAAa,EAAM,aAAe,QAClC,eAAgB,EAAM,gBAAkB,WACzC,CACD,EAAE,CACP,CACF,CAAC,CACsB,CACxB,MAAO,CACL,OAAQ,EAAK,OAAS,EAAE,EAAE,IAAI,EAAQ,CACtC,MAAO,EAAK,OAAS,EACtB,EAGH,MAAM,OAAO,EAAuE,CAOlF,EANY,MAAM,EAAO,MAAM,WAAW,CACxC,KAAM,EAAK,KACX,MAAO,EAAK,MACZ,SAAU,EAAK,SACf,KAAM,EAAK,KACZ,CAAC,CACS,EAGb,MAAM,OAAO,EAAgB,EAAyB,CAEpD,EADY,MAAM,EAAO,MAAM,WAAW,CAAE,SAAQ,OAAM,CAAC,CAChD,EAGb,MAAM,OAAO,EAAgB,CAE3B,EADY,MAAM,EAAO,MAAM,WAAW,CAAE,SAAQ,CAAC,CAC1C,EAGb,MAAM,QAAQ,EAAgB,EAAc,CAE1C,EADY,MAAM,EAAO,MAAM,QAAQ,CAAE,SAAQ,OAAM,CAAC,CAC7C,EAGb,MAAM,IAAI,EAAgB,EAAmD,CAM3E,EALY,MAAM,EAAO,MAAM,QAAQ,CACrC,SACA,GAAI,GAAS,OAAS,CAAE,UAAW,EAAQ,OAAQ,CAAG,EAAE,CACxD,GAAI,GAAS,UAAY,CAAE,aAAc,EAAQ,UAAW,CAAG,EAAE,CAClE,CAAC,CACS,EAGb,MAAM,MAAM,EAAgB,CAE1B,EADY,MAAM,EAAO,MAAM,UAAU,CAAE,SAAQ,CAAC,CACzC,EAGb,MAAM,eAAe,EAAgB,CAEnC,EADY,MAAM,EAAO,MAAM,mBAAmB,CAAE,SAAQ,CAAC,CAClD,EAEd,CAIH,SAAS,EAAQ,EAA8B,CAC7C,MAAO,CACL,GAAI,EAAE,GACN,KAAM,EAAE,MAAQ,GAChB,MAAO,EAAE,MACT,cAAe,EAAE,eAAiB,GAClC,MAAO,EAAE,OAAS,KAClB,UAAW,EAAE,qBAAqB,KAAO,EAAE,UAAU,aAAa,CAAG,OAAO,EAAE,WAAa,GAAG,CAC9F,UAAW,EAAE,qBAAqB,KAAO,EAAE,UAAU,aAAa,CAAG,OAAO,EAAE,WAAa,GAAG,CAC9F,KAAM,EAAE,MAAQ,KAChB,OAAQ,EAAE,QAAU,KACpB,UAAW,EAAE,WAAa,KAC1B,WAAY,EAAE,sBAAsB,KAAO,EAAE,WAAW,aAAa,CAAG,EAAE,WAAa,OAAO,EAAE,WAAW,CAAG,KAC/G"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as AuthConfig, t as AdminUser } from "./types-Dxs8Jhxs.mjs";
|
|
2
|
+
import { i as AuthAdminApi, n as getAuth, r as Auth, t as auth } from "./plugin-DlfYYNXb.mjs";
|
|
2
3
|
import { createAccessControl } from "better-auth/plugins/access";
|
|
3
4
|
import * as _$better_auth_plugins0 from "better-auth/plugins";
|
|
4
5
|
import { PermissionChecker, RequestContext } from "@murumets-ee/core";
|
|
@@ -100,5 +101,5 @@ declare function buildDefaultRoles(ac: ReturnType<typeof createAccessControl>, e
|
|
|
100
101
|
};
|
|
101
102
|
};
|
|
102
103
|
//#endregion
|
|
103
|
-
export { ACTIONS, ACTIONS_WITH_PUBLISH, type Auth, type AuthConfig, BUILT_IN_ROLES, METHOD_TO_ACTION, auth, buildDefaultRoles, buildInitialRoleDefinitions, buildPermissionChecker, buildResourceCatalog, buildStatements, createAccessControl, getAuth, resolveAuthContext };
|
|
104
|
+
export { ACTIONS, ACTIONS_WITH_PUBLISH, type AdminUser, type Auth, type AuthAdminApi, type AuthConfig, BUILT_IN_ROLES, METHOD_TO_ACTION, auth, buildDefaultRoles, buildInitialRoleDefinitions, buildPermissionChecker, buildResourceCatalog, buildStatements, createAccessControl, getAuth, resolveAuthContext };
|
|
104
105
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.ts","../src/permissions.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.ts","../src/permissions.ts"],"mappings":";;;;;;;;AA8BA;;;;;;;;;;;;;;;;;;;AAAA,iBAAsB,kBAAA,CAAmB,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,cAAA;;;cCf1E,OAAA;AAAA,cACA,oBAAA;;cASO,cAAA;;cAGA,gBAAA,EAAkB,MAAA;;;;;;;iBAiBf,2BAAA,CAAA,GAA+B,MAAA,SAAe,MAAA;;;AAhCE;;;;;AAED;iBA6C/C,sBAAA,CACd,eAAA,EAAiB,MAAA,SAAe,MAAA,sBAC/B,iBAAA;;;;AArCH;;;;;AAGA;;;iBAwEgB,oBAAA,CACd,QAAA;EAAY,IAAA;EAAc,SAAA;IAAc,IAAA;EAAA;AAAA,KACxC,MAAA;EAAW,QAAA;EAAmB,OAAA;AAAA,MAC7B,MAAA;;;;;;;;iBA+Ca,eAAA,CAAgB,QAAA,EAAU,MAAA,KAAQ,MAAA;;;;;AAlDlD;;iBAkEgB,iBAAA,CAAkB,EAAA,EAAI,UAAA,QAAkB,mBAAA,GAAsB,QAAA,EAAU,MAAA"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { n as AuthConfig, t as AdminUser } from "./types-Dxs8Jhxs.mjs";
|
|
2
|
+
import { Auth } from "better-auth";
|
|
3
|
+
import { Plugin } from "@murumets-ee/core";
|
|
4
|
+
//#region src/server.d.ts
|
|
5
|
+
/** Type of the auth server instance. Aliased from better-auth's generic
|
|
6
|
+
* `Auth` because the explicit annotation on `createAuthServer` means
|
|
7
|
+
* `ReturnType<typeof createAuthServer>` is already `BetterAuthBase`. */
|
|
8
|
+
type Auth$1 = Auth;
|
|
9
|
+
/**
|
|
10
|
+
* Structural interface for the server-side admin API methods.
|
|
11
|
+
*
|
|
12
|
+
* The widened `Auth` type (BetterAuthBase) doesn't expose admin plugin
|
|
13
|
+
* endpoints. This interface describes just the methods consumers need
|
|
14
|
+
* so they can access them without `as any`.
|
|
15
|
+
*
|
|
16
|
+
* Usage: `(auth.api as AuthAdminApi).listUsers(...)`
|
|
17
|
+
*/
|
|
18
|
+
interface AuthAdminApi {
|
|
19
|
+
listUsers: (opts: {
|
|
20
|
+
headers: Headers;
|
|
21
|
+
query: {
|
|
22
|
+
limit: number;
|
|
23
|
+
sortBy: string;
|
|
24
|
+
sortDirection: 'asc' | 'desc';
|
|
25
|
+
};
|
|
26
|
+
}) => Promise<{
|
|
27
|
+
users: AdminUser[];
|
|
28
|
+
total: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/plugin.d.ts
|
|
33
|
+
/** Auth with admin API — admin plugin is always loaded in createAuthServer */
|
|
34
|
+
type AuthWithAdmin = Auth$1 & {
|
|
35
|
+
api: AuthAdminApi;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Get the auth server instance.
|
|
39
|
+
* Throws if the auth plugin hasn't been initialized yet.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // app/api/auth/[...all]/route.ts (user writes this)
|
|
44
|
+
* import { toNextJsHandler } from 'better-auth/next-js'
|
|
45
|
+
* import { getAuth } from '@murumets-ee/auth'
|
|
46
|
+
*
|
|
47
|
+
* export const { GET, POST } = toNextJsHandler(getAuth())
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function getAuth(): AuthWithAdmin;
|
|
51
|
+
/**
|
|
52
|
+
* Create the auth toolkit plugin.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { defineConfig } from '@murumets-ee/core'
|
|
57
|
+
* import { auth } from '@murumets-ee/auth'
|
|
58
|
+
*
|
|
59
|
+
* export default defineConfig({
|
|
60
|
+
* db: { url: process.env.DATABASE_URL! },
|
|
61
|
+
* entities: [Article, Category],
|
|
62
|
+
* plugins: [
|
|
63
|
+
* auth({ providers: ['email'] }),
|
|
64
|
+
* ],
|
|
65
|
+
* })
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare function auth(config?: AuthConfig): Plugin;
|
|
69
|
+
//#endregion
|
|
70
|
+
export { AuthAdminApi as i, getAuth as n, Auth$1 as r, auth as t };
|
|
71
|
+
//# sourceMappingURL=plugin-DlfYYNXb.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-DlfYYNXb.d.mts","names":[],"sources":["../src/server.ts","../src/plugin.ts"],"mappings":";;;;;;;KAsYY,MAAA,GAAO,IAAA;;ACnXyB;;;;;;;;UD8X3B,YAAA;EACf,SAAA,GAAY,IAAA;IACV,OAAA,EAAS,OAAA;IACT,KAAA;MACE,KAAA;MACA,MAAA;MACA,aAAA;IAAA;EAAA,MAEE,OAAA;IAAU,KAAA,EAAO,SAAA;IAAa,KAAA;EAAA;AAAA;;;;KCnYjC,aAAA,GAAgB,MAAA;EAAS,GAAA,EAAK,YAAA;AAAA;;;;;;;;;;;;;;iBAkBnB,OAAA,CAAA,GAAW,aAAA;;;;;;;;;;AArBiB;;;;;;;;iBA6C5B,IAAA,CAAK,MAAA,GAAQ,UAAA,GAAkB,MAAA"}
|
package/dist/plugin.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as getAuth, t as auth } from "./plugin-
|
|
1
|
+
import { n as getAuth, t as auth } from "./plugin-DlfYYNXb.mjs";
|
|
2
2
|
export { auth, getAuth };
|
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * Toolkit plugin implementation for @murumets-ee/auth.\n *\n * Implements the Plugin interface from @murumets-ee/core.\n * Creates and stores the better-auth server instance during init.\n */\n\nimport type { Plugin } from '@murumets-ee/core'\nimport type { AuditLogger } from '@murumets-ee/logging'\nimport {\n account,\n invitation,\n member,\n organization,\n session,\n user,\n verification,\n} from './schema.js'\nimport type { Auth } from './server.js'\nimport type { AuthConfig } from './types.js'\n\n/** The initialized auth server instance (set during plugin init) */\nlet _auth:
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * Toolkit plugin implementation for @murumets-ee/auth.\n *\n * Implements the Plugin interface from @murumets-ee/core.\n * Creates and stores the better-auth server instance during init.\n */\n\nimport type { Plugin } from '@murumets-ee/core'\nimport type { AuditLogger } from '@murumets-ee/logging'\nimport {\n account,\n invitation,\n member,\n organization,\n session,\n user,\n verification,\n} from './schema.js'\nimport type { Auth, AuthAdminApi } from './server.js'\nimport type { AuthConfig } from './types.js'\n\n/** Auth with admin API — admin plugin is always loaded in createAuthServer */\ntype AuthWithAdmin = Auth & { api: AuthAdminApi }\n\n/** The initialized auth server instance (set during plugin init) */\nlet _auth: AuthWithAdmin | null = null\n\n/**\n * Get the auth server instance.\n * Throws if the auth plugin hasn't been initialized yet.\n *\n * @example\n * ```typescript\n * // app/api/auth/[...all]/route.ts (user writes this)\n * import { toNextJsHandler } from 'better-auth/next-js'\n * import { getAuth } from '@murumets-ee/auth'\n *\n * export const { GET, POST } = toNextJsHandler(getAuth())\n * ```\n */\nexport function getAuth(): AuthWithAdmin {\n if (!_auth) {\n throw new Error('@murumets-ee/auth not initialized. Add auth() to your toolkit config plugins.')\n }\n return _auth\n}\n\n/**\n * Create the auth toolkit plugin.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@murumets-ee/core'\n * import { auth } from '@murumets-ee/auth'\n *\n * export default defineConfig({\n * db: { url: process.env.DATABASE_URL! },\n * entities: [Article, Category],\n * plugins: [\n * auth({ providers: ['email'] }),\n * ],\n * })\n * ```\n */\nexport function auth(config: AuthConfig = {}): Plugin {\n return {\n name: '@murumets-ee/auth',\n // Expose better-auth's Drizzle tables so `lumi migrate` picks them up\n // automatically. The canonical schema lives in\n // `@murumets-ee/auth/schema` — committed, not codegen-generated.\n tables: { user, session, account, verification, organization, member, invitation },\n init: async (app) => {\n const { createAuthServer } = await import('./server.js')\n\n // Create audit logger for auth events (login, signup, ban, etc.)\n // unless explicitly disabled via `audit: false`\n let auditLogger: AuditLogger | undefined\n if (config.audit !== false) {\n const { createAuditLogger, createAuditDbWriter, createLogger } = await import(\n '@murumets-ee/logging'\n )\n auditLogger = createAuditLogger({\n logger: createLogger({ name: 'auth-audit' }),\n dbWriter: createAuditDbWriter(app.db.readWrite),\n })\n }\n\n // createAuthServer always loads the admin plugin, so listUsers etc.\n // exist at runtime. The return type is widened to BetterAuthBase for\n // DTS portability (TS2742 — zod@4 internal paths). This single\n // assertion bridges the gap so getAuth() consumers get typed admin API.\n _auth = createAuthServer(config, app, auditLogger) as AuthWithAdmin\n app.logger.info('Auth plugin initialized')\n },\n }\n}\n"],"mappings":"+EAyBA,IAAI,EAA8B,KAelC,SAAgB,GAAyB,CACvC,GAAI,CAAC,EACH,MAAU,MAAM,gFAAgF,CAElG,OAAO,EAoBT,SAAgB,EAAK,EAAqB,EAAE,CAAU,CACpD,MAAO,CACL,KAAM,oBAIN,OAAQ,CAAE,OAAM,UAAS,UAAS,eAAc,eAAc,SAAQ,aAAY,CAClF,KAAM,KAAO,IAAQ,CACnB,GAAM,CAAE,oBAAqB,MAAM,OAAO,yBAItC,EACJ,GAAI,EAAO,QAAU,GAAO,CAC1B,GAAM,CAAE,oBAAmB,sBAAqB,gBAAiB,MAAM,OACrE,wBAEF,EAAc,EAAkB,CAC9B,OAAQ,EAAa,CAAE,KAAM,aAAc,CAAC,CAC5C,SAAU,EAAoB,EAAI,GAAG,UAAU,CAChD,CAAC,CAOJ,EAAQ,EAAiB,EAAQ,EAAK,EAAY,CAClD,EAAI,OAAO,KAAK,0BAA0B,EAE7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-Je6e5yt2.mjs","names":[],"sources":["../src/schema.ts"],"sourcesContent":["/**\n * Pre-generated Drizzle schema for better-auth tables.\n *\n * This file is the canonical snapshot of every table better-auth's\n * `admin` and `organization` plugins create when configured with the\n * toolkit's default server. It is committed source — NOT generated at\n * `lumi setup` time — so scaffolded projects don't need to invoke\n * `@better-auth/cli generate`, don't need a separate `auth.config.ts`,\n * and don't carry a `generated/auth-schema.ts` file in their repo.\n *\n * Regenerating this file:\n *\n * 1. Only when bumping better-auth or changing the plugin list in\n * `packages/auth/src/server.ts`.\n * 2. Run `pnpm --filter @murumets-ee/auth gen:schema` (which runs\n * `@better-auth/cli generate` against `scripts/schema-source.ts`)\n * and review the diff.\n * 3. Commit.\n *\n * Consumers: `import * as authSchema from '@murumets-ee/auth/schema'`\n * and pass it directly to drizzle-kit/api's `generateDrizzleJson`.\n */\n\nimport { relations } from 'drizzle-orm'\nimport { boolean, index, pgTable, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'\n\nexport const user = pgTable('user', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n emailVerified: boolean('email_verified').default(false).notNull(),\n image: text('image'),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .defaultNow()\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n role: text('role'),\n banned: boolean('banned').default(false),\n banReason: text('ban_reason'),\n banExpires: timestamp('ban_expires'),\n})\n\nexport const session = pgTable(\n 'session',\n {\n id: text('id').primaryKey(),\n expiresAt: timestamp('expires_at').notNull(),\n token: text('token').notNull().unique(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n ipAddress: text('ip_address'),\n userAgent: text('user_agent'),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n impersonatedBy: text('impersonated_by'),\n activeOrganizationId: text('active_organization_id'),\n },\n (table) => [index('session_userId_idx').on(table.userId)],\n)\n\nexport const account = pgTable(\n 'account',\n {\n id: text('id').primaryKey(),\n accountId: text('account_id').notNull(),\n providerId: text('provider_id').notNull(),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n accessToken: text('access_token'),\n refreshToken: text('refresh_token'),\n idToken: text('id_token'),\n accessTokenExpiresAt: timestamp('access_token_expires_at'),\n refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),\n scope: text('scope'),\n password: text('password'),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n },\n (table) => [index('account_userId_idx').on(table.userId)],\n)\n\nexport const verification = pgTable(\n 'verification',\n {\n id: text('id').primaryKey(),\n identifier: text('identifier').notNull(),\n value: text('value').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .defaultNow()\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n },\n (table) => [index('verification_identifier_idx').on(table.identifier)],\n)\n\nexport const organization = pgTable(\n 'organization',\n {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n slug: text('slug').notNull().unique(),\n logo: text('logo'),\n createdAt: timestamp('created_at').notNull(),\n metadata: text('metadata'),\n },\n (table) => [uniqueIndex('organization_slug_uidx').on(table.slug)],\n)\n\nexport const member = pgTable(\n 'member',\n {\n id: text('id').primaryKey(),\n organizationId: text('organization_id')\n .notNull()\n .references(() => organization.id, { onDelete: 'cascade' }),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n role: text('role').default('member').notNull(),\n createdAt: timestamp('created_at').notNull(),\n },\n (table) => [\n index('member_organizationId_idx').on(table.organizationId),\n index('member_userId_idx').on(table.userId),\n ],\n)\n\nexport const invitation = pgTable(\n 'invitation',\n {\n id: text('id').primaryKey(),\n organizationId: text('organization_id')\n .notNull()\n .references(() => organization.id, { onDelete: 'cascade' }),\n email: text('email').notNull(),\n role: text('role'),\n status: text('status').default('pending').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n inviterId: text('inviter_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n },\n (table) => [\n index('invitation_organizationId_idx').on(table.organizationId),\n index('invitation_email_idx').on(table.email),\n ],\n)\n\nexport const userRelations = relations(user, ({ many }) => ({\n sessions: many(session),\n accounts: many(account),\n members: many(member),\n invitations: many(invitation),\n}))\n\nexport const sessionRelations = relations(session, ({ one }) => ({\n user: one(user, {\n fields: [session.userId],\n references: [user.id],\n }),\n}))\n\nexport const accountRelations = relations(account, ({ one }) => ({\n user: one(user, {\n fields: [account.userId],\n references: [user.id],\n }),\n}))\n\nexport const organizationRelations = relations(organization, ({ many }) => ({\n members: many(member),\n invitations: many(invitation),\n}))\n\nexport const memberRelations = relations(member, ({ one }) => ({\n organization: one(organization, {\n fields: [member.organizationId],\n references: [organization.id],\n }),\n user: one(user, {\n fields: [member.userId],\n references: [user.id],\n }),\n}))\n\nexport const invitationRelations = relations(invitation, ({ one }) => ({\n organization: one(organization, {\n fields: [invitation.organizationId],\n references: [organization.id],\n }),\n user: one(user, {\n fields: [invitation.inviterId],\n references: [user.id],\n }),\n}))\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema-Je6e5yt2.mjs","names":[],"sources":["../src/schema.ts"],"sourcesContent":["/**\n * Pre-generated Drizzle schema for better-auth tables.\n *\n * This file is the canonical snapshot of every table better-auth's\n * `admin` and `organization` plugins create when configured with the\n * toolkit's default server. It is committed source — NOT generated at\n * scaffold time — so scaffolded projects don't need to invoke\n * `@better-auth/cli generate`, don't need a separate `auth.config.ts`,\n * and don't carry a `generated/auth-schema.ts` file in their repo.\n *\n * Regenerating this file:\n *\n * 1. Only when bumping better-auth or changing the plugin list in\n * `packages/auth/src/server.ts`.\n * 2. Run `pnpm --filter @murumets-ee/auth gen:schema` (which runs\n * `@better-auth/cli generate` against `scripts/schema-source.ts`)\n * and review the diff.\n * 3. Commit.\n *\n * Consumers: `import * as authSchema from '@murumets-ee/auth/schema'`\n * and pass it directly to drizzle-kit/api's `generateDrizzleJson`.\n */\n\nimport { relations } from 'drizzle-orm'\nimport { boolean, index, pgTable, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'\n\nexport const user = pgTable('user', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n emailVerified: boolean('email_verified').default(false).notNull(),\n image: text('image'),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .defaultNow()\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n role: text('role'),\n banned: boolean('banned').default(false),\n banReason: text('ban_reason'),\n banExpires: timestamp('ban_expires'),\n})\n\nexport const session = pgTable(\n 'session',\n {\n id: text('id').primaryKey(),\n expiresAt: timestamp('expires_at').notNull(),\n token: text('token').notNull().unique(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n ipAddress: text('ip_address'),\n userAgent: text('user_agent'),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n impersonatedBy: text('impersonated_by'),\n activeOrganizationId: text('active_organization_id'),\n },\n (table) => [index('session_userId_idx').on(table.userId)],\n)\n\nexport const account = pgTable(\n 'account',\n {\n id: text('id').primaryKey(),\n accountId: text('account_id').notNull(),\n providerId: text('provider_id').notNull(),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n accessToken: text('access_token'),\n refreshToken: text('refresh_token'),\n idToken: text('id_token'),\n accessTokenExpiresAt: timestamp('access_token_expires_at'),\n refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),\n scope: text('scope'),\n password: text('password'),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n },\n (table) => [index('account_userId_idx').on(table.userId)],\n)\n\nexport const verification = pgTable(\n 'verification',\n {\n id: text('id').primaryKey(),\n identifier: text('identifier').notNull(),\n value: text('value').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n updatedAt: timestamp('updated_at')\n .defaultNow()\n .$onUpdate(() => /* @__PURE__ */ new Date())\n .notNull(),\n },\n (table) => [index('verification_identifier_idx').on(table.identifier)],\n)\n\nexport const organization = pgTable(\n 'organization',\n {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n slug: text('slug').notNull().unique(),\n logo: text('logo'),\n createdAt: timestamp('created_at').notNull(),\n metadata: text('metadata'),\n },\n (table) => [uniqueIndex('organization_slug_uidx').on(table.slug)],\n)\n\nexport const member = pgTable(\n 'member',\n {\n id: text('id').primaryKey(),\n organizationId: text('organization_id')\n .notNull()\n .references(() => organization.id, { onDelete: 'cascade' }),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n role: text('role').default('member').notNull(),\n createdAt: timestamp('created_at').notNull(),\n },\n (table) => [\n index('member_organizationId_idx').on(table.organizationId),\n index('member_userId_idx').on(table.userId),\n ],\n)\n\nexport const invitation = pgTable(\n 'invitation',\n {\n id: text('id').primaryKey(),\n organizationId: text('organization_id')\n .notNull()\n .references(() => organization.id, { onDelete: 'cascade' }),\n email: text('email').notNull(),\n role: text('role'),\n status: text('status').default('pending').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow().notNull(),\n inviterId: text('inviter_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n },\n (table) => [\n index('invitation_organizationId_idx').on(table.organizationId),\n index('invitation_email_idx').on(table.email),\n ],\n)\n\nexport const userRelations = relations(user, ({ many }) => ({\n sessions: many(session),\n accounts: many(account),\n members: many(member),\n invitations: many(invitation),\n}))\n\nexport const sessionRelations = relations(session, ({ one }) => ({\n user: one(user, {\n fields: [session.userId],\n references: [user.id],\n }),\n}))\n\nexport const accountRelations = relations(account, ({ one }) => ({\n user: one(user, {\n fields: [account.userId],\n references: [user.id],\n }),\n}))\n\nexport const organizationRelations = relations(organization, ({ many }) => ({\n members: many(member),\n invitations: many(invitation),\n}))\n\nexport const memberRelations = relations(member, ({ one }) => ({\n organization: one(organization, {\n fields: [member.organizationId],\n references: [organization.id],\n }),\n user: one(user, {\n fields: [member.userId],\n references: [user.id],\n }),\n}))\n\nexport const invitationRelations = relations(invitation, ({ one }) => ({\n organization: one(organization, {\n fields: [invitation.organizationId],\n references: [organization.id],\n }),\n user: one(user, {\n fields: [invitation.inviterId],\n references: [user.id],\n }),\n}))\n"],"mappings":"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"}
|
package/dist/schema.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ import * as _$drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
|
|
|
8
8
|
* This file is the canonical snapshot of every table better-auth's
|
|
9
9
|
* `admin` and `organization` plugins create when configured with the
|
|
10
10
|
* toolkit's default server. It is committed source — NOT generated at
|
|
11
|
-
*
|
|
11
|
+
* scaffold time — so scaffolded projects don't need to invoke
|
|
12
12
|
* `@better-auth/cli generate`, don't need a separate `auth.config.ts`,
|
|
13
13
|
* and don't carry a `generated/auth-schema.ts` file in their repo.
|
|
14
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-B7Gdv2He.mjs","names":["defaultAuthSchema"],"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-side auth instance factory.\n *\n * Creates a configured `betterAuth()` instance using the toolkit's database\n * connection and entity definitions. This is server-only code.\n */\n\nimport type { ToolkitApp } from '@murumets-ee/core'\nimport type { AuditLogger } from '@murumets-ee/logging'\nimport type { Auth as BetterAuthBase, BetterAuthOptions } from 'better-auth'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\nimport { APIError, createAuthMiddleware } from 'better-auth/api'\nimport { nextCookies } from 'better-auth/next-js'\nimport { admin } from 'better-auth/plugins'\nimport type { Role } from 'better-auth/plugins/access'\nimport { createAccessControl } from 'better-auth/plugins/access'\nimport { organization } from 'better-auth/plugins/organization'\nimport { sql as drizzleSql } from 'drizzle-orm'\nimport { buildDefaultRoles, buildStatements } from './permissions.js'\nimport * as defaultAuthSchema from './schema.js'\nimport type { AuthConfig } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Audit hooks — wired into better-auth's databaseHooks\n// ---------------------------------------------------------------------------\n\n/** Extract acting admin's id and name from better-auth hook context.\n * ctx is GenericEndpointContext | null — we access session safely via optional chaining. */\nfunction getActor(ctx: unknown) {\n const session = (ctx as { context?: { session?: Record<string, unknown> } } | null)?.context\n ?.session\n const user = session?.user as { id?: string; name?: string } | undefined\n return {\n id: user?.id ?? (session?.userId as string | undefined),\n name: user?.name,\n }\n}\n\n/** Fields to strip from user update audit payloads */\nconst SKIP_FIELDS = new Set(['updatedAt', 'createdAt'])\n\nfunction buildDatabaseHooks(db: ToolkitApp['db'], auditLogger?: AuditLogger) {\n /** Fire-and-forget audit — never block auth operations */\n function audit(entry: Parameters<AuditLogger['log']>[0]) {\n auditLogger?.log(entry).catch(() => {})\n }\n\n // `before` captures changed fields, `after` has full user + actor ctx.\n // Bridge with a simple variable — updates are sequential per request.\n let pendingFields: Record<string, unknown> | null = null\n\n return {\n user: {\n create: {\n after: async (user: Record<string, unknown>) => {\n // Auto-promote first user to admin (fresh DB setup).\n // Single atomic statement — if two signups race, only one sees count=1.\n try {\n await db.readWrite.execute(\n drizzleSql`UPDATE \"user\" SET role = 'admin' WHERE id = ${user.id as string} AND (SELECT COUNT(*) FROM \"user\") = 1`,\n )\n } catch {\n // Non-fatal — don't block signup if promotion fails\n }\n\n // Signup — actor is the new user themselves\n audit({\n action: 'auth.signup',\n entityType: 'user',\n entityId: user.id as string,\n userId: user.id as string,\n userName: user.name as string,\n changes: {\n fields: { name: user.name, email: user.email },\n },\n })\n },\n },\n update: {\n // `before` receives only the changed fields — capture them\n before: async (userData: Record<string, unknown>) => {\n const fields: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(userData)) {\n if (SKIP_FIELDS.has(key) || key === 'id') continue\n fields[key] = value\n }\n pendingFields = Object.keys(fields).length > 0 ? fields : null\n },\n // `after` has full user (name) + ctx (actor session) — log everything\n after: async (user: Record<string, unknown>, ctx: unknown) => {\n const actor = getActor(ctx)\n const fields = pendingFields\n pendingFields = null\n audit({\n action: 'auth.user.update',\n entityType: 'user',\n entityId: user.id as string,\n userId: actor.id,\n userName: actor.name,\n changes: fields ? { fields } : undefined,\n metadata: {\n targetUser: user.name as string | undefined,\n },\n })\n },\n },\n delete: {\n after: async (user: Record<string, unknown>, ctx: unknown) => {\n const actor = getActor(ctx)\n audit({\n action: 'auth.user.delete',\n entityType: 'user',\n entityId: user.id as string,\n userId: actor.id,\n userName: actor.name,\n metadata: {\n targetUser: user.name as string | undefined,\n },\n })\n },\n },\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Request-level hooks — catches failed logins, password changes, etc.\n// ---------------------------------------------------------------------------\n\n/** Auth paths where a non-2xx response means a failed attempt worth logging */\nconst SIGN_IN_PATHS = ['/sign-in/email', '/sign-in/social']\n\n/** Auth paths for session/password lifecycle events */\nconst SIGN_OUT_PATH = '/sign-out'\nconst PASSWORD_PATHS: Record<string, string> = {\n '/change-password': 'auth.password.change',\n '/forget-password': 'auth.password.reset_request',\n '/reset-password': 'auth.password.reset',\n}\n\n/** Paths that should be audit-logged when successful */\nconst AUDIT_ADMIN_PATHS: Record<string, string> = {\n '/admin/set-role': 'auth.admin.set_role',\n '/admin/ban-user': 'auth.admin.ban',\n '/admin/unban-user': 'auth.admin.unban',\n '/admin/create-user': 'auth.admin.create_user',\n '/admin/remove-user': 'auth.admin.remove_user',\n '/admin/impersonate-user': 'auth.admin.impersonate',\n '/admin/stop-impersonating': 'auth.admin.stop_impersonating',\n '/admin/revoke-session': 'auth.admin.revoke_session',\n '/admin/revoke-sessions': 'auth.admin.revoke_sessions',\n}\n\nfunction buildRequestHooks(auditLogger: AuditLogger) {\n function audit(entry: Parameters<AuditLogger['log']>[0]) {\n auditLogger.log(entry).catch(() => {})\n }\n\n return {\n after: createAuthMiddleware(async (ctx) => {\n // --- Login attempt logging ---\n const isSignIn = SIGN_IN_PATHS.some((p) => ctx.path.startsWith(p))\n if (isSignIn) {\n const returned = ctx.context.returned as { status?: number } | undefined\n const status = returned?.status\n if (!status) return\n\n if (status >= 400) {\n const email = (ctx.body as Record<string, unknown> | undefined)?.email\n audit({\n action: 'auth.login.failed',\n metadata: {\n ...(typeof email === 'string' ? { email } : {}),\n status,\n path: ctx.path,\n },\n })\n } else {\n const newSession = ctx.context.newSession as\n | { user?: { id?: string; name?: string } }\n | undefined\n if (newSession?.user?.id) {\n audit({\n action: 'auth.login',\n entityType: 'user',\n entityId: newSession.user.id,\n userId: newSession.user.id,\n userName: newSession.user.name,\n })\n }\n }\n return\n }\n\n // --- Logout logging ---\n if (ctx.path === SIGN_OUT_PATH) {\n const returned = ctx.context.returned as { status?: number } | undefined\n if (!returned?.status || returned.status < 400) {\n const actor = getActor(ctx)\n if (actor.id) {\n audit({\n action: 'auth.logout',\n entityType: 'user',\n entityId: actor.id,\n userId: actor.id,\n userName: actor.name,\n })\n }\n }\n return\n }\n\n // --- Password change/reset logging ---\n const passwordAction = PASSWORD_PATHS[ctx.path]\n if (passwordAction) {\n const returned = ctx.context.returned as { status?: number } | undefined\n if (!returned?.status || returned.status < 400) {\n const actor = getActor(ctx)\n const body = ctx.body as Record<string, unknown> | undefined\n audit({\n action: passwordAction,\n entityType: 'user',\n userId: actor.id,\n userName: actor.name,\n metadata: {\n // For reset requests, log the email (not sensitive — it's the input)\n ...(typeof body?.email === 'string' ? { email: body.email } : {}),\n path: ctx.path,\n },\n })\n }\n return\n }\n\n // --- Admin operation audit logging (impersonation, role changes, bans, etc.) ---\n const auditAction = AUDIT_ADMIN_PATHS[ctx.path]\n if (!auditAction) return\n\n const returned = ctx.context.returned as { status?: number } | undefined\n if (returned?.status && returned.status >= 400) return // failed — skip\n\n const actor = getActor(ctx)\n const body = ctx.body as Record<string, unknown> | undefined\n audit({\n action: auditAction,\n entityType: 'user',\n entityId: (body?.userId as string) ?? undefined,\n userId: actor.id,\n userName: actor.name,\n metadata: {\n targetUserId: body?.userId as string | undefined,\n ...(body?.role ? { role: body.role as string } : {}),\n path: ctx.path,\n },\n })\n }),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signup gate — closes registration after the first user exists\n// ---------------------------------------------------------------------------\n\nfunction buildSignupGate(db: ToolkitApp['db']) {\n return createAuthMiddleware(async (ctx) => {\n if (ctx.path !== '/sign-up/email') return\n const result = await db.readWrite.execute<{ count: string }>(\n drizzleSql`SELECT COUNT(*)::text as count FROM \"user\"`,\n )\n if (Number(result[0]?.count) > 0) {\n throw new APIError('FORBIDDEN', { message: 'Sign-up is closed' })\n }\n })\n}\n\n// ---------------------------------------------------------------------------\n// Server factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a better-auth server instance wired to the toolkit.\n *\n * Called during plugin init — the returned instance powers:\n * - `auth.api.getSession()` for session resolution\n * - `auth.api.listUsers()` for admin user management\n * - Route handler via `toNextJsHandler(auth)`\n *\n * IMPORTANT: Plugins are inlined in the `betterAuth()` call so TypeScript\n * preserves the literal plugin types. Extracting them into a `BetterAuthPlugin[]`\n * variable erases specific endpoint types (admin, organization, etc.).\n *\n * The explicit `BetterAuthBase` return type annotation is required because\n * better-auth 1.6's internals use zod@4 types that tsdown's dts generator\n * cannot name portably across pnpm's `.pnpm/zod@4.x` symlink paths (TS2742).\n * The annotation widens to better-auth's generic `Auth` type — specific\n * plugin endpoint types (`auth.api.listUsers` etc.) are still accessible\n * because better-auth's `InferAPI` helper resolves them at the consumer's\n * compile time against their installed better-auth version.\n */\nexport function createAuthServer(\n config: AuthConfig,\n app: ToolkitApp,\n auditLogger?: AuditLogger,\n): BetterAuthBase {\n const entities = [...app.entities.values()]\n const statement = buildStatements(entities)\n const ac = createAccessControl(statement)\n const roles: Record<string, Role> = buildDefaultRoles(ac, entities)\n\n // Build social provider config\n const socialProviders: Record<string, { clientId: string; clientSecret: string }> = {}\n if (config.social?.google) {\n socialProviders.google = config.social.google\n }\n if (config.social?.github) {\n socialProviders.github = config.social.github\n }\n\n // Plugins are inlined so TS infers the literal tuple type.\n // DO NOT extract into a typed variable — `BetterAuthPlugin[]` erases endpoint types.\n // nextCookies() must be last — required for Next.js server actions.\n // Default to the pre-baked schema from `@murumets-ee/auth/schema` so\n // consumers don't need to generate one with `@better-auth/cli`. They\n // can still override via `auth({ schema: customSchema })` if they've\n // extended better-auth with plugins that add tables.\n const schema = config.schema ?? defaultAuthSchema\n return betterAuth({\n database: drizzleAdapter(app.db.readWrite, {\n provider: 'pg',\n schema,\n }),\n\n emailAndPassword: {\n enabled: config.providers?.includes('email') ?? true,\n },\n\n socialProviders,\n\n session: {\n expiresIn: config.session?.expiresIn ?? 60 * 60 * 2, // 2 hours (admin CMS — short-lived)\n updateAge: config.session?.updateAge ?? 60 * 60, // 1 hour\n },\n\n // Rate limiting — strict on sensitive paths, relaxed global default\n rateLimit: {\n enabled: true,\n window: 60, // 60s global window\n max: 100, // 100 req/min default\n storage: 'memory',\n customRules: {\n '/sign-in/email': { window: 60, max: 5 }, // 5 login attempts/min\n '/sign-in/social': { window: 60, max: 10 },\n '/sign-up/email': { window: 60, max: 3 }, // 3 signups/min\n '/forget-password': { window: 60, max: 3 }, // 3 resets/min\n '/reset-password': { window: 60, max: 5 },\n '/admin/*': { window: 60, max: 20 }, // admin ops capped\n },\n },\n\n databaseHooks: buildDatabaseHooks(app.db, auditLogger),\n hooks: {\n before: buildSignupGate(app.db),\n ...(auditLogger ? buildRequestHooks(auditLogger) : {}),\n },\n\n plugins: [\n admin({ ac, roles, defaultRole: 'authenticated' }),\n ...(config.organizations ? [organization({ ac, roles })] : []),\n ...(config.betterAuthPlugins ?? []),\n nextCookies(),\n ],\n })\n}\n\n/** Type of the auth server instance. Aliased from better-auth's generic\n * `Auth` because the explicit annotation on `createAuthServer` means\n * `ReturnType<typeof createAuthServer>` is already `BetterAuthBase`. */\nexport type Auth = BetterAuthBase\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server-B7Gdv2He.mjs","names":["defaultAuthSchema"],"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-side auth instance factory.\n *\n * Creates a configured `betterAuth()` instance using the toolkit's database\n * connection and entity definitions. This is server-only code.\n */\n\nimport type { ToolkitApp } from '@murumets-ee/core'\nimport type { AuditLogger } from '@murumets-ee/logging'\nimport type { Auth as BetterAuthBase, BetterAuthOptions } from 'better-auth'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\nimport { APIError, createAuthMiddleware } from 'better-auth/api'\nimport { nextCookies } from 'better-auth/next-js'\nimport { admin } from 'better-auth/plugins'\nimport type { Role } from 'better-auth/plugins/access'\nimport { createAccessControl } from 'better-auth/plugins/access'\nimport { organization } from 'better-auth/plugins/organization'\nimport { sql as drizzleSql } from 'drizzle-orm'\nimport { buildDefaultRoles, buildStatements } from './permissions.js'\nimport * as defaultAuthSchema from './schema.js'\nimport type { AdminUser, AuthConfig } from './types.js'\n\n// ---------------------------------------------------------------------------\n// Audit hooks — wired into better-auth's databaseHooks\n// ---------------------------------------------------------------------------\n\n/** Extract acting admin's id and name from better-auth hook context.\n * ctx is GenericEndpointContext | null — we access session safely via optional chaining. */\nfunction getActor(ctx: unknown) {\n const session = (ctx as { context?: { session?: Record<string, unknown> } } | null)?.context\n ?.session\n const user = session?.user as { id?: string; name?: string } | undefined\n return {\n id: user?.id ?? (session?.userId as string | undefined),\n name: user?.name,\n }\n}\n\n/** Fields to strip from user update audit payloads */\nconst SKIP_FIELDS = new Set(['updatedAt', 'createdAt'])\n\nfunction buildDatabaseHooks(db: ToolkitApp['db'], auditLogger?: AuditLogger) {\n /** Fire-and-forget audit — never block auth operations */\n function audit(entry: Parameters<AuditLogger['log']>[0]) {\n auditLogger?.log(entry).catch(() => {})\n }\n\n // `before` captures changed fields, `after` has full user + actor ctx.\n // Bridge with a simple variable — updates are sequential per request.\n let pendingFields: Record<string, unknown> | null = null\n\n return {\n user: {\n create: {\n after: async (user: Record<string, unknown>) => {\n // Auto-promote first user to admin (fresh DB setup).\n // Single atomic statement — if two signups race, only one sees count=1.\n try {\n await db.readWrite.execute(\n drizzleSql`UPDATE \"user\" SET role = 'admin' WHERE id = ${user.id as string} AND (SELECT COUNT(*) FROM \"user\") = 1`,\n )\n } catch {\n // Non-fatal — don't block signup if promotion fails\n }\n\n // Signup — actor is the new user themselves\n audit({\n action: 'auth.signup',\n entityType: 'user',\n entityId: user.id as string,\n userId: user.id as string,\n userName: user.name as string,\n changes: {\n fields: { name: user.name, email: user.email },\n },\n })\n },\n },\n update: {\n // `before` receives only the changed fields — capture them\n before: async (userData: Record<string, unknown>) => {\n const fields: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(userData)) {\n if (SKIP_FIELDS.has(key) || key === 'id') continue\n fields[key] = value\n }\n pendingFields = Object.keys(fields).length > 0 ? fields : null\n },\n // `after` has full user (name) + ctx (actor session) — log everything\n after: async (user: Record<string, unknown>, ctx: unknown) => {\n const actor = getActor(ctx)\n const fields = pendingFields\n pendingFields = null\n audit({\n action: 'auth.user.update',\n entityType: 'user',\n entityId: user.id as string,\n userId: actor.id,\n userName: actor.name,\n changes: fields ? { fields } : undefined,\n metadata: {\n targetUser: user.name as string | undefined,\n },\n })\n },\n },\n delete: {\n after: async (user: Record<string, unknown>, ctx: unknown) => {\n const actor = getActor(ctx)\n audit({\n action: 'auth.user.delete',\n entityType: 'user',\n entityId: user.id as string,\n userId: actor.id,\n userName: actor.name,\n metadata: {\n targetUser: user.name as string | undefined,\n },\n })\n },\n },\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Request-level hooks — catches failed logins, password changes, etc.\n// ---------------------------------------------------------------------------\n\n/** Auth paths where a non-2xx response means a failed attempt worth logging */\nconst SIGN_IN_PATHS = ['/sign-in/email', '/sign-in/social']\n\n/** Auth paths for session/password lifecycle events */\nconst SIGN_OUT_PATH = '/sign-out'\nconst PASSWORD_PATHS: Record<string, string> = {\n '/change-password': 'auth.password.change',\n '/forget-password': 'auth.password.reset_request',\n '/reset-password': 'auth.password.reset',\n}\n\n/** Paths that should be audit-logged when successful */\nconst AUDIT_ADMIN_PATHS: Record<string, string> = {\n '/admin/set-role': 'auth.admin.set_role',\n '/admin/ban-user': 'auth.admin.ban',\n '/admin/unban-user': 'auth.admin.unban',\n '/admin/create-user': 'auth.admin.create_user',\n '/admin/remove-user': 'auth.admin.remove_user',\n '/admin/impersonate-user': 'auth.admin.impersonate',\n '/admin/stop-impersonating': 'auth.admin.stop_impersonating',\n '/admin/revoke-session': 'auth.admin.revoke_session',\n '/admin/revoke-sessions': 'auth.admin.revoke_sessions',\n}\n\nfunction buildRequestHooks(auditLogger: AuditLogger) {\n function audit(entry: Parameters<AuditLogger['log']>[0]) {\n auditLogger.log(entry).catch(() => {})\n }\n\n return {\n after: createAuthMiddleware(async (ctx) => {\n // --- Login attempt logging ---\n const isSignIn = SIGN_IN_PATHS.some((p) => ctx.path.startsWith(p))\n if (isSignIn) {\n const returned = ctx.context.returned as { status?: number } | undefined\n const status = returned?.status\n if (!status) return\n\n if (status >= 400) {\n const email = (ctx.body as Record<string, unknown> | undefined)?.email\n audit({\n action: 'auth.login.failed',\n metadata: {\n ...(typeof email === 'string' ? { email } : {}),\n status,\n path: ctx.path,\n },\n })\n } else {\n const newSession = ctx.context.newSession as\n | { user?: { id?: string; name?: string } }\n | undefined\n if (newSession?.user?.id) {\n audit({\n action: 'auth.login',\n entityType: 'user',\n entityId: newSession.user.id,\n userId: newSession.user.id,\n userName: newSession.user.name,\n })\n }\n }\n return\n }\n\n // --- Logout logging ---\n if (ctx.path === SIGN_OUT_PATH) {\n const returned = ctx.context.returned as { status?: number } | undefined\n if (!returned?.status || returned.status < 400) {\n const actor = getActor(ctx)\n if (actor.id) {\n audit({\n action: 'auth.logout',\n entityType: 'user',\n entityId: actor.id,\n userId: actor.id,\n userName: actor.name,\n })\n }\n }\n return\n }\n\n // --- Password change/reset logging ---\n const passwordAction = PASSWORD_PATHS[ctx.path]\n if (passwordAction) {\n const returned = ctx.context.returned as { status?: number } | undefined\n if (!returned?.status || returned.status < 400) {\n const actor = getActor(ctx)\n const body = ctx.body as Record<string, unknown> | undefined\n audit({\n action: passwordAction,\n entityType: 'user',\n userId: actor.id,\n userName: actor.name,\n metadata: {\n // For reset requests, log the email (not sensitive — it's the input)\n ...(typeof body?.email === 'string' ? { email: body.email } : {}),\n path: ctx.path,\n },\n })\n }\n return\n }\n\n // --- Admin operation audit logging (impersonation, role changes, bans, etc.) ---\n const auditAction = AUDIT_ADMIN_PATHS[ctx.path]\n if (!auditAction) return\n\n const returned = ctx.context.returned as { status?: number } | undefined\n if (returned?.status && returned.status >= 400) return // failed — skip\n\n const actor = getActor(ctx)\n const body = ctx.body as Record<string, unknown> | undefined\n audit({\n action: auditAction,\n entityType: 'user',\n entityId: (body?.userId as string) ?? undefined,\n userId: actor.id,\n userName: actor.name,\n metadata: {\n targetUserId: body?.userId as string | undefined,\n ...(body?.role ? { role: body.role as string } : {}),\n path: ctx.path,\n },\n })\n }),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signup gate — closes registration after the first user exists\n// ---------------------------------------------------------------------------\n\nfunction buildSignupGate(db: ToolkitApp['db']) {\n return createAuthMiddleware(async (ctx) => {\n if (ctx.path !== '/sign-up/email') return\n const result = await db.readWrite.execute<{ count: string }>(\n drizzleSql`SELECT COUNT(*)::text as count FROM \"user\"`,\n )\n if (Number(result[0]?.count) > 0) {\n throw new APIError('FORBIDDEN', { message: 'Sign-up is closed' })\n }\n })\n}\n\n// ---------------------------------------------------------------------------\n// Server factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a better-auth server instance wired to the toolkit.\n *\n * Called during plugin init — the returned instance powers:\n * - `auth.api.getSession()` for session resolution\n * - `auth.api.listUsers()` for admin user management\n * - Route handler via `toNextJsHandler(auth)`\n *\n * IMPORTANT: Plugins are inlined in the `betterAuth()` call so TypeScript\n * preserves the literal plugin types. Extracting them into a `BetterAuthPlugin[]`\n * variable erases specific endpoint types (admin, organization, etc.).\n *\n * The explicit `BetterAuthBase` return type annotation is required because\n * better-auth 1.6's internals use zod@4 types that tsdown's dts generator\n * cannot name portably across pnpm's `.pnpm/zod@4.x` symlink paths (TS2742).\n * The annotation widens to better-auth's generic `Auth` type — specific\n * plugin endpoint types (`auth.api.listUsers` etc.) are still accessible\n * because better-auth's `InferAPI` helper resolves them at the consumer's\n * compile time against their installed better-auth version.\n */\nexport function createAuthServer(\n config: AuthConfig,\n app: ToolkitApp,\n auditLogger?: AuditLogger,\n): BetterAuthBase {\n const entities = [...app.entities.values()]\n const statement = buildStatements(entities)\n const ac = createAccessControl(statement)\n const roles: Record<string, Role> = buildDefaultRoles(ac, entities)\n\n // Build social provider config\n const socialProviders: Record<string, { clientId: string; clientSecret: string }> = {}\n if (config.social?.google) {\n socialProviders.google = config.social.google\n }\n if (config.social?.github) {\n socialProviders.github = config.social.github\n }\n\n // Plugins are inlined so TS infers the literal tuple type.\n // DO NOT extract into a typed variable — `BetterAuthPlugin[]` erases endpoint types.\n // nextCookies() must be last — required for Next.js server actions.\n // Default to the pre-baked schema from `@murumets-ee/auth/schema` so\n // consumers don't need to generate one with `@better-auth/cli`. They\n // can still override via `auth({ schema: customSchema })` if they've\n // extended better-auth with plugins that add tables.\n const schema = config.schema ?? defaultAuthSchema\n\n // Widen the config to BetterAuthOptions so betterAuth() returns\n // Auth<BetterAuthOptions> (= BetterAuthBase). This is required because:\n // 1. Without a return type annotation, tsdown fails with TS2742\n // (zod@4 internal types can't be named portably in .d.mts)\n // 2. The admin plugin with custom ac/roles makes Auth<SpecificConfig>\n // structurally incompatible with Auth (better-auth#8855)\n // Widening the config erases plugin-specific API types at compile time,\n // but plugin endpoints (listUsers, etc.) are fully functional at runtime.\n // Consumers already access them via typed wrappers in AdminPagesConfig.\n const authOptions: BetterAuthOptions = {\n database: drizzleAdapter(app.db.readWrite, {\n provider: 'pg',\n schema,\n }),\n\n emailAndPassword: {\n enabled: config.providers?.includes('email') ?? true,\n },\n\n socialProviders,\n\n session: {\n expiresIn: config.session?.expiresIn ?? 60 * 60 * 2, // 2 hours (admin CMS — short-lived)\n updateAge: config.session?.updateAge ?? 60 * 60, // 1 hour\n },\n\n // Rate limiting — strict on sensitive paths, relaxed global default\n rateLimit: {\n enabled: true,\n window: 60, // 60s global window\n max: 100, // 100 req/min default\n storage: 'memory',\n customRules: {\n '/sign-in/email': { window: 60, max: 5 }, // 5 login attempts/min\n '/sign-in/social': { window: 60, max: 10 },\n '/sign-up/email': { window: 60, max: 3 }, // 3 signups/min\n '/forget-password': { window: 60, max: 3 }, // 3 resets/min\n '/reset-password': { window: 60, max: 5 },\n '/admin/*': { window: 60, max: 20 }, // admin ops capped\n },\n },\n\n databaseHooks: buildDatabaseHooks(app.db, auditLogger),\n hooks: {\n before: buildSignupGate(app.db),\n ...(auditLogger ? buildRequestHooks(auditLogger) : {}),\n },\n\n plugins: [\n admin({ ac, roles, defaultRole: 'authenticated' }),\n ...(config.organizations ? [organization({ ac, roles })] : []),\n ...(config.betterAuthPlugins ?? []),\n nextCookies(),\n ],\n }\n\n return betterAuth(authOptions)\n}\n\n/** Type of the auth server instance. Aliased from better-auth's generic\n * `Auth` because the explicit annotation on `createAuthServer` means\n * `ReturnType<typeof createAuthServer>` is already `BetterAuthBase`. */\nexport type Auth = BetterAuthBase\n\n/**\n * Structural interface for the server-side admin API methods.\n *\n * The widened `Auth` type (BetterAuthBase) doesn't expose admin plugin\n * endpoints. This interface describes just the methods consumers need\n * so they can access them without `as any`.\n *\n * Usage: `(auth.api as AuthAdminApi).listUsers(...)`\n */\nexport interface AuthAdminApi {\n listUsers: (opts: {\n headers: Headers\n query: {\n limit: number\n sortBy: string\n sortDirection: 'asc' | 'desc'\n }\n }) => Promise<{ users: AdminUser[]; total: number }>\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { BetterAuthPlugin } from "better-auth";
|
|
2
|
+
|
|
3
3
|
//#region src/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* better-auth base user fields + admin plugin fields.
|
|
6
|
+
* Base: id, createdAt, updatedAt, email, emailVerified, name, image
|
|
7
|
+
* Admin plugin adds: role, banned, banReason, banExpires
|
|
8
|
+
*
|
|
9
|
+
* Defined here (not in server.ts) so client.ts can import it
|
|
10
|
+
* without crossing the server-only boundary.
|
|
11
|
+
*/
|
|
12
|
+
interface AdminUser {
|
|
13
|
+
id: string;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
email: string;
|
|
17
|
+
emailVerified: boolean;
|
|
18
|
+
name: string;
|
|
19
|
+
image?: string | null;
|
|
20
|
+
role?: string | null;
|
|
21
|
+
banned: boolean | null;
|
|
22
|
+
banReason?: string | null;
|
|
23
|
+
banExpires?: Date | null;
|
|
24
|
+
}
|
|
4
25
|
/**
|
|
5
26
|
* Auth plugin configuration
|
|
6
27
|
*/
|
|
@@ -46,45 +67,5 @@ interface AuthConfig {
|
|
|
46
67
|
audit?: false;
|
|
47
68
|
}
|
|
48
69
|
//#endregion
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* `Auth` because the explicit annotation on `createAuthServer` means
|
|
52
|
-
* `ReturnType<typeof createAuthServer>` is already `BetterAuthBase`. */
|
|
53
|
-
type Auth$1 = Auth;
|
|
54
|
-
//#endregion
|
|
55
|
-
//#region src/plugin.d.ts
|
|
56
|
-
/**
|
|
57
|
-
* Get the auth server instance.
|
|
58
|
-
* Throws if the auth plugin hasn't been initialized yet.
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```typescript
|
|
62
|
-
* // app/api/auth/[...all]/route.ts (user writes this)
|
|
63
|
-
* import { toNextJsHandler } from 'better-auth/next-js'
|
|
64
|
-
* import { getAuth } from '@murumets-ee/auth'
|
|
65
|
-
*
|
|
66
|
-
* export const { GET, POST } = toNextJsHandler(getAuth())
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
declare function getAuth(): Auth$1;
|
|
70
|
-
/**
|
|
71
|
-
* Create the auth toolkit plugin.
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```typescript
|
|
75
|
-
* import { defineConfig } from '@murumets-ee/core'
|
|
76
|
-
* import { auth } from '@murumets-ee/auth'
|
|
77
|
-
*
|
|
78
|
-
* export default defineConfig({
|
|
79
|
-
* db: { url: process.env.DATABASE_URL! },
|
|
80
|
-
* entities: [Article, Category],
|
|
81
|
-
* plugins: [
|
|
82
|
-
* auth({ providers: ['email'] }),
|
|
83
|
-
* ],
|
|
84
|
-
* })
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
declare function auth(config?: AuthConfig): Plugin;
|
|
88
|
-
//#endregion
|
|
89
|
-
export { AuthConfig as i, getAuth as n, Auth$1 as r, auth as t };
|
|
90
|
-
//# sourceMappingURL=plugin-BS-ho4BN.d.mts.map
|
|
70
|
+
export { AuthConfig as n, AdminUser as t };
|
|
71
|
+
//# sourceMappingURL=types-Dxs8Jhxs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-Dxs8Jhxs.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;AAUA;;;;;;UAAiB,SAAA;EACf,EAAA;EACA,SAAA,EAAW,IAAA;EACX,SAAA,EAAW,IAAA;EACX,KAAA;EACA,aAAA;EACA,IAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA,GAAa,IAAA;AAAA;;;;UAME,UAAA;EANE;EAQjB,SAAA;EAFyB;EAKzB,MAAA;IACE,MAAA;MAAW,QAAA;MAAkB,YAAA;IAAA;IAC7B,MAAA;MAAW,QAAA;MAAkB,YAAA;IAAA;EAAA;EAI/B;EAAA,OAAA;IAIE,2DAFA,SAAA,WAeF;IAbE,SAAA;EAAA;EAmBkB;EAfpB,aAAA;EAsBK;;;;;;;EAbL,MAAA,GAAS,MAAA;;;;;EAMT,iBAAA,GAAoB,gBAAA;;;;;;EAOpB,KAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@murumets-ee/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,25 +28,25 @@
|
|
|
28
28
|
"files": [
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsdown",
|
|
33
|
+
"dev": "tsdown --watch",
|
|
34
|
+
"test": "vitest",
|
|
35
|
+
"gen:schema": "npx @better-auth/cli generate --config scripts/schema-source.ts --output src/schema.ts -y"
|
|
36
|
+
},
|
|
31
37
|
"dependencies": {
|
|
38
|
+
"@murumets-ee/core": "workspace:*",
|
|
39
|
+
"@murumets-ee/db": "workspace:*",
|
|
40
|
+
"@murumets-ee/entity": "workspace:*",
|
|
41
|
+
"@murumets-ee/logging": "workspace:*",
|
|
32
42
|
"better-auth": "^1.6.2",
|
|
33
43
|
"drizzle-orm": "^0.45.0",
|
|
34
|
-
"server-only": "^0.0.1"
|
|
35
|
-
"@murumets-ee/db": "0.2.0",
|
|
36
|
-
"@murumets-ee/entity": "0.2.1",
|
|
37
|
-
"@murumets-ee/logging": "0.2.0",
|
|
38
|
-
"@murumets-ee/core": "0.2.0"
|
|
44
|
+
"server-only": "^0.0.1"
|
|
39
45
|
},
|
|
40
46
|
"devDependencies": {
|
|
41
47
|
"@types/node": "^22.10.5",
|
|
42
48
|
"tsdown": "^0.21.7",
|
|
43
49
|
"typescript": "^5.7.3",
|
|
44
50
|
"vitest": "^2.1.8"
|
|
45
|
-
},
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "tsdown",
|
|
48
|
-
"dev": "tsdown --watch",
|
|
49
|
-
"test": "vitest",
|
|
50
|
-
"gen:schema": "npx @better-auth/cli generate --config scripts/schema-source.ts --output src/schema.ts -y"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
Elastic License 2.0 (ELv2)
|
|
2
|
-
|
|
3
|
-
URL: https://www.elastic.co/licensing/elastic-license
|
|
4
|
-
|
|
5
|
-
## Acceptance
|
|
6
|
-
|
|
7
|
-
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
-
|
|
9
|
-
## Copyright License
|
|
10
|
-
|
|
11
|
-
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
-
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
13
|
-
available, and prepare derivative works of the software, in each case subject
|
|
14
|
-
to the limitations and conditions below.
|
|
15
|
-
|
|
16
|
-
## Limitations
|
|
17
|
-
|
|
18
|
-
You may not provide the software to third parties as a hosted or managed
|
|
19
|
-
service, where the service provides users with access to any substantial set
|
|
20
|
-
of the features or functionality of the software.
|
|
21
|
-
|
|
22
|
-
You may not move, change, disable, or circumvent the license key functionality
|
|
23
|
-
in the software, and you may not remove or obscure any functionality in the
|
|
24
|
-
software that is protected by the license key.
|
|
25
|
-
|
|
26
|
-
You may not alter, remove, or obscure any licensing, copyright, or other
|
|
27
|
-
notices of the licensor in the software. Any use of the licensor's trademarks
|
|
28
|
-
is subject to applicable law.
|
|
29
|
-
|
|
30
|
-
## Patents
|
|
31
|
-
|
|
32
|
-
The licensor grants you a license, under any patent claims the licensor can
|
|
33
|
-
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
34
|
-
sale, import and have imported the software, in each case subject to the
|
|
35
|
-
limitations and conditions in this license. This license does not cover any
|
|
36
|
-
patent claims that you cause to be infringed by modifications or additions to
|
|
37
|
-
the software. If you or your company make any written claim that the software
|
|
38
|
-
infringes or contributes to infringement of any patent, your patent license
|
|
39
|
-
for the software granted under these terms ends immediately. If your company
|
|
40
|
-
makes such a claim, your patent license ends immediately for work on behalf
|
|
41
|
-
of your company.
|
|
42
|
-
|
|
43
|
-
## Notices
|
|
44
|
-
|
|
45
|
-
You must ensure that anyone who gets a copy of any part of the software from
|
|
46
|
-
you also gets a copy of these terms.
|
|
47
|
-
|
|
48
|
-
If you modify the software, you must include in any modified copies of the
|
|
49
|
-
software prominent notices stating that you have modified the software.
|
|
50
|
-
|
|
51
|
-
## No Other Rights
|
|
52
|
-
|
|
53
|
-
These terms do not imply any licenses other than those expressly granted in
|
|
54
|
-
these terms.
|
|
55
|
-
|
|
56
|
-
## Termination
|
|
57
|
-
|
|
58
|
-
If you use the software in violation of these terms, such use is not licensed,
|
|
59
|
-
and your licenses will automatically terminate. If the licensor provides you
|
|
60
|
-
with a notice of your violation, and you cease all violation of this license
|
|
61
|
-
no later than 30 days after you receive that notice, your licenses will be
|
|
62
|
-
reinstated retroactively. However, if you violate these terms after such
|
|
63
|
-
reinstatement, any additional violation of these terms will cause your
|
|
64
|
-
licenses to terminate automatically and permanently.
|
|
65
|
-
|
|
66
|
-
## No Liability
|
|
67
|
-
|
|
68
|
-
As far as the law allows, the software comes as is, without any warranty or
|
|
69
|
-
condition, and the licensor will not be liable to you for any damages arising
|
|
70
|
-
out of these terms or the use or nature of the software, under any kind of
|
|
71
|
-
legal claim.
|
|
72
|
-
|
|
73
|
-
## Definitions
|
|
74
|
-
|
|
75
|
-
The **licensor** is the entity offering these terms, and the **software** is
|
|
76
|
-
the software the licensor makes available under these terms, including any
|
|
77
|
-
portion of it.
|
|
78
|
-
|
|
79
|
-
**you** refers to the individual or entity agreeing to these terms.
|
|
80
|
-
|
|
81
|
-
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
82
|
-
organization that you work for, plus all organizations that have control over,
|
|
83
|
-
are under the control of, or are under common control with that organization.
|
|
84
|
-
**control** means ownership of substantially all the assets of an entity, or
|
|
85
|
-
the power to direct the management and policies of an entity (for example, by
|
|
86
|
-
voting right, contract, or otherwise). Control can be direct or indirect.
|
|
87
|
-
|
|
88
|
-
**your licenses** are all the licenses granted to you for the software under
|
|
89
|
-
these terms.
|
|
90
|
-
|
|
91
|
-
**use** means anything you do with the software requiring one of your
|
|
92
|
-
licenses.
|
|
93
|
-
|
|
94
|
-
**trademark** means trademarks, service marks, and similar rights.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-BS-ho4BN.d.mts","names":[],"sources":["../src/types.ts","../src/server.ts","../src/plugin.ts"],"mappings":";;;;;;UAKiB,UAAA;EAAA;EAEf,SAAA;;EAGA,MAAA;IACE,MAAA;MAAW,QAAA;MAAkB,YAAA;IAAA;IAC7B,MAAA;MAAW,QAAA;MAAkB,YAAA;IAAA;EAAA;EAM7B;EAFF,OAAA;IAQA,2DANE,SAAA,WAeO;IAbP,SAAA;EAAA;EA0BF;EAtBA,aAAA;EAsBK;;;;AC4UP;;;EDzVE,MAAA,GAAS,MAAA;ECyVsB;;;;EDnV/B,iBAAA,GAAoB,gBAAA;EEFC;;;;AAwBvB;EFfE,KAAA;AAAA;;;AC4UF;;;AAAA,KAAY,MAAA,GAAO,IAAA;;;;;;;;;;;;;;;;iBCrVH,OAAA,CAAA,GAAW,MAAA;;;;;;;;;ADqV3B;;;;;;;;ACrVA;iBAwBgB,IAAA,CAAK,MAAA,GAAQ,UAAA,GAAkB,MAAA"}
|