better-auth 1.5.4 → 1.5.6
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/adapters/index.d.mts +25 -1
- package/dist/adapters/index.mjs +9 -1
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/api/index.d.mts +36 -10
- package/dist/api/index.mjs +19 -4
- package/dist/api/index.mjs.map +1 -1
- package/dist/api/middlewares/origin-check.mjs +17 -8
- package/dist/api/middlewares/origin-check.mjs.map +1 -1
- package/dist/api/routes/account.d.mts +1 -1
- package/dist/api/routes/email-verification.d.mts +0 -1
- package/dist/api/routes/password.d.mts +1 -0
- package/dist/api/routes/password.mjs +2 -1
- package/dist/api/routes/password.mjs.map +1 -1
- package/dist/api/routes/session.d.mts +0 -1
- package/dist/api/routes/sign-in.d.mts +16 -2
- package/dist/api/routes/sign-in.mjs +10 -2
- package/dist/api/routes/sign-in.mjs.map +1 -1
- package/dist/api/routes/sign-up.d.mts +0 -1
- package/dist/api/routes/sign-up.mjs +3 -2
- package/dist/api/routes/sign-up.mjs.map +1 -1
- package/dist/api/routes/update-session.d.mts +0 -1
- package/dist/api/routes/update-user.d.mts +0 -1
- package/dist/api/to-auth-endpoints.mjs +49 -12
- package/dist/api/to-auth-endpoints.mjs.map +1 -1
- package/dist/auth/full.d.mts +0 -1
- package/dist/auth/minimal.d.mts +0 -1
- package/dist/client/index.d.mts +3 -4
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/path-to-object.d.mts +9 -2
- package/dist/client/query.mjs +3 -2
- package/dist/client/query.mjs.map +1 -1
- package/dist/client/session-refresh.d.mts +11 -3
- package/dist/client/session-refresh.mjs +13 -8
- package/dist/client/session-refresh.mjs.map +1 -1
- package/dist/client/types.d.mts +0 -1
- package/dist/context/create-context.mjs +4 -1
- package/dist/context/create-context.mjs.map +1 -1
- package/dist/context/helpers.mjs +10 -4
- package/dist/context/helpers.mjs.map +1 -1
- package/dist/cookies/index.d.mts +0 -1
- package/dist/cookies/session-store.d.mts +0 -2
- package/dist/db/get-migration.mjs +3 -2
- package/dist/db/get-migration.mjs.map +1 -1
- package/dist/db/index.d.mts +2 -2
- package/dist/db/internal-adapter.d.mts +2 -1
- package/dist/db/internal-adapter.mjs +1 -1
- package/dist/db/internal-adapter.mjs.map +1 -1
- package/dist/db/schema.d.mts +0 -1
- package/dist/db/with-hooks.d.mts +6 -2
- package/dist/db/with-hooks.mjs +72 -31
- package/dist/db/with-hooks.mjs.map +1 -1
- package/dist/index.d.mts +0 -2
- package/dist/integrations/node.d.mts +0 -1
- package/dist/oauth2/link-account.d.mts +0 -1
- package/dist/plugins/admin/access/statement.d.mts +0 -2
- package/dist/plugins/admin/admin.d.mts +0 -1
- package/dist/plugins/admin/client.d.mts +0 -2
- package/dist/plugins/admin/types.d.mts +0 -2
- package/dist/plugins/anonymous/types.d.mts +0 -1
- package/dist/plugins/email-otp/index.mjs +2 -1
- package/dist/plugins/email-otp/index.mjs.map +1 -1
- package/dist/plugins/email-otp/otp-token.mjs +31 -2
- package/dist/plugins/email-otp/otp-token.mjs.map +1 -1
- package/dist/plugins/email-otp/routes.mjs +60 -59
- package/dist/plugins/email-otp/routes.mjs.map +1 -1
- package/dist/plugins/email-otp/types.d.mts +12 -0
- package/dist/plugins/email-otp/utils.mjs +4 -1
- package/dist/plugins/email-otp/utils.mjs.map +1 -1
- package/dist/plugins/generic-oauth/client.d.mts +0 -1
- package/dist/plugins/generic-oauth/index.d.mts +0 -1
- package/dist/plugins/index.d.mts +0 -3
- package/dist/plugins/jwt/types.d.mts +0 -1
- package/dist/plugins/magic-link/index.d.mts +2 -0
- package/dist/plugins/magic-link/index.mjs +5 -3
- package/dist/plugins/magic-link/index.mjs.map +1 -1
- package/dist/plugins/mcp/index.d.mts +0 -1
- package/dist/plugins/oidc-provider/authorize.mjs +13 -4
- package/dist/plugins/oidc-provider/authorize.mjs.map +1 -1
- package/dist/plugins/oidc-provider/error.mjs +12 -2
- package/dist/plugins/oidc-provider/error.mjs.map +1 -1
- package/dist/plugins/oidc-provider/index.d.mts +0 -1
- package/dist/plugins/oidc-provider/types.d.mts +0 -1
- package/dist/plugins/one-time-token/index.d.mts +0 -1
- package/dist/plugins/organization/access/statement.d.mts +0 -2
- package/dist/plugins/organization/adapter.d.mts +0 -2
- package/dist/plugins/organization/adapter.mjs +2 -2
- package/dist/plugins/organization/adapter.mjs.map +1 -1
- package/dist/plugins/organization/client.d.mts +0 -5
- package/dist/plugins/organization/organization.d.mts +0 -2
- package/dist/plugins/organization/permission.d.mts +0 -1
- package/dist/plugins/organization/routes/crud-access-control.d.mts +0 -2
- package/dist/plugins/organization/routes/crud-invites.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-invites.mjs +1 -1
- package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-members.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-members.mjs +1 -1
- package/dist/plugins/organization/routes/crud-members.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-org.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-team.d.mts +2 -3
- package/dist/plugins/organization/routes/crud-team.mjs +18 -14
- package/dist/plugins/organization/routes/crud-team.mjs.map +1 -1
- package/dist/plugins/organization/schema.d.mts +0 -1
- package/dist/plugins/organization/types.d.mts +0 -2
- package/dist/plugins/phone-number/types.d.mts +0 -1
- package/dist/plugins/siwe/index.d.mts +0 -1
- package/dist/plugins/test-utils/types.d.mts +0 -2
- package/dist/plugins/two-factor/client.d.mts +7 -0
- package/dist/plugins/two-factor/client.mjs +5 -1
- package/dist/plugins/two-factor/client.mjs.map +1 -1
- package/dist/plugins/two-factor/index.mjs +7 -1
- package/dist/plugins/two-factor/index.mjs.map +1 -1
- package/dist/plugins/two-factor/otp/index.d.mts +2 -2
- package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
- package/dist/plugins/two-factor/types.d.mts +7 -1
- package/dist/test-utils/test-instance.d.mts +108 -21
- package/dist/types/index.d.mts +0 -1
- package/package.json +13 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to-auth-endpoints.mjs","names":[],"sources":["../../src/api/to-auth-endpoints.ts"],"sourcesContent":["import type { AuthContext, HookEndpointContext } from \"@better-auth/core\";\nimport type { AuthEndpoint, AuthMiddleware } from \"@better-auth/core/api\";\nimport {\n\thasRequestState,\n\trunWithEndpointContext,\n\trunWithRequestState,\n} from \"@better-auth/core/context\";\nimport { shouldPublishLog } from \"@better-auth/core/env\";\nimport { APIError } from \"@better-auth/core/error\";\nimport type {\n\tEndpointContext,\n\tEndpointOptions,\n\tInputContext,\n} from \"better-call\";\nimport { kAPIErrorHeaderSymbol, toResponse } from \"better-call\";\nimport { createDefu } from \"defu\";\nimport { isAPIError } from \"../utils/is-api-error\";\n\ntype InternalContext = Partial<\n\tInputContext<string, any> & EndpointContext<string, any>\n> & {\n\tpath: string;\n\tasResponse?: boolean | undefined;\n\tcontext: AuthContext & {\n\t\tlogger: AuthContext[\"logger\"];\n\t\treturned?: unknown | undefined;\n\t\tresponseHeaders?: Headers | undefined;\n\t};\n};\n\nconst defuReplaceArrays = createDefu((obj, key, value) => {\n\tif (Array.isArray(obj[key]) && Array.isArray(value)) {\n\t\tobj[key] = value;\n\t\treturn true;\n\t}\n});\n\nconst hooksSourceWeakMap = new WeakMap<\n\tAuthMiddleware,\n\t`user` | `plugin:${string}`\n>();\n\ntype UserInputContext = Partial<\n\tInputContext<string, any> & EndpointContext<string, any>\n>;\n\nexport function toAuthEndpoints<\n\tconst E extends Record<\n\t\tstring,\n\t\tOmit<AuthEndpoint<string, EndpointOptions, any>, \"wrap\">\n\t>,\n>(endpoints: E, ctx: AuthContext | Promise<AuthContext>): E {\n\tconst api: Record<\n\t\tstring,\n\t\t((\n\t\t\tcontext: EndpointContext<string, any> & InputContext<string, any>,\n\t\t) => Promise<any>) & {\n\t\t\tpath?: string | undefined;\n\t\t\toptions?: EndpointOptions | undefined;\n\t\t}\n\t> = {};\n\n\tfor (const [key, endpoint] of Object.entries(endpoints)) {\n\t\tapi[key] = async (context?: UserInputContext) => {\n\t\t\tconst run = async () => {\n\t\t\t\tconst authContext = await ctx;\n\t\t\t\tlet internalContext: InternalContext = {\n\t\t\t\t\t...context,\n\t\t\t\t\tcontext: {\n\t\t\t\t\t\t...authContext,\n\t\t\t\t\t\treturned: undefined,\n\t\t\t\t\t\tresponseHeaders: undefined,\n\t\t\t\t\t\tsession: null,\n\t\t\t\t\t},\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\theaders: context?.headers ? new Headers(context?.headers) : undefined,\n\t\t\t\t};\n\t\t\t\treturn runWithEndpointContext(internalContext, async () => {\n\t\t\t\t\tconst { beforeHooks, afterHooks } = getHooks(authContext);\n\t\t\t\t\tconst before = await runBeforeHooks(internalContext, beforeHooks);\n\t\t\t\t\t/**\n\t\t\t\t\t * If `before.context` is returned, it should\n\t\t\t\t\t * get merged with the original context\n\t\t\t\t\t */\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"context\" in before &&\n\t\t\t\t\t\tbefore.context &&\n\t\t\t\t\t\ttypeof before.context === \"object\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst { headers, ...rest } = before.context as {\n\t\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\t};\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Headers should be merged differently\n\t\t\t\t\t\t * so the hook doesn't override the whole\n\t\t\t\t\t\t * header\n\t\t\t\t\t\t */\n\t\t\t\t\t\tif (headers) {\n\t\t\t\t\t\t\theaders.forEach((value, key) => {\n\t\t\t\t\t\t\t\t(internalContext.headers as Headers).set(key, value);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinternalContext = defuReplaceArrays(rest, internalContext);\n\t\t\t\t\t} else if (before) {\n\t\t\t\t\t\t/* Return before hook response if it's anything other than a context return */\n\t\t\t\t\t\treturn context?.asResponse\n\t\t\t\t\t\t\t? toResponse(before, {\n\t\t\t\t\t\t\t\t\theaders: context?.headers,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: context?.returnHeaders\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\theaders: context?.headers,\n\t\t\t\t\t\t\t\t\t\tresponse: before,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: before;\n\t\t\t\t\t}\n\n\t\t\t\t\tinternalContext.asResponse = false;\n\t\t\t\t\tinternalContext.returnHeaders = true;\n\t\t\t\t\tinternalContext.returnStatus = true;\n\t\t\t\t\tconst result = (await runWithEndpointContext(internalContext, () =>\n\t\t\t\t\t\t(endpoint as any)(internalContext as any),\n\t\t\t\t\t).catch((e: any) => {\n\t\t\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * API Errors from response are caught\n\t\t\t\t\t\t\t * and returned to hooks\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tresponse: e,\n\t\t\t\t\t\t\t\tstatus: e.statusCode,\n\t\t\t\t\t\t\t\theaders: e.headers ? new Headers(e.headers) : null,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t})) as {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tresponse: any;\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t};\n\n\t\t\t\t\t//if response object is returned we skip after hooks and post processing\n\t\t\t\t\tif (result && result instanceof Response) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\tinternalContext.context.returned = result.response;\n\t\t\t\t\tinternalContext.context.responseHeaders = result.headers;\n\n\t\t\t\t\tconst after = await runAfterHooks(internalContext, afterHooks);\n\n\t\t\t\t\tif (after.response) {\n\t\t\t\t\t\tresult.response = after.response;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tisAPIError(result.response) &&\n\t\t\t\t\t\tshouldPublishLog(authContext.logger.level, \"debug\")\n\t\t\t\t\t) {\n\t\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\t\tresult.response.stack = result.response.errorStack;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (isAPIError(result.response) && !context?.asResponse) {\n\t\t\t\t\t\tthrow result.response;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst response = context?.asResponse\n\t\t\t\t\t\t? toResponse(result.response, {\n\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\tstatus: result.status,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: context?.returnHeaders\n\t\t\t\t\t\t\t? context?.returnStatus\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\t\t\tresponse: result.response,\n\t\t\t\t\t\t\t\t\t\tstatus: result.status,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\t\t\tresponse: result.response,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: context?.returnStatus\n\t\t\t\t\t\t\t\t? { response: result.response, status: result.status }\n\t\t\t\t\t\t\t\t: result.response;\n\t\t\t\t\treturn response;\n\t\t\t\t});\n\t\t\t};\n\t\t\tif (await hasRequestState()) {\n\t\t\t\treturn run();\n\t\t\t} else {\n\t\t\t\tconst store = new WeakMap();\n\t\t\t\treturn runWithRequestState(store, run);\n\t\t\t}\n\t\t};\n\t\tapi[key].path = endpoint.path;\n\t\tapi[key].options = endpoint.options;\n\t}\n\treturn api as unknown as E;\n}\n\nasync function runBeforeHooks(\n\tcontext: InternalContext,\n\thooks: {\n\t\tmatcher: (context: HookEndpointContext) => boolean;\n\t\thandler: AuthMiddleware;\n\t}[],\n) {\n\tlet modifiedContext: Partial<InternalContext> = {};\n\n\tfor (const hook of hooks) {\n\t\tlet matched = false;\n\t\ttry {\n\t\t\tmatched = hook.matcher(context);\n\t\t} catch (error) {\n\t\t\t// manually handle unexpected errors during hook matcher execution to prevent accidental exposure of internal details\n\t\t\t// Also provides debug information about which plugin the hook failed and error info\n\t\t\tconst hookSource = hooksSourceWeakMap.get(hook.handler) ?? \"unknown\";\n\t\t\tcontext.context.logger.error(\n\t\t\t\t`An error occurred during ${hookSource} hook matcher execution:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: `An error occurred during hook matcher execution. Check the logs for more details.`,\n\t\t\t});\n\t\t}\n\t\tif (matched) {\n\t\t\tconst result = await hook\n\t\t\t\t.handler({\n\t\t\t\t\t...context,\n\t\t\t\t\treturnHeaders: false,\n\t\t\t\t})\n\t\t\t\t.catch((e: unknown) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tisAPIError(e) &&\n\t\t\t\t\t\tshouldPublishLog(context.context.logger.level, \"debug\")\n\t\t\t\t\t) {\n\t\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\t\te.stack = e.errorStack;\n\t\t\t\t\t}\n\t\t\t\t\tthrow e;\n\t\t\t\t});\n\t\t\tif (result && typeof result === \"object\") {\n\t\t\t\tif (\"context\" in result && typeof result.context === \"object\") {\n\t\t\t\t\tconst { headers, ...rest } =\n\t\t\t\t\t\tresult.context as Partial<InternalContext>;\n\t\t\t\t\tif (headers instanceof Headers) {\n\t\t\t\t\t\tif (modifiedContext.headers) {\n\t\t\t\t\t\t\theaders.forEach((value, key) => {\n\t\t\t\t\t\t\t\tmodifiedContext.headers?.set(key, value);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmodifiedContext.headers = headers;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmodifiedContext = defuReplaceArrays(rest, modifiedContext);\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\treturn { context: modifiedContext };\n}\n\nasync function runAfterHooks(\n\tcontext: InternalContext,\n\thooks: {\n\t\tmatcher: (context: HookEndpointContext) => boolean;\n\t\thandler: AuthMiddleware;\n\t}[],\n) {\n\tfor (const hook of hooks) {\n\t\tif (hook.matcher(context)) {\n\t\t\tconst result = (await hook.handler(context).catch((e) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst headers = (e as any)[kAPIErrorHeaderSymbol] as\n\t\t\t\t\t\t| Headers\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tif (shouldPublishLog(context.context.logger.level, \"debug\")) {\n\t\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\t\te.stack = e.errorStack;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresponse: e,\n\t\t\t\t\t\theaders: headers\n\t\t\t\t\t\t\t? headers\n\t\t\t\t\t\t\t: e.headers\n\t\t\t\t\t\t\t\t? new Headers(e.headers)\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t})) as {\n\t\t\t\tresponse: any;\n\t\t\t\theaders: Headers;\n\t\t\t};\n\t\t\tif (result.headers) {\n\t\t\t\tresult.headers.forEach((value, key) => {\n\t\t\t\t\tif (!context.context.responseHeaders) {\n\t\t\t\t\t\tcontext.context.responseHeaders = new Headers({\n\t\t\t\t\t\t\t[key]: value,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (key.toLowerCase() === \"set-cookie\") {\n\t\t\t\t\t\t\tcontext.context.responseHeaders.append(key, value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.context.responseHeaders.set(key, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (result.response) {\n\t\t\t\tcontext.context.returned = result.response;\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tresponse: context.context.returned,\n\t\theaders: context.context.responseHeaders,\n\t};\n}\n\nfunction getHooks(authContext: AuthContext) {\n\tconst plugins = authContext.options.plugins || [];\n\tconst beforeHooks: {\n\t\tmatcher: (context: HookEndpointContext) => boolean;\n\t\thandler: AuthMiddleware;\n\t}[] = [];\n\tconst afterHooks: {\n\t\tmatcher: (context: HookEndpointContext) => boolean;\n\t\thandler: AuthMiddleware;\n\t}[] = [];\n\tconst beforeHookHandler = authContext.options.hooks?.before;\n\tif (beforeHookHandler) {\n\t\thooksSourceWeakMap.set(beforeHookHandler, \"user\");\n\t\tbeforeHooks.push({\n\t\t\tmatcher: () => true,\n\t\t\thandler: beforeHookHandler,\n\t\t});\n\t}\n\tconst afterHookHandler = authContext.options.hooks?.after;\n\tif (afterHookHandler) {\n\t\thooksSourceWeakMap.set(afterHookHandler, \"user\");\n\t\tafterHooks.push({\n\t\t\tmatcher: () => true,\n\t\t\thandler: afterHookHandler,\n\t\t});\n\t}\n\tconst pluginBeforeHooks = plugins\n\t\t.filter((plugin) => plugin.hooks?.before)\n\t\t.map((plugin) => plugin.hooks?.before!)\n\t\t.flat();\n\tconst pluginAfterHooks = plugins\n\t\t.filter((plugin) => plugin.hooks?.after)\n\t\t.map((plugin) => plugin.hooks?.after!)\n\t\t.flat();\n\n\t/**\n\t * Add plugin added hooks at last\n\t */\n\tif (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks);\n\tif (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks);\n\n\treturn {\n\t\tbeforeHooks,\n\t\tafterHooks,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"to-auth-endpoints.mjs","names":[],"sources":["../../src/api/to-auth-endpoints.ts"],"sourcesContent":["import type { AuthContext, HookEndpointContext } from \"@better-auth/core\";\nimport type { AuthMiddleware } from \"@better-auth/core/api\";\nimport {\n\thasRequestState,\n\trunWithEndpointContext,\n\trunWithRequestState,\n} from \"@better-auth/core/context\";\nimport { shouldPublishLog } from \"@better-auth/core/env\";\nimport { APIError } from \"@better-auth/core/error\";\nimport {\n\tATTR_CONTEXT,\n\tATTR_HOOK_TYPE,\n\tATTR_HTTP_ROUTE,\n\tATTR_OPERATION_ID,\n\twithSpan,\n} from \"@better-auth/core/instrumentation\";\nimport type {\n\tEndpoint,\n\tEndpointContext,\n\tEndpointOptions,\n\tInputContext,\n} from \"better-call\";\nimport { kAPIErrorHeaderSymbol, toResponse } from \"better-call\";\nimport { createDefu } from \"defu\";\nimport { isAPIError } from \"../utils/is-api-error\";\n\ntype InternalContext = Partial<\n\tInputContext<string, any> &\n\t\tEndpointContext<\n\t\t\tstring,\n\t\t\tany,\n\t\t\tAuthContext & {\n\t\t\t\treturned?: unknown | undefined;\n\t\t\t\tresponseHeaders?: Headers | undefined;\n\t\t\t}\n\t\t>\n> & {\n\tpath: string;\n\tasResponse?: boolean | undefined;\n\tcontext: AuthContext & {\n\t\tlogger: AuthContext[\"logger\"];\n\t\treturned?: unknown | undefined;\n\t\tresponseHeaders?: Headers | undefined;\n\t};\n};\n\nconst defuReplaceArrays = createDefu((obj, key, value) => {\n\tif (Array.isArray(obj[key]) && Array.isArray(value)) {\n\t\tobj[key] = value;\n\t\treturn true;\n\t}\n});\n\ntype Hook = {\n\tmatcher: (context: HookEndpointContext) => boolean;\n\thandler: AuthMiddleware;\n};\n\nconst hooksSourceWeakMap = new WeakMap<\n\tAuthMiddleware,\n\t`user` | `plugin:${string}`\n>();\n\nfunction getOperationId(endpoint: Endpoint | undefined, key: string): string {\n\tif (!endpoint?.options) return key;\n\tconst opts = endpoint.options as {\n\t\toperationId?: string;\n\t\tmetadata?: { openapi?: { operationId?: string } };\n\t};\n\treturn opts.operationId ?? opts.metadata?.openapi?.operationId ?? key;\n}\n\ntype UserInputContext = Partial<\n\tInputContext<string, any> & EndpointContext<string, any, any>\n>;\n\nexport function toAuthEndpoints<const E extends Record<string, Endpoint>>(\n\tendpoints: E,\n\tctx: AuthContext | Promise<AuthContext>,\n): E {\n\tconst api: Record<\n\t\tstring,\n\t\t((\n\t\t\tcontext: EndpointContext<string, any, any> & InputContext<string, any>,\n\t\t) => Promise<any>) & {\n\t\t\tpath?: string | undefined;\n\t\t\toptions?: EndpointOptions | undefined;\n\t\t}\n\t> = {};\n\n\tfor (const [key, endpoint] of Object.entries(endpoints)) {\n\t\tapi[key] = async (context?: UserInputContext) => {\n\t\t\tconst operationId = getOperationId(endpoint, key);\n\t\t\tconst endpointMethod = endpoint?.options?.method;\n\t\t\tconst defaultMethod = Array.isArray(endpointMethod)\n\t\t\t\t? endpointMethod[0]\n\t\t\t\t: endpointMethod;\n\n\t\t\tconst run = async () => {\n\t\t\t\tconst authContext = await ctx;\n\t\t\t\tconst methodName =\n\t\t\t\t\tcontext?.method ?? context?.request?.method ?? defaultMethod ?? \"?\";\n\t\t\t\tconst pathName = context?.path ?? endpoint.path ?? \"/:virtual\";\n\n\t\t\t\tlet internalContext: InternalContext = {\n\t\t\t\t\t...context,\n\t\t\t\t\tcontext: {\n\t\t\t\t\t\t...authContext,\n\t\t\t\t\t\treturned: undefined,\n\t\t\t\t\t\tresponseHeaders: undefined,\n\t\t\t\t\t\tsession: null,\n\t\t\t\t\t},\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\theaders: context?.headers ? new Headers(context?.headers) : undefined,\n\t\t\t\t};\n\t\t\t\treturn withSpan(\n\t\t\t\t\t`${methodName} ${pathName}`,\n\t\t\t\t\t{\n\t\t\t\t\t\t[ATTR_HTTP_ROUTE]: pathName,\n\t\t\t\t\t\t[ATTR_OPERATION_ID]: operationId,\n\t\t\t\t\t},\n\t\t\t\t\tasync () =>\n\t\t\t\t\t\trunWithEndpointContext(internalContext, async () => {\n\t\t\t\t\t\t\tconst { beforeHooks, afterHooks } = getHooks(authContext);\n\t\t\t\t\t\t\tconst before = await runBeforeHooks(\n\t\t\t\t\t\t\t\tinternalContext,\n\t\t\t\t\t\t\t\tbeforeHooks,\n\t\t\t\t\t\t\t\tendpoint,\n\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * If `before.context` is returned, it should\n\t\t\t\t\t\t\t * get merged with the original context\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\"context\" in before &&\n\t\t\t\t\t\t\t\tbefore.context &&\n\t\t\t\t\t\t\t\ttypeof before.context === \"object\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tconst { headers, ...rest } = before.context as {\n\t\t\t\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * Headers should be merged differently\n\t\t\t\t\t\t\t\t * so the hook doesn't override the whole\n\t\t\t\t\t\t\t\t * header\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tif (headers) {\n\t\t\t\t\t\t\t\t\theaders.forEach((value, key) => {\n\t\t\t\t\t\t\t\t\t\t(internalContext.headers as Headers).set(key, value);\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tinternalContext = defuReplaceArrays(rest, internalContext);\n\t\t\t\t\t\t\t} else if (before) {\n\t\t\t\t\t\t\t\t/* Return before hook response if it's anything other than a context return */\n\t\t\t\t\t\t\t\treturn context?.asResponse\n\t\t\t\t\t\t\t\t\t? toResponse(before, {\n\t\t\t\t\t\t\t\t\t\t\theaders: context?.headers,\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t: context?.returnHeaders\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\theaders: context?.headers,\n\t\t\t\t\t\t\t\t\t\t\t\tresponse: before,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: before;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tinternalContext.asResponse = false;\n\t\t\t\t\t\t\tinternalContext.returnHeaders = true;\n\t\t\t\t\t\t\tinternalContext.returnStatus = true;\n\t\t\t\t\t\t\tconst result = (await runWithEndpointContext(\n\t\t\t\t\t\t\t\tinternalContext,\n\t\t\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\t\t\twithSpan(\n\t\t\t\t\t\t\t\t\t\t`handler ${pathName}`,\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t[ATTR_HTTP_ROUTE]: pathName,\n\t\t\t\t\t\t\t\t\t\t\t[ATTR_OPERATION_ID]: operationId,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t() => (endpoint as any)(internalContext as any),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t).catch((e: any) => {\n\t\t\t\t\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t\t * API Errors from response are caught\n\t\t\t\t\t\t\t\t\t * and returned to hooks\n\t\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tresponse: e,\n\t\t\t\t\t\t\t\t\t\tstatus: e.statusCode,\n\t\t\t\t\t\t\t\t\t\theaders: e.headers ? new Headers(e.headers) : null,\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t\t})) as {\n\t\t\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\t\t\tresponse: any;\n\t\t\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t//if response object is returned we skip after hooks and post processing\n\t\t\t\t\t\t\tif (result && result instanceof Response) {\n\t\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tinternalContext.context.returned = result.response;\n\t\t\t\t\t\t\tinternalContext.context.responseHeaders = result.headers;\n\n\t\t\t\t\t\t\tconst after = await runAfterHooks(\n\t\t\t\t\t\t\t\tinternalContext,\n\t\t\t\t\t\t\t\tafterHooks,\n\t\t\t\t\t\t\t\tendpoint,\n\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (after.response) {\n\t\t\t\t\t\t\t\tresult.response = after.response;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tisAPIError(result.response) &&\n\t\t\t\t\t\t\t\tshouldPublishLog(authContext.logger.level, \"debug\")\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\t\t\t\tresult.response.stack = result.response.errorStack;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (isAPIError(result.response) && !context?.asResponse) {\n\t\t\t\t\t\t\t\tthrow result.response;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst response = context?.asResponse\n\t\t\t\t\t\t\t\t? toResponse(result.response, {\n\t\t\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\t\t\tstatus: result.status,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t: context?.returnHeaders\n\t\t\t\t\t\t\t\t\t? context?.returnStatus\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\t\t\t\t\tresponse: result.response,\n\t\t\t\t\t\t\t\t\t\t\t\tstatus: result.status,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\t\theaders: result.headers,\n\t\t\t\t\t\t\t\t\t\t\t\tresponse: result.response,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: context?.returnStatus\n\t\t\t\t\t\t\t\t\t\t? { response: result.response, status: result.status }\n\t\t\t\t\t\t\t\t\t\t: result.response;\n\t\t\t\t\t\t\treturn response;\n\t\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t};\n\t\t\tif (await hasRequestState()) {\n\t\t\t\treturn run();\n\t\t\t} else {\n\t\t\t\tconst store = new WeakMap();\n\t\t\t\treturn runWithRequestState(store, run);\n\t\t\t}\n\t\t};\n\t\tapi[key].path = endpoint.path;\n\t\tapi[key].options = endpoint.options;\n\t}\n\treturn api as unknown as E;\n}\n\nasync function runBeforeHooks(\n\tcontext: InternalContext,\n\thooks: Hook[],\n\tendpoint: Endpoint,\n\toperationId: string,\n) {\n\tlet modifiedContext: Partial<InternalContext> = {};\n\n\tfor (const hook of hooks) {\n\t\tlet matched = false;\n\t\ttry {\n\t\t\tmatched = hook.matcher(context);\n\t\t} catch (error) {\n\t\t\t// manually handle unexpected errors during hook matcher execution to prevent accidental exposure of internal details\n\t\t\t// Also provides debug information about which plugin the hook failed and error info\n\t\t\tconst hookSource = hooksSourceWeakMap.get(hook.handler) ?? \"unknown\";\n\t\t\tcontext.context.logger.error(\n\t\t\t\t`An error occurred during ${hookSource} hook matcher execution:`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: `An error occurred during hook matcher execution. Check the logs for more details.`,\n\t\t\t});\n\t\t}\n\t\tif (matched) {\n\t\t\tconst hookSource = hooksSourceWeakMap.get(hook.handler) ?? \"unknown\";\n\t\t\tconst path = context.path ?? endpoint?.path ?? \"/:virtual\";\n\t\t\tconst result = await withSpan(\n\t\t\t\t`hook before ${path} ${hookSource}`,\n\t\t\t\t{\n\t\t\t\t\t[ATTR_HOOK_TYPE]: \"before\",\n\t\t\t\t\t[ATTR_HTTP_ROUTE]: path,\n\t\t\t\t\t[ATTR_CONTEXT]: hookSource,\n\t\t\t\t\t[ATTR_OPERATION_ID]: operationId,\n\t\t\t\t},\n\t\t\t\t() =>\n\t\t\t\t\thook.handler({\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\treturnHeaders: false,\n\t\t\t\t\t}),\n\t\t\t).catch((e: unknown) => {\n\t\t\t\tif (\n\t\t\t\t\tisAPIError(e) &&\n\t\t\t\t\tshouldPublishLog(context.context.logger.level, \"debug\")\n\t\t\t\t) {\n\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\te.stack = e.errorStack;\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t});\n\t\t\tif (result && typeof result === \"object\") {\n\t\t\t\tif (\"context\" in result && typeof result.context === \"object\") {\n\t\t\t\t\tconst { headers, ...rest } =\n\t\t\t\t\t\tresult.context as Partial<InternalContext>;\n\t\t\t\t\tif (headers instanceof Headers) {\n\t\t\t\t\t\tif (modifiedContext.headers) {\n\t\t\t\t\t\t\theaders.forEach((value, key) => {\n\t\t\t\t\t\t\t\tmodifiedContext.headers?.set(key, value);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmodifiedContext.headers = headers;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmodifiedContext = defuReplaceArrays(rest, modifiedContext);\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\treturn { context: modifiedContext };\n}\n\nasync function runAfterHooks(\n\tcontext: InternalContext,\n\thooks: Hook[],\n\tendpoint: Endpoint,\n\toperationId: string,\n) {\n\tfor (const hook of hooks) {\n\t\tif (hook.matcher(context)) {\n\t\t\tconst hookSource = hooksSourceWeakMap.get(hook.handler) ?? \"unknown\";\n\t\t\tconst path = context.path ?? endpoint?.path ?? \"/:virtual\";\n\t\t\tconst result = (await withSpan(\n\t\t\t\t`hook after ${path} ${hookSource}`,\n\t\t\t\t{\n\t\t\t\t\t[ATTR_HOOK_TYPE]: \"after\",\n\t\t\t\t\t[ATTR_HTTP_ROUTE]: path,\n\t\t\t\t\t[ATTR_CONTEXT]: hookSource,\n\t\t\t\t\t[ATTR_OPERATION_ID]: operationId,\n\t\t\t\t},\n\t\t\t\t() => hook.handler(context),\n\t\t\t).catch((e) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst headers = (e as any)[kAPIErrorHeaderSymbol] as\n\t\t\t\t\t\t| Headers\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tif (shouldPublishLog(context.context.logger.level, \"debug\")) {\n\t\t\t\t\t\t// inherit stack from errorStack if debug mode is enabled\n\t\t\t\t\t\te.stack = e.errorStack;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresponse: e,\n\t\t\t\t\t\theaders: headers\n\t\t\t\t\t\t\t? headers\n\t\t\t\t\t\t\t: e.headers\n\t\t\t\t\t\t\t\t? new Headers(e.headers)\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t})) as {\n\t\t\t\tresponse: any;\n\t\t\t\theaders: Headers;\n\t\t\t};\n\t\t\tif (result.headers) {\n\t\t\t\tresult.headers.forEach((value, key) => {\n\t\t\t\t\tif (!context.context.responseHeaders) {\n\t\t\t\t\t\tcontext.context.responseHeaders = new Headers({\n\t\t\t\t\t\t\t[key]: value,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (key.toLowerCase() === \"set-cookie\") {\n\t\t\t\t\t\t\tcontext.context.responseHeaders.append(key, value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.context.responseHeaders.set(key, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (result.response) {\n\t\t\t\tcontext.context.returned = result.response;\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tresponse: context.context.returned,\n\t\theaders: context.context.responseHeaders,\n\t};\n}\n\nfunction getHooks(authContext: AuthContext) {\n\tconst plugins = authContext.options.plugins || [];\n\tconst beforeHooks: Hook[] = [];\n\tconst afterHooks: Hook[] = [];\n\tconst beforeHookHandler = authContext.options.hooks?.before;\n\tif (beforeHookHandler) {\n\t\thooksSourceWeakMap.set(beforeHookHandler, \"user\");\n\t\tbeforeHooks.push({\n\t\t\tmatcher: () => true,\n\t\t\thandler: beforeHookHandler,\n\t\t});\n\t}\n\tconst afterHookHandler = authContext.options.hooks?.after;\n\tif (afterHookHandler) {\n\t\thooksSourceWeakMap.set(afterHookHandler, \"user\");\n\t\tafterHooks.push({\n\t\t\tmatcher: () => true,\n\t\t\thandler: afterHookHandler,\n\t\t});\n\t}\n\tconst pluginBeforeHooks = plugins.flatMap((plugin) =>\n\t\t(plugin.hooks?.before ?? []).map((h) => {\n\t\t\thooksSourceWeakMap.set(h.handler, `plugin:${plugin.id}`);\n\t\t\treturn h;\n\t\t}),\n\t);\n\tconst pluginAfterHooks = plugins.flatMap((plugin) =>\n\t\t(plugin.hooks?.after ?? []).map((h) => {\n\t\t\thooksSourceWeakMap.set(h.handler, `plugin:${plugin.id}`);\n\t\t\treturn h;\n\t\t}),\n\t);\n\n\t/**\n\t * Add plugin added hooks at last\n\t */\n\tif (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks);\n\tif (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks);\n\n\treturn {\n\t\tbeforeHooks,\n\t\tafterHooks,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/auth/full.d.mts
CHANGED
package/dist/auth/minimal.d.mts
CHANGED
package/dist/client/index.d.mts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { HasRequiredKeys, Prettify, PrettifyDeep, RequiredKeysOf, StripEmptyObjects, UnionToIntersection } from "../types/helper.mjs";
|
|
2
|
+
import { CamelCase, InferCtx, InferRoute, InferRoutes, InferSignUpEmailCtx, InferUserUpdateCtx, MergeRoutes, PathToObject, ProxyRequest } from "./path-to-object.mjs";
|
|
2
3
|
import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientStore, InferActions, InferAdditionalFromClient, InferClientAPI, InferErrorCodes, InferSessionFromClient, InferUserFromClient, IsSignal, SessionQueryParams } from "./types.mjs";
|
|
3
4
|
import { BroadcastChannel, BroadcastListener, BroadcastMessage, getGlobalBroadcastChannel, kBroadcastChannel } from "./broadcast-channel.mjs";
|
|
4
5
|
import { FocusListener, FocusManager, kFocusManager } from "./focus-manager.mjs";
|
|
5
6
|
import { OnlineListener, OnlineManager, kOnlineManager } from "./online-manager.mjs";
|
|
6
7
|
import { parseJSON } from "./parser.mjs";
|
|
7
8
|
import { AuthQueryAtom, useAuthQuery } from "./query.mjs";
|
|
8
|
-
import { SessionRefreshOptions, createSessionRefreshManager } from "./session-refresh.mjs";
|
|
9
|
+
import { SessionRefreshOptions, SessionResponse, createSessionRefreshManager } from "./session-refresh.mjs";
|
|
9
10
|
import { AuthClient, createAuthClient } from "./vanilla.mjs";
|
|
10
11
|
import { AccessControl, ArrayElement, Role, Statements, SubArray, Subset } from "../plugins/access/types.mjs";
|
|
11
12
|
import { AuthorizeResponse, createAccessControl, role } from "../plugins/access/access.mjs";
|
|
12
|
-
import "../plugins/access/index.mjs";
|
|
13
13
|
import { OrganizationOptions } from "../plugins/organization/types.mjs";
|
|
14
14
|
import { InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferTeam, Invitation, InvitationInput, InvitationStatus, Member, MemberInput, Organization, OrganizationInput, OrganizationRole, OrganizationSchema, Team, TeamInput, TeamMember, TeamMemberInput, defaultRolesSchema, invitationSchema, invitationStatus, memberSchema, organizationRoleSchema, organizationSchema, roleSchema, teamMemberSchema, teamSchema } from "../plugins/organization/schema.mjs";
|
|
15
15
|
import { getOrgAdapter } from "../plugins/organization/adapter.mjs";
|
|
16
16
|
import { hasPermission } from "../plugins/organization/has-permission.mjs";
|
|
17
17
|
import { DefaultOrganizationPlugin, DynamicAccessControlEndpoints, OrganizationCreator, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "../plugins/organization/organization.mjs";
|
|
18
|
-
import "../plugins/organization/index.mjs";
|
|
19
18
|
import { BetterAuthOptions, BetterAuthPlugin } from "@better-auth/core";
|
|
20
19
|
import { DBPrimitive } from "@better-auth/core/db";
|
|
21
20
|
export * from "@better-auth/core/db";
|
|
@@ -31,5 +30,5 @@ declare function InferAuth<O extends {
|
|
|
31
30
|
options: BetterAuthOptions;
|
|
32
31
|
}>(): O["options"];
|
|
33
32
|
//#endregion
|
|
34
|
-
export { AccessControl, ArrayElement, AuthClient, AuthQueryAtom, AuthorizeResponse, BetterAuthClientOptions, BetterAuthClientPlugin, BroadcastChannel, BroadcastListener, BroadcastMessage, ClientAtomListener, ClientStore, type DBPrimitive, DefaultOrganizationPlugin, DynamicAccessControlEndpoints, type FocusListener, type FocusManager, HasRequiredKeys, InferActions, InferAdditionalFromClient, InferAuth, InferClientAPI, InferErrorCodes, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPlugin, InferSessionFromClient, InferTeam, InferUserFromClient, Invitation, InvitationInput, InvitationStatus, IsSignal, Member, MemberInput, type OnlineListener, type OnlineManager, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, Prettify, PrettifyDeep, RequiredKeysOf, Role, SessionQueryParams, SessionRefreshOptions, Statements, StripEmptyObjects, SubArray, Subset, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, type UnionToIntersection, createAccessControl, createAuthClient, createSessionRefreshManager, defaultRolesSchema, getGlobalBroadcastChannel, getOrgAdapter, hasPermission, invitationSchema, invitationStatus, kBroadcastChannel, kFocusManager, kOnlineManager, memberSchema, organization, organizationRoleSchema, organizationSchema, parseJSON, parseRoles, role, roleSchema, teamMemberSchema, teamSchema, useAuthQuery };
|
|
33
|
+
export { AccessControl, ArrayElement, AuthClient, AuthQueryAtom, AuthorizeResponse, BetterAuthClientOptions, BetterAuthClientPlugin, BroadcastChannel, BroadcastListener, BroadcastMessage, CamelCase, ClientAtomListener, ClientStore, type DBPrimitive, DefaultOrganizationPlugin, DynamicAccessControlEndpoints, type FocusListener, type FocusManager, HasRequiredKeys, InferActions, InferAdditionalFromClient, InferAuth, InferClientAPI, InferCtx, InferErrorCodes, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPlugin, InferRoute, InferRoutes, InferSessionFromClient, InferSignUpEmailCtx, InferTeam, InferUserFromClient, InferUserUpdateCtx, Invitation, InvitationInput, InvitationStatus, IsSignal, Member, MemberInput, MergeRoutes, type OnlineListener, type OnlineManager, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, PathToObject, Prettify, PrettifyDeep, ProxyRequest, RequiredKeysOf, Role, SessionQueryParams, SessionRefreshOptions, SessionResponse, Statements, StripEmptyObjects, SubArray, Subset, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, type UnionToIntersection, createAccessControl, createAuthClient, createSessionRefreshManager, defaultRolesSchema, getGlobalBroadcastChannel, getOrgAdapter, hasPermission, invitationSchema, invitationStatus, kBroadcastChannel, kFocusManager, kOnlineManager, memberSchema, organization, organizationRoleSchema, organizationSchema, parseJSON, parseRoles, role, roleSchema, teamMemberSchema, teamSchema, useAuthQuery };
|
|
35
34
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/index.ts"],"sourcesContent":["import type {\n\tBetterAuthClientPlugin,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\n\nexport * from \"./broadcast-channel\";\nexport {\n\ttype FocusListener,\n\ttype FocusManager,\n\tkFocusManager,\n} from \"./focus-manager\";\nexport {\n\tkOnlineManager,\n\ttype OnlineListener,\n\ttype OnlineManager,\n} from \"./online-manager\";\nexport * from \"./parser\";\nexport * from \"./query\";\nexport * from \"./session-refresh\";\nexport * from \"./types\";\nexport * from \"./vanilla\";\n\nexport const InferPlugin = <T extends BetterAuthPlugin>() => {\n\treturn {\n\t\tid: \"infer-server-plugin\",\n\t\t$InferServerPlugin: {} as T,\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport function InferAuth<O extends { options: BetterAuthOptions }>() {\n\treturn {} as O[\"options\"];\n}\n\n//#region Necessary re-exports\nexport type * from \"@better-auth/core/db\";\nexport type { DBPrimitive } from \"@better-auth/core/db\";\nexport type * from \"@better-fetch/fetch\";\nexport type * from \"nanostores\";\nexport type * from \"../plugins/access\";\nexport type * from \"../plugins/organization\";\nexport type * from \"../types/helper\";\nexport type { UnionToIntersection } from \"../types/helper\";\n//#endregion\n"],"mappings":";;;;;;;;;AAuBA,MAAa,oBAAgD;AAC5D,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB;;AAGF,SAAgB,YAAsD;AACrE,QAAO,EAAE"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/index.ts"],"sourcesContent":["import type {\n\tBetterAuthClientPlugin,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\n\nexport * from \"./broadcast-channel\";\nexport {\n\ttype FocusListener,\n\ttype FocusManager,\n\tkFocusManager,\n} from \"./focus-manager\";\nexport {\n\tkOnlineManager,\n\ttype OnlineListener,\n\ttype OnlineManager,\n} from \"./online-manager\";\nexport * from \"./parser\";\nexport * from \"./query\";\nexport * from \"./session-refresh\";\nexport * from \"./types\";\nexport * from \"./vanilla\";\n\nexport const InferPlugin = <T extends BetterAuthPlugin>() => {\n\treturn {\n\t\tid: \"infer-server-plugin\",\n\t\t$InferServerPlugin: {} as T,\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport function InferAuth<O extends { options: BetterAuthOptions }>() {\n\treturn {} as O[\"options\"];\n}\n\n//#region Necessary re-exports\nexport type * from \"@better-auth/core/db\";\nexport type { DBPrimitive } from \"@better-auth/core/db\";\nexport type * from \"@better-fetch/fetch\";\nexport type * from \"nanostores\";\nexport type * from \"../plugins/access\";\nexport type * from \"../plugins/organization\";\nexport type * from \"../types/helper\";\nexport type { UnionToIntersection } from \"../types/helper\";\nexport type * from \"./path-to-object\";\n//#endregion\n"],"mappings":";;;;;;;;;AAuBA,MAAa,oBAAgD;AAC5D,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB;;AAGF,SAAgB,YAAsD;AACrE,QAAO,EAAE"}
|
|
@@ -8,6 +8,8 @@ import { BetterFetchResponse } from "@better-fetch/fetch";
|
|
|
8
8
|
type KeepNullishFromOriginal<Original, Replaced> = Replaced | (undefined extends Original ? undefined : never) | (null extends Original ? null : never);
|
|
9
9
|
type ReplaceTopLevelField<Data, Field extends "user" | "session", Replaced> = Data extends object ? Field extends keyof Data ? Omit<Data, Field> & { [K in Field]: KeepNullishFromOriginal<Data[K], Replaced> } : Data : Data;
|
|
10
10
|
type ReplaceAuthUserAndSession<Data, ClientOpts extends BetterAuthClientOptions> = ReplaceTopLevelField<ReplaceTopLevelField<Data, "user", InferUserFromClient<ClientOpts>>, "session", InferSessionFromClient<ClientOpts>>;
|
|
11
|
+
type MergeCustomSessionField<R extends object, Field extends "user" | "session", InferType> = Field extends keyof R ? { [K in Field]: KeepNullishFromOriginal<R[K], NonNullable<R[K]> & InferType> } : {};
|
|
12
|
+
type MergeCustomSessionWithInferred<R, ClientOpts extends BetterAuthClientOptions> = R extends object ? Omit<R, "user" | "session"> & MergeCustomSessionField<R, "user", InferUserFromClient<ClientOpts>> & MergeCustomSessionField<R, "session", InferSessionFromClient<ClientOpts>> : never;
|
|
11
13
|
type RefineAuthResponse<Data, ClientOpts extends BetterAuthClientOptions> = Data extends {
|
|
12
14
|
token: unknown;
|
|
13
15
|
} | {
|
|
@@ -50,7 +52,7 @@ type InferRoute<API, COpts extends BetterAuthClientOptions> = API extends Record
|
|
|
50
52
|
scope: "server";
|
|
51
53
|
} ? {} : PathToObject<T["path"], T extends ((ctx: infer C) => infer R) ? C extends InputContext<any, any> ? <FetchOptions extends ClientFetchOption<Partial<C["body"]> & Record<string, any>, Partial<C["query"]> & Record<string, any>, C["params"]>>(...data: HasRequiredKeys<InferCtx<C, FetchOptions>> extends true ? [Prettify$1<T["path"] extends `/sign-up/email` ? InferSignUpEmailCtx<COpts, FetchOptions> : InferCtx<C, FetchOptions>>, FetchOptions?] : [Prettify$1<T["path"] extends `/update-user` ? InferUserUpdateCtx<COpts, FetchOptions> : InferCtx<C, FetchOptions>>?, FetchOptions?]) => Promise<BetterFetchResponse<T["options"]["metadata"] extends {
|
|
52
54
|
CUSTOM_SESSION: boolean;
|
|
53
|
-
} ? NonNullable<Awaited<R
|
|
55
|
+
} ? MergeCustomSessionWithInferred<NonNullable<Awaited<R>>, COpts> : T["path"] extends "/get-session" ? {
|
|
54
56
|
user: InferUserFromClient<COpts>;
|
|
55
57
|
session: InferSessionFromClient<COpts>;
|
|
56
58
|
} | null : RefineAuthResponse<NonNullable<Awaited<R>>, COpts>, T["options"]["error"] extends StandardSchemaV1 ? NonNullable<T["options"]["error"]["~standard"]["types"]>["output"] : {
|
|
@@ -60,6 +62,11 @@ type InferRoute<API, COpts extends BetterAuthClientOptions> = API extends Record
|
|
|
60
62
|
throw: true;
|
|
61
63
|
} ? true : false>> : never : never> : {} : never;
|
|
62
64
|
type InferRoutes<API extends Record<string, Endpoint>, ClientOpts extends BetterAuthClientOptions> = MergeRoutes<InferRoute<API, ClientOpts>>;
|
|
65
|
+
type ProxyRequest = {
|
|
66
|
+
options?: ClientFetchOption<any, any> | undefined;
|
|
67
|
+
query?: any | undefined;
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
};
|
|
63
70
|
//#endregion
|
|
64
|
-
export { InferRoute, InferRoutes };
|
|
71
|
+
export { CamelCase, InferCtx, InferRoute, InferRoutes, InferSignUpEmailCtx, InferUserUpdateCtx, MergeRoutes, PathToObject, ProxyRequest };
|
|
65
72
|
//# sourceMappingURL=path-to-object.d.mts.map
|
package/dist/client/query.mjs
CHANGED
|
@@ -38,9 +38,10 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
38
38
|
const retryAttempts = typeof request.retry === "number" ? request.retry : request.retry?.attempts;
|
|
39
39
|
const retryAttempt = request.retryAttempt || 0;
|
|
40
40
|
if (retryAttempts && retryAttempt < retryAttempts) return;
|
|
41
|
+
const isUnauthorized = context.error.status === 401;
|
|
41
42
|
value.set({
|
|
42
43
|
error: context.error,
|
|
43
|
-
data: null,
|
|
44
|
+
data: isUnauthorized ? null : value.get().data,
|
|
44
45
|
isPending: false,
|
|
45
46
|
isRefetching: false,
|
|
46
47
|
refetch: value.value.refetch
|
|
@@ -61,7 +62,7 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
61
62
|
}).catch((error) => {
|
|
62
63
|
value.set({
|
|
63
64
|
error,
|
|
64
|
-
data:
|
|
65
|
+
data: value.get().data,
|
|
65
66
|
isPending: false,
|
|
66
67
|
isRefetching: false,
|
|
67
68
|
refetch: value.value.refetch
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.mjs","names":[],"sources":["../../src/client/query.ts"],"sourcesContent":["import type { ClientFetchOption } from \"@better-auth/core\";\nimport type { BetterFetch, BetterFetchError } from \"@better-fetch/fetch\";\nimport type { PreinitializedWritableAtom } from \"nanostores\";\nimport { atom, onMount } from \"nanostores\";\nimport type { SessionQueryParams } from \"./types\";\n\n// SSR detection\nconst isServer = () => typeof window === \"undefined\";\n\nexport type AuthQueryAtom<T> = PreinitializedWritableAtom<{\n\tdata: null | T;\n\terror: null | BetterFetchError;\n\tisPending: boolean;\n\tisRefetching: boolean;\n\trefetch: (\n\t\tqueryParams?: { query?: SessionQueryParams } | undefined,\n\t) => Promise<void>;\n}>;\n\nexport const useAuthQuery = <T>(\n\tinitializedAtom:\n\t\t| PreinitializedWritableAtom<any>\n\t\t| PreinitializedWritableAtom<any>[],\n\tpath: string,\n\t$fetch: BetterFetch,\n\toptions?:\n\t\t| (\n\t\t\t\t| ((value: {\n\t\t\t\t\t\tdata: null | T;\n\t\t\t\t\t\terror: null | BetterFetchError;\n\t\t\t\t\t\tisPending: boolean;\n\t\t\t\t }) => ClientFetchOption)\n\t\t\t\t| ClientFetchOption\n\t\t )\n\t\t| undefined,\n) => {\n\tconst value: AuthQueryAtom<T> = atom({\n\t\tdata: null,\n\t\terror: null,\n\t\tisPending: true,\n\t\tisRefetching: false,\n\t\trefetch: (queryParams) => fn(queryParams),\n\t});\n\n\tconst fn = async (\n\t\tqueryParams?: { query?: SessionQueryParams } | undefined,\n\t) => {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst opts =\n\t\t\t\ttypeof options === \"function\"\n\t\t\t\t\t? options({\n\t\t\t\t\t\t\tdata: value.get().data,\n\t\t\t\t\t\t\terror: value.get().error,\n\t\t\t\t\t\t\tisPending: value.get().isPending,\n\t\t\t\t\t\t})\n\t\t\t\t\t: options;\n\n\t\t\t$fetch<T>(path, {\n\t\t\t\t...opts,\n\t\t\t\tquery: {\n\t\t\t\t\t...opts?.query,\n\t\t\t\t\t...queryParams?.query,\n\t\t\t\t},\n\t\t\t\tasync onSuccess(context) {\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\tdata: context.data,\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\tisPending: false,\n\t\t\t\t\t\tisRefetching: false,\n\t\t\t\t\t\trefetch: value.value.refetch,\n\t\t\t\t\t});\n\t\t\t\t\tawait opts?.onSuccess?.(context);\n\t\t\t\t},\n\t\t\t\tasync onError(context) {\n\t\t\t\t\tconst { request } = context;\n\t\t\t\t\tconst retryAttempts =\n\t\t\t\t\t\ttypeof request.retry === \"number\"\n\t\t\t\t\t\t\t? request.retry\n\t\t\t\t\t\t\t: request.retry?.attempts;\n\t\t\t\t\tconst retryAttempt = request.retryAttempt || 0;\n\t\t\t\t\tif (retryAttempts && retryAttempt < retryAttempts) return;\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\terror: context.error,\n\t\t\t\t\t\tdata: null
|
|
1
|
+
{"version":3,"file":"query.mjs","names":[],"sources":["../../src/client/query.ts"],"sourcesContent":["import type { ClientFetchOption } from \"@better-auth/core\";\nimport type { BetterFetch, BetterFetchError } from \"@better-fetch/fetch\";\nimport type { PreinitializedWritableAtom } from \"nanostores\";\nimport { atom, onMount } from \"nanostores\";\nimport type { SessionQueryParams } from \"./types\";\n\n// SSR detection\nconst isServer = () => typeof window === \"undefined\";\n\nexport type AuthQueryAtom<T> = PreinitializedWritableAtom<{\n\tdata: null | T;\n\terror: null | BetterFetchError;\n\tisPending: boolean;\n\tisRefetching: boolean;\n\trefetch: (\n\t\tqueryParams?: { query?: SessionQueryParams } | undefined,\n\t) => Promise<void>;\n}>;\n\nexport const useAuthQuery = <T>(\n\tinitializedAtom:\n\t\t| PreinitializedWritableAtom<any>\n\t\t| PreinitializedWritableAtom<any>[],\n\tpath: string,\n\t$fetch: BetterFetch,\n\toptions?:\n\t\t| (\n\t\t\t\t| ((value: {\n\t\t\t\t\t\tdata: null | T;\n\t\t\t\t\t\terror: null | BetterFetchError;\n\t\t\t\t\t\tisPending: boolean;\n\t\t\t\t }) => ClientFetchOption)\n\t\t\t\t| ClientFetchOption\n\t\t )\n\t\t| undefined,\n) => {\n\tconst value: AuthQueryAtom<T> = atom({\n\t\tdata: null,\n\t\terror: null,\n\t\tisPending: true,\n\t\tisRefetching: false,\n\t\trefetch: (queryParams) => fn(queryParams),\n\t});\n\n\tconst fn = async (\n\t\tqueryParams?: { query?: SessionQueryParams } | undefined,\n\t) => {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst opts =\n\t\t\t\ttypeof options === \"function\"\n\t\t\t\t\t? options({\n\t\t\t\t\t\t\tdata: value.get().data,\n\t\t\t\t\t\t\terror: value.get().error,\n\t\t\t\t\t\t\tisPending: value.get().isPending,\n\t\t\t\t\t\t})\n\t\t\t\t\t: options;\n\n\t\t\t$fetch<T>(path, {\n\t\t\t\t...opts,\n\t\t\t\tquery: {\n\t\t\t\t\t...opts?.query,\n\t\t\t\t\t...queryParams?.query,\n\t\t\t\t},\n\t\t\t\tasync onSuccess(context) {\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\tdata: context.data,\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\tisPending: false,\n\t\t\t\t\t\tisRefetching: false,\n\t\t\t\t\t\trefetch: value.value.refetch,\n\t\t\t\t\t});\n\t\t\t\t\tawait opts?.onSuccess?.(context);\n\t\t\t\t},\n\t\t\t\tasync onError(context) {\n\t\t\t\t\tconst { request } = context;\n\t\t\t\t\tconst retryAttempts =\n\t\t\t\t\t\ttypeof request.retry === \"number\"\n\t\t\t\t\t\t\t? request.retry\n\t\t\t\t\t\t\t: request.retry?.attempts;\n\t\t\t\t\tconst retryAttempt = request.retryAttempt || 0;\n\t\t\t\t\tif (retryAttempts && retryAttempt < retryAttempts) return;\n\t\t\t\t\tconst isUnauthorized = context.error.status === 401;\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\terror: context.error,\n\t\t\t\t\t\tdata: isUnauthorized\n\t\t\t\t\t\t\t? null // clear session on HTTP 401\n\t\t\t\t\t\t\t: value.get().data, // preserve stale data on other errors\n\t\t\t\t\t\tisPending: false,\n\t\t\t\t\t\tisRefetching: false,\n\t\t\t\t\t\trefetch: value.value.refetch,\n\t\t\t\t\t});\n\t\t\t\t\tawait opts?.onError?.(context);\n\t\t\t\t},\n\t\t\t\tasync onRequest(context) {\n\t\t\t\t\tconst currentValue = value.get();\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\tisPending: currentValue.data === null,\n\t\t\t\t\t\tdata: currentValue.data,\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\tisRefetching: true,\n\t\t\t\t\t\trefetch: value.value.refetch,\n\t\t\t\t\t});\n\t\t\t\t\tawait opts?.onRequest?.(context);\n\t\t\t\t},\n\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tvalue.set({\n\t\t\t\t\t\terror,\n\t\t\t\t\t\tdata: value.get().data,\n\t\t\t\t\t\tisPending: false,\n\t\t\t\t\t\tisRefetching: false,\n\t\t\t\t\t\trefetch: value.value.refetch,\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tresolve(void 0);\n\t\t\t\t});\n\t\t});\n\t};\n\tinitializedAtom = Array.isArray(initializedAtom)\n\t\t? initializedAtom\n\t\t: [initializedAtom];\n\tlet isMounted = false;\n\n\tfor (const initAtom of initializedAtom) {\n\t\tinitAtom.subscribe(async () => {\n\t\t\tif (isServer()) {\n\t\t\t\t// On server, don't trigger fetch\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isMounted) {\n\t\t\t\tawait fn();\n\t\t\t} else {\n\t\t\t\tonMount(value, () => {\n\t\t\t\t\tconst timeoutId = setTimeout(async () => {\n\t\t\t\t\t\tif (!isMounted) {\n\t\t\t\t\t\t\tawait fn();\n\t\t\t\t\t\t\tisMounted = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 0);\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tvalue.off();\n\t\t\t\t\t\tinitAtom.off();\n\t\t\t\t\t\tclearTimeout(timeoutId);\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\treturn value;\n};\n"],"mappings":";;;AAOA,MAAM,iBAAiB,OAAO,WAAW;AAYzC,MAAa,gBACZ,iBAGA,MACA,QACA,YAUI;CACJ,MAAM,QAA0B,KAAK;EACpC,MAAM;EACN,OAAO;EACP,WAAW;EACX,cAAc;EACd,UAAU,gBAAgB,GAAG,YAAY;EACzC,CAAC;CAEF,MAAM,KAAK,OACV,gBACI;AACJ,SAAO,IAAI,SAAe,YAAY;GACrC,MAAM,OACL,OAAO,YAAY,aAChB,QAAQ;IACR,MAAM,MAAM,KAAK,CAAC;IAClB,OAAO,MAAM,KAAK,CAAC;IACnB,WAAW,MAAM,KAAK,CAAC;IACvB,CAAC,GACD;AAEJ,UAAU,MAAM;IACf,GAAG;IACH,OAAO;KACN,GAAG,MAAM;KACT,GAAG,aAAa;KAChB;IACD,MAAM,UAAU,SAAS;AACxB,WAAM,IAAI;MACT,MAAM,QAAQ;MACd,OAAO;MACP,WAAW;MACX,cAAc;MACd,SAAS,MAAM,MAAM;MACrB,CAAC;AACF,WAAM,MAAM,YAAY,QAAQ;;IAEjC,MAAM,QAAQ,SAAS;KACtB,MAAM,EAAE,YAAY;KACpB,MAAM,gBACL,OAAO,QAAQ,UAAU,WACtB,QAAQ,QACR,QAAQ,OAAO;KACnB,MAAM,eAAe,QAAQ,gBAAgB;AAC7C,SAAI,iBAAiB,eAAe,cAAe;KACnD,MAAM,iBAAiB,QAAQ,MAAM,WAAW;AAChD,WAAM,IAAI;MACT,OAAO,QAAQ;MACf,MAAM,iBACH,OACA,MAAM,KAAK,CAAC;MACf,WAAW;MACX,cAAc;MACd,SAAS,MAAM,MAAM;MACrB,CAAC;AACF,WAAM,MAAM,UAAU,QAAQ;;IAE/B,MAAM,UAAU,SAAS;KACxB,MAAM,eAAe,MAAM,KAAK;AAChC,WAAM,IAAI;MACT,WAAW,aAAa,SAAS;MACjC,MAAM,aAAa;MACnB,OAAO;MACP,cAAc;MACd,SAAS,MAAM,MAAM;MACrB,CAAC;AACF,WAAM,MAAM,YAAY,QAAQ;;IAEjC,CAAC,CACA,OAAO,UAAU;AACjB,UAAM,IAAI;KACT;KACA,MAAM,MAAM,KAAK,CAAC;KAClB,WAAW;KACX,cAAc;KACd,SAAS,MAAM,MAAM;KACrB,CAAC;KACD,CACD,cAAc;AACd,YAAQ,KAAK,EAAE;KACd;IACF;;AAEH,mBAAkB,MAAM,QAAQ,gBAAgB,GAC7C,kBACA,CAAC,gBAAgB;CACpB,IAAI,YAAY;AAEhB,MAAK,MAAM,YAAY,gBACtB,UAAS,UAAU,YAAY;AAC9B,MAAI,UAAU,CAEb;AAED,MAAI,UACH,OAAM,IAAI;MAEV,SAAQ,aAAa;GACpB,MAAM,YAAY,WAAW,YAAY;AACxC,QAAI,CAAC,WAAW;AACf,WAAM,IAAI;AACV,iBAAY;;MAEX,EAAE;AACL,gBAAa;AACZ,UAAM,KAAK;AACX,aAAS,KAAK;AACd,iBAAa,UAAU;;IAEvB;GAEF;AAEH,QAAO"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Session, User } from "../types/models.mjs";
|
|
2
|
-
import "../types/index.mjs";
|
|
3
2
|
import { AuthQueryAtom } from "./query.mjs";
|
|
4
3
|
import { BetterAuthClientOptions } from "@better-auth/core";
|
|
5
4
|
import { WritableAtom } from "nanostores";
|
|
@@ -10,11 +9,20 @@ interface SessionRefreshOptions {
|
|
|
10
9
|
sessionAtom: AuthQueryAtom<{
|
|
11
10
|
user: User;
|
|
12
11
|
session: Session;
|
|
13
|
-
}
|
|
12
|
+
} & Record<string, any>>;
|
|
14
13
|
sessionSignal: WritableAtom<boolean>;
|
|
15
14
|
$fetch: BetterFetch;
|
|
16
15
|
options?: BetterAuthClientOptions | undefined;
|
|
17
16
|
}
|
|
17
|
+
type SessionResponse = ({
|
|
18
|
+
session: null;
|
|
19
|
+
user: null;
|
|
20
|
+
needsRefresh?: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
session: Session;
|
|
23
|
+
user: User;
|
|
24
|
+
needsRefresh?: boolean;
|
|
25
|
+
}) & Record<string, any>;
|
|
18
26
|
declare function createSessionRefreshManager(opts: SessionRefreshOptions): {
|
|
19
27
|
init: () => void;
|
|
20
28
|
cleanup: () => void;
|
|
@@ -24,5 +32,5 @@ declare function createSessionRefreshManager(opts: SessionRefreshOptions): {
|
|
|
24
32
|
broadcastSessionUpdate: (trigger: "signout" | "getSession" | "updateUser") => void;
|
|
25
33
|
};
|
|
26
34
|
//#endregion
|
|
27
|
-
export { SessionRefreshOptions, createSessionRefreshManager };
|
|
35
|
+
export { SessionRefreshOptions, SessionResponse, createSessionRefreshManager };
|
|
28
36
|
//# sourceMappingURL=session-refresh.d.mts.map
|
|
@@ -5,6 +5,16 @@ import { getGlobalOnlineManager } from "./online-manager.mjs";
|
|
|
5
5
|
//#region src/client/session-refresh.ts
|
|
6
6
|
const now = () => Math.floor(Date.now() / 1e3);
|
|
7
7
|
/**
|
|
8
|
+
* Normalize $fetch response: `throw: true` returns data directly, otherwise `{ data, error }`.
|
|
9
|
+
*/
|
|
10
|
+
function normalizeSessionResponse(res) {
|
|
11
|
+
if (typeof res === "object" && res !== null && "data" in res && "error" in res) return res;
|
|
12
|
+
return {
|
|
13
|
+
data: res,
|
|
14
|
+
error: null
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
8
18
|
* Rate limit: don't refetch on focus if a session request was made within this many seconds
|
|
9
19
|
*/
|
|
10
20
|
const FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;
|
|
@@ -32,17 +42,12 @@ function createSessionRefreshManager(opts) {
|
|
|
32
42
|
const fetchSessionWithRefresh = () => {
|
|
33
43
|
state.lastSessionRequest = now();
|
|
34
44
|
$fetch("/get-session").then(async (res) => {
|
|
35
|
-
let data = res
|
|
36
|
-
let error = res.error || null;
|
|
45
|
+
let { data, error } = normalizeSessionResponse(res);
|
|
37
46
|
if (data?.needsRefresh) try {
|
|
38
47
|
const refreshRes = await $fetch("/get-session", { method: "POST" });
|
|
39
|
-
data = refreshRes
|
|
40
|
-
error = refreshRes.error || null;
|
|
48
|
+
({data, error} = normalizeSessionResponse(refreshRes));
|
|
41
49
|
} catch {}
|
|
42
|
-
const sessionData = data?.session && data?.user ?
|
|
43
|
-
session: data.session,
|
|
44
|
-
user: data.user
|
|
45
|
-
} : null;
|
|
50
|
+
const sessionData = data?.session && data?.user ? data : null;
|
|
46
51
|
sessionAtom.set({
|
|
47
52
|
...currentSession,
|
|
48
53
|
data: sessionData,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-refresh.mjs","names":[],"sources":["../../src/client/session-refresh.ts"],"sourcesContent":["import type { BetterAuthClientOptions } from \"@better-auth/core\";\nimport type { BetterFetch } from \"@better-fetch/fetch\";\nimport type { WritableAtom } from \"nanostores\";\nimport type { Session, User } from \"../types\";\nimport { getGlobalBroadcastChannel } from \"./broadcast-channel\";\nimport { getGlobalFocusManager } from \"./focus-manager\";\nimport { getGlobalOnlineManager } from \"./online-manager\";\nimport type { AuthQueryAtom } from \"./query\";\n\nconst now = () => Math.floor(Date.now() / 1000);\n\n/**\n * Rate limit: don't refetch on focus if a session request was made within this many seconds\n */\nconst FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;\n\nexport interface SessionRefreshOptions {\n\tsessionAtom: AuthQueryAtom
|
|
1
|
+
{"version":3,"file":"session-refresh.mjs","names":[],"sources":["../../src/client/session-refresh.ts"],"sourcesContent":["import type { BetterAuthClientOptions } from \"@better-auth/core\";\nimport type { BetterFetch } from \"@better-fetch/fetch\";\nimport type { WritableAtom } from \"nanostores\";\nimport type { Session, User } from \"../types\";\nimport { getGlobalBroadcastChannel } from \"./broadcast-channel\";\nimport { getGlobalFocusManager } from \"./focus-manager\";\nimport { getGlobalOnlineManager } from \"./online-manager\";\nimport type { AuthQueryAtom } from \"./query\";\n\nconst now = () => Math.floor(Date.now() / 1000);\n\n/**\n * Normalize $fetch response: `throw: true` returns data directly, otherwise `{ data, error }`.\n */\nfunction normalizeSessionResponse(res: unknown): {\n\tdata: SessionResponse | null;\n\terror: unknown;\n} {\n\tif (\n\t\ttypeof res === \"object\" &&\n\t\tres !== null &&\n\t\t\"data\" in res &&\n\t\t\"error\" in res\n\t) {\n\t\treturn res as { data: SessionResponse | null; error: unknown };\n\t}\n\treturn { data: res as SessionResponse, error: null };\n}\n\n/**\n * Rate limit: don't refetch on focus if a session request was made within this many seconds\n */\nconst FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;\n\nexport interface SessionRefreshOptions {\n\tsessionAtom: AuthQueryAtom<\n\t\t{\n\t\t\tuser: User;\n\t\t\tsession: Session;\n\t\t} & Record<string, any>\n\t>;\n\tsessionSignal: WritableAtom<boolean>;\n\t$fetch: BetterFetch;\n\toptions?: BetterAuthClientOptions | undefined;\n}\n\ninterface SessionRefreshState {\n\tlastSync: number;\n\tlastSessionRequest: number;\n\tcachedSession: any;\n\tpollInterval?: ReturnType<typeof setInterval> | undefined;\n\tunsubscribeBroadcast?: (() => void) | undefined;\n\tunsubscribeFocus?: (() => void) | undefined;\n\tunsubscribeOnline?: (() => void) | undefined;\n}\n\nexport type SessionResponse = (\n\t| {\n\t\t\tsession: null;\n\t\t\tuser: null;\n\t\t\tneedsRefresh?: boolean;\n\t }\n\t| {\n\t\t\tsession: Session;\n\t\t\tuser: User;\n\t\t\tneedsRefresh?: boolean;\n\t }\n) &\n\tRecord<string, any>;\n\nexport function createSessionRefreshManager(opts: SessionRefreshOptions) {\n\tconst { sessionAtom, sessionSignal, $fetch, options = {} } = opts;\n\n\tconst refetchInterval = options.sessionOptions?.refetchInterval ?? 0;\n\tconst refetchOnWindowFocus =\n\t\toptions.sessionOptions?.refetchOnWindowFocus ?? true;\n\tconst refetchWhenOffline =\n\t\toptions.sessionOptions?.refetchWhenOffline ?? false;\n\n\tconst state: SessionRefreshState = {\n\t\tlastSync: 0,\n\t\tlastSessionRequest: 0,\n\t\tcachedSession: undefined,\n\t};\n\n\tconst shouldRefetch = (): boolean => {\n\t\treturn refetchWhenOffline || getGlobalOnlineManager().isOnline;\n\t};\n\n\tconst triggerRefetch = (\n\t\tevent?:\n\t\t\t| {\n\t\t\t\t\tevent?: \"poll\" | \"visibilitychange\" | \"storage\";\n\t\t\t }\n\t\t\t| undefined,\n\t) => {\n\t\tif (!shouldRefetch()) return;\n\n\t\tif (event?.event === \"storage\") {\n\t\t\tstate.lastSync = now();\n\t\t\tsessionSignal.set(!sessionSignal.get());\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentSession = sessionAtom.get();\n\n\t\tconst fetchSessionWithRefresh = () => {\n\t\t\tstate.lastSessionRequest = now();\n\t\t\t$fetch<SessionResponse>(\"/get-session\")\n\t\t\t\t.then(async (res) => {\n\t\t\t\t\tlet { data, error } = normalizeSessionResponse(res);\n\n\t\t\t\t\tif (data?.needsRefresh) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst refreshRes = await $fetch<SessionResponse>(\"/get-session\", {\n\t\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t({ data, error } = normalizeSessionResponse(refreshRes));\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst sessionData = data?.session && data?.user ? data : null;\n\n\t\t\t\t\tsessionAtom.set({\n\t\t\t\t\t\t...currentSession,\n\t\t\t\t\t\tdata: sessionData,\n\t\t\t\t\t\terror: error as Parameters<typeof sessionAtom.set>[0][\"error\"],\n\t\t\t\t\t});\n\t\t\t\t\tstate.lastSync = now();\n\t\t\t\t\tsessionSignal.set(!sessionSignal.get());\n\t\t\t\t})\n\t\t\t\t.catch(() => {});\n\t\t};\n\n\t\tif (event?.event === \"poll\") {\n\t\t\tfetchSessionWithRefresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Rate limit: don't refetch on focus if a session request was made recently\n\t\tif (event?.event === \"visibilitychange\") {\n\t\t\tconst timeSinceLastRequest = now() - state.lastSessionRequest;\n\t\t\tif (timeSinceLastRequest < FOCUS_REFETCH_RATE_LIMIT_SECONDS) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.lastSessionRequest = now();\n\t\t}\n\n\t\tif (event?.event === \"visibilitychange\") {\n\t\t\tfetchSessionWithRefresh();\n\t\t\treturn;\n\t\t}\n\n\t\tif (currentSession?.data === null || currentSession?.data === undefined) {\n\t\t\tstate.lastSync = now();\n\t\t\tsessionSignal.set(!sessionSignal.get());\n\t\t}\n\t};\n\n\tconst broadcastSessionUpdate = (\n\t\ttrigger: \"signout\" | \"getSession\" | \"updateUser\",\n\t) => {\n\t\tgetGlobalBroadcastChannel().post({\n\t\t\tevent: \"session\",\n\t\t\tdata: { trigger },\n\t\t\tclientId: Math.random().toString(36).substring(7),\n\t\t});\n\t};\n\n\tconst setupPolling = () => {\n\t\tif (refetchInterval && refetchInterval > 0) {\n\t\t\tstate.pollInterval = setInterval(() => {\n\t\t\t\tconst currentSession = sessionAtom.get();\n\t\t\t\tif (currentSession?.data) {\n\t\t\t\t\ttriggerRefetch({ event: \"poll\" });\n\t\t\t\t}\n\t\t\t}, refetchInterval * 1000);\n\t\t}\n\t};\n\n\tconst setupBroadcast = () => {\n\t\tstate.unsubscribeBroadcast = getGlobalBroadcastChannel().subscribe(() => {\n\t\t\ttriggerRefetch({ event: \"storage\" });\n\t\t});\n\t};\n\n\tconst setupFocusRefetch = () => {\n\t\tif (!refetchOnWindowFocus) return;\n\n\t\tstate.unsubscribeFocus = getGlobalFocusManager().subscribe(() => {\n\t\t\ttriggerRefetch({ event: \"visibilitychange\" });\n\t\t});\n\t};\n\n\tconst setupOnlineRefetch = () => {\n\t\tstate.unsubscribeOnline = getGlobalOnlineManager().subscribe((online) => {\n\t\t\tif (online) {\n\t\t\t\ttriggerRefetch({ event: \"visibilitychange\" });\n\t\t\t}\n\t\t});\n\t};\n\n\tconst init = () => {\n\t\tsetupPolling();\n\t\tsetupBroadcast();\n\t\tsetupFocusRefetch();\n\t\tsetupOnlineRefetch();\n\n\t\tgetGlobalBroadcastChannel().setup();\n\t\tgetGlobalFocusManager().setup();\n\t\tgetGlobalOnlineManager().setup();\n\t};\n\n\tconst cleanup = () => {\n\t\tif (state.pollInterval) {\n\t\t\tclearInterval(state.pollInterval);\n\t\t\tstate.pollInterval = undefined;\n\t\t}\n\t\tif (state.unsubscribeBroadcast) {\n\t\t\tstate.unsubscribeBroadcast();\n\t\t\tstate.unsubscribeBroadcast = undefined;\n\t\t}\n\t\tif (state.unsubscribeFocus) {\n\t\t\tstate.unsubscribeFocus();\n\t\t\tstate.unsubscribeFocus = undefined;\n\t\t}\n\t\tif (state.unsubscribeOnline) {\n\t\t\tstate.unsubscribeOnline();\n\t\t\tstate.unsubscribeOnline = undefined;\n\t\t}\n\t\tstate.lastSync = 0;\n\t\tstate.lastSessionRequest = 0;\n\t\tstate.cachedSession = undefined;\n\t};\n\n\treturn {\n\t\tinit,\n\t\tcleanup,\n\t\ttriggerRefetch,\n\t\tbroadcastSessionUpdate,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/client/types.d.mts
CHANGED
|
@@ -3,7 +3,6 @@ import { StripEmptyObjects, UnionToIntersection } from "../types/helper.mjs";
|
|
|
3
3
|
import { InferRoutes } from "./path-to-object.mjs";
|
|
4
4
|
import { Session as Session$1, User as User$1 } from "../types/models.mjs";
|
|
5
5
|
import { Auth } from "../types/auth.mjs";
|
|
6
|
-
import "../types/index.mjs";
|
|
7
6
|
import { BetterAuthClientOptions as BetterAuthClientOptions$1, BetterAuthClientPlugin as BetterAuthClientPlugin$1, ClientAtomListener, ClientStore } from "@better-auth/core";
|
|
8
7
|
import { BetterAuthPluginDBSchema, InferDBFieldsOutput } from "@better-auth/core/db";
|
|
9
8
|
import { RawError } from "@better-auth/core/utils/error-codes";
|
|
@@ -192,7 +192,10 @@ Most of the features of Better Auth will not work correctly.`);
|
|
|
192
192
|
internalAdapter: createInternalAdapter(adapter, {
|
|
193
193
|
options,
|
|
194
194
|
logger,
|
|
195
|
-
hooks: options.databaseHooks ? [
|
|
195
|
+
hooks: options.databaseHooks ? [{
|
|
196
|
+
source: "user",
|
|
197
|
+
hooks: options.databaseHooks
|
|
198
|
+
}] : [],
|
|
196
199
|
generateId: generateIdFunc
|
|
197
200
|
}),
|
|
198
201
|
createAuthCookie: createCookieGetter(options),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-context.mjs","names":[],"sources":["../../src/context/create-context.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tBetterAuthOptions,\n\tSecretConfig,\n} from \"@better-auth/core\";\nimport { getBetterAuthVersion } from \"@better-auth/core/context\";\nimport { getAuthTables } from \"@better-auth/core/db\";\nimport type { DBAdapter } from \"@better-auth/core/db/adapter\";\nimport { createLogger, env, isProduction, isTest } from \"@better-auth/core/env\";\nimport { BetterAuthError } from \"@better-auth/core/error\";\nimport type { OAuthProvider } from \"@better-auth/core/oauth2\";\nimport type { SocialProviders } from \"@better-auth/core/social-providers\";\nimport { socialProviders } from \"@better-auth/core/social-providers\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport { createTelemetry } from \"@better-auth/telemetry\";\nimport defu from \"defu\";\nimport type { Entries } from \"type-fest\";\nimport { checkEndpointConflicts } from \"../api\";\nimport { matchesOriginPattern } from \"../auth/trusted-origins\";\nimport { createCookieGetter, getCookies } from \"../cookies\";\nimport { hashPassword, verifyPassword } from \"../crypto/password\";\nimport { createInternalAdapter } from \"../db/internal-adapter\";\nimport { DEFAULT_SECRET } from \"../utils/constants\";\nimport { isPromise } from \"../utils/is-promise\";\nimport { checkPassword } from \"../utils/password\";\nimport { getBaseURL, isDynamicBaseURLConfig } from \"../utils/url\";\nimport {\n\tgetInternalPlugins,\n\tgetTrustedOrigins,\n\tgetTrustedProviders,\n\trunPluginInit,\n} from \"./helpers\";\nimport {\n\tbuildSecretConfig,\n\tparseSecretsEnv,\n\tvalidateSecretsArray,\n} from \"./secret-utils\";\n\n/**\n * Estimates the entropy of a string in bits.\n * This is a simple approximation that helps detect low-entropy secrets.\n */\nfunction estimateEntropy(str: string): number {\n\tconst unique = new Set(str).size;\n\tif (unique === 0) return 0;\n\treturn Math.log2(Math.pow(unique, str.length));\n}\n\n/**\n * Validates that the secret meets minimum security requirements.\n * Throws BetterAuthError if the secret is invalid.\n * Skips validation for DEFAULT_SECRET in test environments only.\n * Only throws for DEFAULT_SECRET in production environment.\n */\nfunction validateSecret(\n\tsecret: string,\n\tlogger: ReturnType<typeof createLogger>,\n): void {\n\tconst isDefaultSecret = secret === DEFAULT_SECRET;\n\n\tif (isTest()) {\n\t\treturn;\n\t}\n\n\tif (isDefaultSecret && isProduction) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config.\",\n\t\t);\n\t}\n\n\tif (!secret) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"BETTER_AUTH_SECRET is missing. Set it in your environment or pass `secret` to betterAuth({ secret }).\",\n\t\t);\n\t}\n\n\tif (secret.length < 32) {\n\t\tlogger.warn(\n\t\t\t`[better-auth] Warning: your BETTER_AUTH_SECRET should be at least 32 characters long for adequate security. Generate one with \\`npx auth secret\\` or \\`openssl rand -base64 32\\`.`,\n\t\t);\n\t}\n\n\t// Optional high-entropy check: warn if entropy appears low\n\tconst entropy = estimateEntropy(secret);\n\tif (entropy < 120) {\n\t\tlogger.warn(\n\t\t\t\"[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production.\",\n\t\t);\n\t}\n}\n\nexport async function createAuthContext<Options extends BetterAuthOptions>(\n\tadapter: DBAdapter,\n\toptions: Options,\n\tgetDatabaseType: (database: Options[\"database\"]) => string,\n): Promise<AuthContext<Options>> {\n\t//set default options for stateless mode\n\tif (!options.database) {\n\t\toptions = defu(options, {\n\t\t\tsession: {\n\t\t\t\tcookieCache: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tstrategy: \"jwe\" as const,\n\t\t\t\t\trefreshCache: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\taccount: {\n\t\t\t\tstoreStateStrategy: \"cookie\" as const,\n\t\t\t\tstoreAccountCookie: true,\n\t\t\t},\n\t\t}) as Options;\n\t}\n\tconst plugins = options.plugins || [];\n\tconst internalPlugins = getInternalPlugins(options);\n\tconst logger = createLogger(options.logger);\n\n\tconst isDynamicConfig = isDynamicBaseURLConfig(options.baseURL);\n\n\tif (isDynamicBaseURLConfig(options.baseURL)) {\n\t\tconst { allowedHosts } = options.baseURL;\n\t\tif (!allowedHosts || allowedHosts.length === 0) {\n\t\t\tthrow new BetterAuthError(\n\t\t\t\t\"baseURL.allowedHosts cannot be empty. Provide at least one allowed host pattern \" +\n\t\t\t\t\t'(e.g., [\"myapp.com\", \"*.vercel.app\"]).',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseURL = isDynamicConfig\n\t\t? undefined\n\t\t: getBaseURL(\n\t\t\t\ttypeof options.baseURL === \"string\" ? options.baseURL : undefined,\n\t\t\t\toptions.basePath,\n\t\t\t);\n\n\tif (!baseURL && !isDynamicConfig) {\n\t\tlogger.warn(\n\t\t\t`[better-auth] Base URL could not be determined. Please set a valid base URL using the baseURL config option or the BETTER_AUTH_URL environment variable. Without this, callbacks and redirects may not work correctly.`,\n\t\t);\n\t}\n\n\tif (\n\t\tadapter.id === \"memory\" &&\n\t\toptions.advanced?.database?.generateId === false\n\t) {\n\t\tlogger.error(\n\t\t\t`[better-auth] Misconfiguration detected.\nYou are using the memory DB with generateId: false.\nThis will cause no id to be generated for any model.\nMost of the features of Better Auth will not work correctly.`,\n\t\t);\n\t}\n\n\tconst secretsArray =\n\t\toptions.secrets ?? parseSecretsEnv(env.BETTER_AUTH_SECRETS);\n\n\tconst legacySecret =\n\t\toptions.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || \"\";\n\n\tlet secret: string;\n\tlet secretConfig: string | SecretConfig;\n\n\tif (secretsArray) {\n\t\tvalidateSecretsArray(secretsArray, logger);\n\t\tsecret = secretsArray[0]!.value;\n\t\tsecretConfig = buildSecretConfig(secretsArray, legacySecret);\n\t} else {\n\t\tsecret = legacySecret || DEFAULT_SECRET;\n\t\tvalidateSecret(secret, logger);\n\t\tsecretConfig = secret;\n\t}\n\n\toptions = {\n\t\t...options,\n\t\tsecret,\n\t\tbaseURL: isDynamicConfig\n\t\t\t? options.baseURL\n\t\t\t: baseURL\n\t\t\t\t? new URL(baseURL).origin\n\t\t\t\t: \"\",\n\t\tbasePath: options.basePath || \"/api/auth\",\n\t\tplugins: plugins.concat(internalPlugins),\n\t};\n\n\tcheckEndpointConflicts(options, logger);\n\tconst cookies = getCookies(options);\n\tconst tables = getAuthTables(options);\n\tconst providers = (\n\t\tawait Promise.all(\n\t\t\t(\n\t\t\t\tObject.entries(\n\t\t\t\t\toptions.socialProviders || {},\n\t\t\t\t) as unknown as Entries<SocialProviders>\n\t\t\t).map(async ([key, originalConfig]) => {\n\t\t\t\tconst config =\n\t\t\t\t\ttypeof originalConfig === \"function\"\n\t\t\t\t\t\t? await originalConfig()\n\t\t\t\t\t\t: originalConfig;\n\t\t\t\tif (config == null) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (config.enabled === false) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (!config.clientId) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t`Social provider ${key} is missing clientId or clientSecret`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst provider = socialProviders[key](config as never);\n\t\t\t\t(provider as OAuthProvider).disableImplicitSignUp =\n\t\t\t\t\tconfig.disableImplicitSignUp;\n\t\t\t\treturn provider as OAuthProvider;\n\t\t\t}),\n\t\t)\n\t).filter((x) => x !== null);\n\n\tconst generateIdFunc: AuthContext[\"generateId\"] = ({ model, size }) => {\n\t\tif (typeof (options.advanced as any)?.generateId === \"function\") {\n\t\t\treturn (options.advanced as any).generateId({ model, size });\n\t\t}\n\t\tconst dbGenerateId = options?.advanced?.database?.generateId;\n\t\tif (typeof dbGenerateId === \"function\") {\n\t\t\treturn dbGenerateId({ model, size });\n\t\t}\n\t\tif (dbGenerateId === \"uuid\") {\n\t\t\treturn crypto.randomUUID();\n\t\t}\n\t\tif (dbGenerateId === \"serial\" || dbGenerateId === false) {\n\t\t\treturn false;\n\t\t}\n\t\treturn generateId(size);\n\t};\n\n\tconst { publish } = await createTelemetry(options, {\n\t\tadapter: adapter.id,\n\t\tdatabase:\n\t\t\ttypeof options.database === \"function\"\n\t\t\t\t? \"adapter\"\n\t\t\t\t: getDatabaseType(options.database),\n\t});\n\n\tconst pluginIds = new Set(options.plugins!.map((p) => p.id));\n\n\tconst getPluginFn = (id: string) =>\n\t\t(options.plugins!.find((p) => p.id === id) as never | undefined) ?? null;\n\n\tconst hasPluginFn = (id: string) => pluginIds.has(id);\n\n\tconst trustedOrigins = await getTrustedOrigins(options);\n\tconst trustedProviders = await getTrustedProviders(options);\n\n\tconst ctx: AuthContext = {\n\t\tappName: options.appName || \"Better Auth\",\n\t\tbaseURL: baseURL || \"\",\n\t\tversion: getBetterAuthVersion(),\n\t\tsocialProviders: providers,\n\t\toptions,\n\t\toauthConfig: {\n\t\t\tstoreStateStrategy:\n\t\t\t\toptions.account?.storeStateStrategy ||\n\t\t\t\t(options.database ? \"database\" : \"cookie\"),\n\t\t\tskipStateCookieCheck: !!options.account?.skipStateCookieCheck,\n\t\t},\n\t\ttables,\n\t\ttrustedOrigins,\n\t\ttrustedProviders,\n\t\tisTrustedOrigin(\n\t\t\turl: string,\n\t\t\tsettings?: {\n\t\t\t\tallowRelativePaths: boolean;\n\t\t\t},\n\t\t) {\n\t\t\treturn this.trustedOrigins.some((origin) =>\n\t\t\t\tmatchesOriginPattern(url, origin, settings),\n\t\t\t);\n\t\t},\n\t\tsessionConfig: {\n\t\t\tupdateAge:\n\t\t\t\toptions.session?.updateAge !== undefined\n\t\t\t\t\t? options.session.updateAge\n\t\t\t\t\t: 24 * 60 * 60,\n\t\t\texpiresIn: options.session?.expiresIn || 60 * 60 * 24 * 7,\n\t\t\tfreshAge:\n\t\t\t\toptions.session?.freshAge === undefined\n\t\t\t\t\t? 60 * 60 * 24\n\t\t\t\t\t: options.session.freshAge,\n\t\t\tcookieRefreshCache: (() => {\n\t\t\t\tconst refreshCache = options.session?.cookieCache?.refreshCache;\n\t\t\t\tconst maxAge = options.session?.cookieCache?.maxAge || 60 * 5;\n\n\t\t\t\t// `refreshCache` is intended for fully stateless / DB-less setups.\n\t\t\t\t// If a server-side store is configured, prefer fetching/refreshing from that source\n\t\t\t\t// and disable stateless refresh behavior to avoid confusing/unsafe configurations.\n\t\t\t\tconst isStateful = !!options.database || !!options.secondaryStorage;\n\t\t\t\tif (isStateful && refreshCache) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\"[better-auth] `session.cookieCache.refreshCache` is enabled while `database` or `secondaryStorage` is configured. `refreshCache` is meant for stateless (DB-less) setups. Disabling `refreshCache` — remove it from your config to silence this warning.\",\n\t\t\t\t\t);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (refreshCache === false || refreshCache === undefined) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (refreshCache === true) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tupdateAge: Math.floor(maxAge * 0.2),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tupdateAge:\n\t\t\t\t\t\trefreshCache.updateAge !== undefined\n\t\t\t\t\t\t\t? refreshCache.updateAge\n\t\t\t\t\t\t\t: Math.floor(maxAge * 0.2),\n\t\t\t\t};\n\t\t\t})(),\n\t\t},\n\t\tsecret,\n\t\tsecretConfig,\n\t\trateLimit: {\n\t\t\t...options.rateLimit,\n\t\t\tenabled: options.rateLimit?.enabled ?? isProduction,\n\t\t\twindow: options.rateLimit?.window || 10,\n\t\t\tmax: options.rateLimit?.max || 100,\n\t\t\tstorage:\n\t\t\t\toptions.rateLimit?.storage ||\n\t\t\t\t(options.secondaryStorage ? \"secondary-storage\" : \"memory\"),\n\t\t},\n\t\tauthCookies: cookies,\n\t\tlogger,\n\t\tgenerateId: generateIdFunc,\n\t\tsession: null,\n\t\tsecondaryStorage: options.secondaryStorage,\n\t\tpassword: {\n\t\t\thash: options.emailAndPassword?.password?.hash || hashPassword,\n\t\t\tverify: options.emailAndPassword?.password?.verify || verifyPassword,\n\t\t\tconfig: {\n\t\t\t\tminPasswordLength: options.emailAndPassword?.minPasswordLength || 8,\n\t\t\t\tmaxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128,\n\t\t\t},\n\t\t\tcheckPassword,\n\t\t},\n\t\tsetNewSession(session) {\n\t\t\tthis.newSession = session;\n\t\t},\n\t\tnewSession: null,\n\t\tadapter: adapter,\n\t\tinternalAdapter: createInternalAdapter(adapter, {\n\t\t\toptions,\n\t\t\tlogger,\n\t\t\thooks: options.databaseHooks ? [options.databaseHooks] : [],\n\t\t\tgenerateId: generateIdFunc,\n\t\t}),\n\t\tcreateAuthCookie: createCookieGetter(options),\n\t\tasync runMigrations() {\n\t\t\tthrow new BetterAuthError(\n\t\t\t\t\"runMigrations will be set by the specific init implementation\",\n\t\t\t);\n\t\t},\n\t\tpublishTelemetry: publish,\n\t\tskipCSRFCheck: !!options.advanced?.disableCSRFCheck,\n\t\tskipOriginCheck:\n\t\t\toptions.advanced?.disableOriginCheck !== undefined\n\t\t\t\t? options.advanced.disableOriginCheck\n\t\t\t\t: isTest()\n\t\t\t\t\t? true\n\t\t\t\t\t: false,\n\t\trunInBackground:\n\t\t\toptions.advanced?.backgroundTasks?.handler ??\n\t\t\t((p) => {\n\t\t\t\tp.catch(() => {});\n\t\t\t}),\n\t\tasync runInBackgroundOrAwait(\n\t\t\tpromise: Promise<unknown> | Promise<void> | void | unknown,\n\t\t) {\n\t\t\ttry {\n\t\t\t\tif (options.advanced?.backgroundTasks?.handler) {\n\t\t\t\t\tif (promise instanceof Promise) {\n\t\t\t\t\t\toptions.advanced.backgroundTasks.handler(\n\t\t\t\t\t\t\tpromise.catch((e) => {\n\t\t\t\t\t\t\t\tlogger.error(\"Failed to run background task:\", e);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tawait promise;\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(\"Failed to run background task:\", e);\n\t\t\t}\n\t\t},\n\t\tgetPlugin: getPluginFn,\n\t\thasPlugin: hasPluginFn as never,\n\t};\n\n\tconst initOrPromise = runPluginInit(ctx);\n\tif (isPromise(initOrPromise)) {\n\t\tawait initOrPromise;\n\t}\n\n\treturn ctx as unknown as AuthContext<Options>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-context.mjs","names":[],"sources":["../../src/context/create-context.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tBetterAuthOptions,\n\tSecretConfig,\n} from \"@better-auth/core\";\nimport { getBetterAuthVersion } from \"@better-auth/core/context\";\nimport { getAuthTables } from \"@better-auth/core/db\";\nimport type { DBAdapter } from \"@better-auth/core/db/adapter\";\nimport { createLogger, env, isProduction, isTest } from \"@better-auth/core/env\";\nimport { BetterAuthError } from \"@better-auth/core/error\";\nimport type { OAuthProvider } from \"@better-auth/core/oauth2\";\nimport type { SocialProviders } from \"@better-auth/core/social-providers\";\nimport { socialProviders } from \"@better-auth/core/social-providers\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport { createTelemetry } from \"@better-auth/telemetry\";\nimport defu from \"defu\";\nimport type { Entries } from \"type-fest\";\nimport { checkEndpointConflicts } from \"../api\";\nimport { matchesOriginPattern } from \"../auth/trusted-origins\";\nimport { createCookieGetter, getCookies } from \"../cookies\";\nimport { hashPassword, verifyPassword } from \"../crypto/password\";\nimport { createInternalAdapter } from \"../db/internal-adapter\";\nimport { DEFAULT_SECRET } from \"../utils/constants\";\nimport { isPromise } from \"../utils/is-promise\";\nimport { checkPassword } from \"../utils/password\";\nimport { getBaseURL, isDynamicBaseURLConfig } from \"../utils/url\";\nimport {\n\tgetInternalPlugins,\n\tgetTrustedOrigins,\n\tgetTrustedProviders,\n\trunPluginInit,\n} from \"./helpers\";\nimport {\n\tbuildSecretConfig,\n\tparseSecretsEnv,\n\tvalidateSecretsArray,\n} from \"./secret-utils\";\n\n/**\n * Estimates the entropy of a string in bits.\n * This is a simple approximation that helps detect low-entropy secrets.\n */\nfunction estimateEntropy(str: string): number {\n\tconst unique = new Set(str).size;\n\tif (unique === 0) return 0;\n\treturn Math.log2(Math.pow(unique, str.length));\n}\n\n/**\n * Validates that the secret meets minimum security requirements.\n * Throws BetterAuthError if the secret is invalid.\n * Skips validation for DEFAULT_SECRET in test environments only.\n * Only throws for DEFAULT_SECRET in production environment.\n */\nfunction validateSecret(\n\tsecret: string,\n\tlogger: ReturnType<typeof createLogger>,\n): void {\n\tconst isDefaultSecret = secret === DEFAULT_SECRET;\n\n\tif (isTest()) {\n\t\treturn;\n\t}\n\n\tif (isDefaultSecret && isProduction) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config.\",\n\t\t);\n\t}\n\n\tif (!secret) {\n\t\tthrow new BetterAuthError(\n\t\t\t\"BETTER_AUTH_SECRET is missing. Set it in your environment or pass `secret` to betterAuth({ secret }).\",\n\t\t);\n\t}\n\n\tif (secret.length < 32) {\n\t\tlogger.warn(\n\t\t\t`[better-auth] Warning: your BETTER_AUTH_SECRET should be at least 32 characters long for adequate security. Generate one with \\`npx auth secret\\` or \\`openssl rand -base64 32\\`.`,\n\t\t);\n\t}\n\n\t// Optional high-entropy check: warn if entropy appears low\n\tconst entropy = estimateEntropy(secret);\n\tif (entropy < 120) {\n\t\tlogger.warn(\n\t\t\t\"[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production.\",\n\t\t);\n\t}\n}\n\nexport async function createAuthContext<Options extends BetterAuthOptions>(\n\tadapter: DBAdapter,\n\toptions: Options,\n\tgetDatabaseType: (database: Options[\"database\"]) => string,\n): Promise<AuthContext<Options>> {\n\t//set default options for stateless mode\n\tif (!options.database) {\n\t\toptions = defu(options, {\n\t\t\tsession: {\n\t\t\t\tcookieCache: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tstrategy: \"jwe\" as const,\n\t\t\t\t\trefreshCache: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\taccount: {\n\t\t\t\tstoreStateStrategy: \"cookie\" as const,\n\t\t\t\tstoreAccountCookie: true,\n\t\t\t},\n\t\t}) as Options;\n\t}\n\tconst plugins = options.plugins || [];\n\tconst internalPlugins = getInternalPlugins(options);\n\tconst logger = createLogger(options.logger);\n\n\tconst isDynamicConfig = isDynamicBaseURLConfig(options.baseURL);\n\n\tif (isDynamicBaseURLConfig(options.baseURL)) {\n\t\tconst { allowedHosts } = options.baseURL;\n\t\tif (!allowedHosts || allowedHosts.length === 0) {\n\t\t\tthrow new BetterAuthError(\n\t\t\t\t\"baseURL.allowedHosts cannot be empty. Provide at least one allowed host pattern \" +\n\t\t\t\t\t'(e.g., [\"myapp.com\", \"*.vercel.app\"]).',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseURL = isDynamicConfig\n\t\t? undefined\n\t\t: getBaseURL(\n\t\t\t\ttypeof options.baseURL === \"string\" ? options.baseURL : undefined,\n\t\t\t\toptions.basePath,\n\t\t\t);\n\n\tif (!baseURL && !isDynamicConfig) {\n\t\tlogger.warn(\n\t\t\t`[better-auth] Base URL could not be determined. Please set a valid base URL using the baseURL config option or the BETTER_AUTH_URL environment variable. Without this, callbacks and redirects may not work correctly.`,\n\t\t);\n\t}\n\n\tif (\n\t\tadapter.id === \"memory\" &&\n\t\toptions.advanced?.database?.generateId === false\n\t) {\n\t\tlogger.error(\n\t\t\t`[better-auth] Misconfiguration detected.\nYou are using the memory DB with generateId: false.\nThis will cause no id to be generated for any model.\nMost of the features of Better Auth will not work correctly.`,\n\t\t);\n\t}\n\n\tconst secretsArray =\n\t\toptions.secrets ?? parseSecretsEnv(env.BETTER_AUTH_SECRETS);\n\n\tconst legacySecret =\n\t\toptions.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || \"\";\n\n\tlet secret: string;\n\tlet secretConfig: string | SecretConfig;\n\n\tif (secretsArray) {\n\t\tvalidateSecretsArray(secretsArray, logger);\n\t\tsecret = secretsArray[0]!.value;\n\t\tsecretConfig = buildSecretConfig(secretsArray, legacySecret);\n\t} else {\n\t\tsecret = legacySecret || DEFAULT_SECRET;\n\t\tvalidateSecret(secret, logger);\n\t\tsecretConfig = secret;\n\t}\n\n\toptions = {\n\t\t...options,\n\t\tsecret,\n\t\tbaseURL: isDynamicConfig\n\t\t\t? options.baseURL\n\t\t\t: baseURL\n\t\t\t\t? new URL(baseURL).origin\n\t\t\t\t: \"\",\n\t\tbasePath: options.basePath || \"/api/auth\",\n\t\tplugins: plugins.concat(internalPlugins),\n\t};\n\n\tcheckEndpointConflicts(options, logger);\n\tconst cookies = getCookies(options);\n\tconst tables = getAuthTables(options);\n\tconst providers = (\n\t\tawait Promise.all(\n\t\t\t(\n\t\t\t\tObject.entries(\n\t\t\t\t\toptions.socialProviders || {},\n\t\t\t\t) as unknown as Entries<SocialProviders>\n\t\t\t).map(async ([key, originalConfig]) => {\n\t\t\t\tconst config =\n\t\t\t\t\ttypeof originalConfig === \"function\"\n\t\t\t\t\t\t? await originalConfig()\n\t\t\t\t\t\t: originalConfig;\n\t\t\t\tif (config == null) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (config.enabled === false) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (!config.clientId) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t`Social provider ${key} is missing clientId or clientSecret`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst provider = socialProviders[key](config as never);\n\t\t\t\t(provider as OAuthProvider).disableImplicitSignUp =\n\t\t\t\t\tconfig.disableImplicitSignUp;\n\t\t\t\treturn provider as OAuthProvider;\n\t\t\t}),\n\t\t)\n\t).filter((x) => x !== null);\n\n\tconst generateIdFunc: AuthContext[\"generateId\"] = ({ model, size }) => {\n\t\tif (typeof (options.advanced as any)?.generateId === \"function\") {\n\t\t\treturn (options.advanced as any).generateId({ model, size });\n\t\t}\n\t\tconst dbGenerateId = options?.advanced?.database?.generateId;\n\t\tif (typeof dbGenerateId === \"function\") {\n\t\t\treturn dbGenerateId({ model, size });\n\t\t}\n\t\tif (dbGenerateId === \"uuid\") {\n\t\t\treturn crypto.randomUUID();\n\t\t}\n\t\tif (dbGenerateId === \"serial\" || dbGenerateId === false) {\n\t\t\treturn false;\n\t\t}\n\t\treturn generateId(size);\n\t};\n\n\tconst { publish } = await createTelemetry(options, {\n\t\tadapter: adapter.id,\n\t\tdatabase:\n\t\t\ttypeof options.database === \"function\"\n\t\t\t\t? \"adapter\"\n\t\t\t\t: getDatabaseType(options.database),\n\t});\n\n\tconst pluginIds = new Set(options.plugins!.map((p) => p.id));\n\n\tconst getPluginFn = (id: string) =>\n\t\t(options.plugins!.find((p) => p.id === id) as never | undefined) ?? null;\n\n\tconst hasPluginFn = (id: string) => pluginIds.has(id);\n\n\tconst trustedOrigins = await getTrustedOrigins(options);\n\tconst trustedProviders = await getTrustedProviders(options);\n\n\tconst ctx: AuthContext = {\n\t\tappName: options.appName || \"Better Auth\",\n\t\tbaseURL: baseURL || \"\",\n\t\tversion: getBetterAuthVersion(),\n\t\tsocialProviders: providers,\n\t\toptions,\n\t\toauthConfig: {\n\t\t\tstoreStateStrategy:\n\t\t\t\toptions.account?.storeStateStrategy ||\n\t\t\t\t(options.database ? \"database\" : \"cookie\"),\n\t\t\tskipStateCookieCheck: !!options.account?.skipStateCookieCheck,\n\t\t},\n\t\ttables,\n\t\ttrustedOrigins,\n\t\ttrustedProviders,\n\t\tisTrustedOrigin(\n\t\t\turl: string,\n\t\t\tsettings?: {\n\t\t\t\tallowRelativePaths: boolean;\n\t\t\t},\n\t\t) {\n\t\t\treturn this.trustedOrigins.some((origin) =>\n\t\t\t\tmatchesOriginPattern(url, origin, settings),\n\t\t\t);\n\t\t},\n\t\tsessionConfig: {\n\t\t\tupdateAge:\n\t\t\t\toptions.session?.updateAge !== undefined\n\t\t\t\t\t? options.session.updateAge\n\t\t\t\t\t: 24 * 60 * 60,\n\t\t\texpiresIn: options.session?.expiresIn || 60 * 60 * 24 * 7,\n\t\t\tfreshAge:\n\t\t\t\toptions.session?.freshAge === undefined\n\t\t\t\t\t? 60 * 60 * 24\n\t\t\t\t\t: options.session.freshAge,\n\t\t\tcookieRefreshCache: (() => {\n\t\t\t\tconst refreshCache = options.session?.cookieCache?.refreshCache;\n\t\t\t\tconst maxAge = options.session?.cookieCache?.maxAge || 60 * 5;\n\n\t\t\t\t// `refreshCache` is intended for fully stateless / DB-less setups.\n\t\t\t\t// If a server-side store is configured, prefer fetching/refreshing from that source\n\t\t\t\t// and disable stateless refresh behavior to avoid confusing/unsafe configurations.\n\t\t\t\tconst isStateful = !!options.database || !!options.secondaryStorage;\n\t\t\t\tif (isStateful && refreshCache) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\"[better-auth] `session.cookieCache.refreshCache` is enabled while `database` or `secondaryStorage` is configured. `refreshCache` is meant for stateless (DB-less) setups. Disabling `refreshCache` — remove it from your config to silence this warning.\",\n\t\t\t\t\t);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (refreshCache === false || refreshCache === undefined) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (refreshCache === true) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tupdateAge: Math.floor(maxAge * 0.2),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tupdateAge:\n\t\t\t\t\t\trefreshCache.updateAge !== undefined\n\t\t\t\t\t\t\t? refreshCache.updateAge\n\t\t\t\t\t\t\t: Math.floor(maxAge * 0.2),\n\t\t\t\t};\n\t\t\t})(),\n\t\t},\n\t\tsecret,\n\t\tsecretConfig,\n\t\trateLimit: {\n\t\t\t...options.rateLimit,\n\t\t\tenabled: options.rateLimit?.enabled ?? isProduction,\n\t\t\twindow: options.rateLimit?.window || 10,\n\t\t\tmax: options.rateLimit?.max || 100,\n\t\t\tstorage:\n\t\t\t\toptions.rateLimit?.storage ||\n\t\t\t\t(options.secondaryStorage ? \"secondary-storage\" : \"memory\"),\n\t\t},\n\t\tauthCookies: cookies,\n\t\tlogger,\n\t\tgenerateId: generateIdFunc,\n\t\tsession: null,\n\t\tsecondaryStorage: options.secondaryStorage,\n\t\tpassword: {\n\t\t\thash: options.emailAndPassword?.password?.hash || hashPassword,\n\t\t\tverify: options.emailAndPassword?.password?.verify || verifyPassword,\n\t\t\tconfig: {\n\t\t\t\tminPasswordLength: options.emailAndPassword?.minPasswordLength || 8,\n\t\t\t\tmaxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128,\n\t\t\t},\n\t\t\tcheckPassword,\n\t\t},\n\t\tsetNewSession(session) {\n\t\t\tthis.newSession = session;\n\t\t},\n\t\tnewSession: null,\n\t\tadapter: adapter,\n\t\tinternalAdapter: createInternalAdapter(adapter, {\n\t\t\toptions,\n\t\t\tlogger,\n\t\t\thooks: options.databaseHooks\n\t\t\t\t? [{ source: \"user\", hooks: options.databaseHooks }]\n\t\t\t\t: [],\n\t\t\tgenerateId: generateIdFunc,\n\t\t}),\n\t\tcreateAuthCookie: createCookieGetter(options),\n\t\tasync runMigrations() {\n\t\t\tthrow new BetterAuthError(\n\t\t\t\t\"runMigrations will be set by the specific init implementation\",\n\t\t\t);\n\t\t},\n\t\tpublishTelemetry: publish,\n\t\tskipCSRFCheck: !!options.advanced?.disableCSRFCheck,\n\t\tskipOriginCheck:\n\t\t\toptions.advanced?.disableOriginCheck !== undefined\n\t\t\t\t? options.advanced.disableOriginCheck\n\t\t\t\t: isTest()\n\t\t\t\t\t? true\n\t\t\t\t\t: false,\n\t\trunInBackground:\n\t\t\toptions.advanced?.backgroundTasks?.handler ??\n\t\t\t((p) => {\n\t\t\t\tp.catch(() => {});\n\t\t\t}),\n\t\tasync runInBackgroundOrAwait(\n\t\t\tpromise: Promise<unknown> | Promise<void> | void | unknown,\n\t\t) {\n\t\t\ttry {\n\t\t\t\tif (options.advanced?.backgroundTasks?.handler) {\n\t\t\t\t\tif (promise instanceof Promise) {\n\t\t\t\t\t\toptions.advanced.backgroundTasks.handler(\n\t\t\t\t\t\t\tpromise.catch((e) => {\n\t\t\t\t\t\t\t\tlogger.error(\"Failed to run background task:\", e);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tawait promise;\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(\"Failed to run background task:\", e);\n\t\t\t}\n\t\t},\n\t\tgetPlugin: getPluginFn,\n\t\thasPlugin: hasPluginFn as never,\n\t};\n\n\tconst initOrPromise = runPluginInit(ctx);\n\tif (isPromise(initOrPromise)) {\n\t\tawait initOrPromise;\n\t}\n\n\treturn ctx as unknown as AuthContext<Options>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAS,gBAAgB,KAAqB;CAC7C,MAAM,SAAS,IAAI,IAAI,IAAI,CAAC;AAC5B,KAAI,WAAW,EAAG,QAAO;AACzB,QAAO,KAAK,KAAK,KAAK,IAAI,QAAQ,IAAI,OAAO,CAAC;;;;;;;;AAS/C,SAAS,eACR,QACA,QACO;CACP,MAAM,kBAAkB,WAAW;AAEnC,KAAI,QAAQ,CACX;AAGD,KAAI,mBAAmB,aACtB,OAAM,IAAI,gBACT,wIACA;AAGF,KAAI,CAAC,OACJ,OAAM,IAAI,gBACT,wGACA;AAGF,KAAI,OAAO,SAAS,GACnB,QAAO,KACN,oLACA;AAKF,KADgB,gBAAgB,OAAO,GACzB,IACb,QAAO,KACN,sHACA;;AAIH,eAAsB,kBACrB,SACA,SACA,iBACgC;AAEhC,KAAI,CAAC,QAAQ,SACZ,WAAU,KAAK,SAAS;EACvB,SAAS,EACR,aAAa;GACZ,SAAS;GACT,UAAU;GACV,cAAc;GACd,EACD;EACD,SAAS;GACR,oBAAoB;GACpB,oBAAoB;GACpB;EACD,CAAC;CAEH,MAAM,UAAU,QAAQ,WAAW,EAAE;CACrC,MAAM,kBAAkB,mBAAmB,QAAQ;CACnD,MAAM,SAAS,aAAa,QAAQ,OAAO;CAE3C,MAAM,kBAAkB,uBAAuB,QAAQ,QAAQ;AAE/D,KAAI,uBAAuB,QAAQ,QAAQ,EAAE;EAC5C,MAAM,EAAE,iBAAiB,QAAQ;AACjC,MAAI,CAAC,gBAAgB,aAAa,WAAW,EAC5C,OAAM,IAAI,gBACT,6HAEA;;CAIH,MAAM,UAAU,kBACb,SACA,WACA,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,QACxD,QAAQ,SACR;AAEH,KAAI,CAAC,WAAW,CAAC,gBAChB,QAAO,KACN,yNACA;AAGF,KACC,QAAQ,OAAO,YACf,QAAQ,UAAU,UAAU,eAAe,MAE3C,QAAO,MACN;;;8DAIA;CAGF,MAAM,eACL,QAAQ,WAAW,gBAAgB,IAAI,oBAAoB;CAE5D,MAAM,eACL,QAAQ,UAAU,IAAI,sBAAsB,IAAI,eAAe;CAEhE,IAAI;CACJ,IAAI;AAEJ,KAAI,cAAc;AACjB,uBAAqB,cAAc,OAAO;AAC1C,WAAS,aAAa,GAAI;AAC1B,iBAAe,kBAAkB,cAAc,aAAa;QACtD;AACN,WAAS,gBAAgB;AACzB,iBAAe,QAAQ,OAAO;AAC9B,iBAAe;;AAGhB,WAAU;EACT,GAAG;EACH;EACA,SAAS,kBACN,QAAQ,UACR,UACC,IAAI,IAAI,QAAQ,CAAC,SACjB;EACJ,UAAU,QAAQ,YAAY;EAC9B,SAAS,QAAQ,OAAO,gBAAgB;EACxC;AAED,wBAAuB,SAAS,OAAO;CACvC,MAAM,UAAU,WAAW,QAAQ;CACnC,MAAM,SAAS,cAAc,QAAQ;CACrC,MAAM,aACL,MAAM,QAAQ,IAEZ,OAAO,QACN,QAAQ,mBAAmB,EAAE,CAC7B,CACA,IAAI,OAAO,CAAC,KAAK,oBAAoB;EACtC,MAAM,SACL,OAAO,mBAAmB,aACvB,MAAM,gBAAgB,GACtB;AACJ,MAAI,UAAU,KACb,QAAO;AAER,MAAI,OAAO,YAAY,MACtB,QAAO;AAER,MAAI,CAAC,OAAO,SACX,QAAO,KACN,mBAAmB,IAAI,sCACvB;EAEF,MAAM,WAAW,gBAAgB,KAAK,OAAgB;AACtD,EAAC,SAA2B,wBAC3B,OAAO;AACR,SAAO;GACN,CACF,EACA,QAAQ,MAAM,MAAM,KAAK;CAE3B,MAAM,kBAA6C,EAAE,OAAO,WAAW;AACtE,MAAI,OAAQ,QAAQ,UAAkB,eAAe,WACpD,QAAQ,QAAQ,SAAiB,WAAW;GAAE;GAAO;GAAM,CAAC;EAE7D,MAAM,eAAe,SAAS,UAAU,UAAU;AAClD,MAAI,OAAO,iBAAiB,WAC3B,QAAO,aAAa;GAAE;GAAO;GAAM,CAAC;AAErC,MAAI,iBAAiB,OACpB,QAAO,OAAO,YAAY;AAE3B,MAAI,iBAAiB,YAAY,iBAAiB,MACjD,QAAO;AAER,SAAO,WAAW,KAAK;;CAGxB,MAAM,EAAE,YAAY,MAAM,gBAAgB,SAAS;EAClD,SAAS,QAAQ;EACjB,UACC,OAAO,QAAQ,aAAa,aACzB,YACA,gBAAgB,QAAQ,SAAS;EACrC,CAAC;CAEF,MAAM,YAAY,IAAI,IAAI,QAAQ,QAAS,KAAK,MAAM,EAAE,GAAG,CAAC;CAE5D,MAAM,eAAe,OACnB,QAAQ,QAAS,MAAM,MAAM,EAAE,OAAO,GAAG,IAA0B;CAErE,MAAM,eAAe,OAAe,UAAU,IAAI,GAAG;CAErD,MAAM,iBAAiB,MAAM,kBAAkB,QAAQ;CACvD,MAAM,mBAAmB,MAAM,oBAAoB,QAAQ;CAE3D,MAAM,MAAmB;EACxB,SAAS,QAAQ,WAAW;EAC5B,SAAS,WAAW;EACpB,SAAS,sBAAsB;EAC/B,iBAAiB;EACjB;EACA,aAAa;GACZ,oBACC,QAAQ,SAAS,uBAChB,QAAQ,WAAW,aAAa;GAClC,sBAAsB,CAAC,CAAC,QAAQ,SAAS;GACzC;EACD;EACA;EACA;EACA,gBACC,KACA,UAGC;AACD,UAAO,KAAK,eAAe,MAAM,WAChC,qBAAqB,KAAK,QAAQ,SAAS,CAC3C;;EAEF,eAAe;GACd,WACC,QAAQ,SAAS,cAAc,SAC5B,QAAQ,QAAQ,YAChB,OAAU;GACd,WAAW,QAAQ,SAAS,aAAa,OAAU,KAAK;GACxD,UACC,QAAQ,SAAS,aAAa,SAC3B,OAAU,KACV,QAAQ,QAAQ;GACpB,2BAA2B;IAC1B,MAAM,eAAe,QAAQ,SAAS,aAAa;IACnD,MAAM,SAAS,QAAQ,SAAS,aAAa,UAAU;AAMvD,SADmB,CAAC,CAAC,QAAQ,YAAY,CAAC,CAAC,QAAQ,qBACjC,cAAc;AAC/B,YAAO,KACN,2PACA;AACD,YAAO;;AAGR,QAAI,iBAAiB,SAAS,iBAAiB,OAC9C,QAAO;AAGR,QAAI,iBAAiB,KACpB,QAAO;KACN,SAAS;KACT,WAAW,KAAK,MAAM,SAAS,GAAI;KACnC;AAGF,WAAO;KACN,SAAS;KACT,WACC,aAAa,cAAc,SACxB,aAAa,YACb,KAAK,MAAM,SAAS,GAAI;KAC5B;OACE;GACJ;EACD;EACA;EACA,WAAW;GACV,GAAG,QAAQ;GACX,SAAS,QAAQ,WAAW,WAAW;GACvC,QAAQ,QAAQ,WAAW,UAAU;GACrC,KAAK,QAAQ,WAAW,OAAO;GAC/B,SACC,QAAQ,WAAW,YAClB,QAAQ,mBAAmB,sBAAsB;GACnD;EACD,aAAa;EACb;EACA,YAAY;EACZ,SAAS;EACT,kBAAkB,QAAQ;EAC1B,UAAU;GACT,MAAM,QAAQ,kBAAkB,UAAU,QAAQ;GAClD,QAAQ,QAAQ,kBAAkB,UAAU,UAAU;GACtD,QAAQ;IACP,mBAAmB,QAAQ,kBAAkB,qBAAqB;IAClE,mBAAmB,QAAQ,kBAAkB,qBAAqB;IAClE;GACD;GACA;EACD,cAAc,SAAS;AACtB,QAAK,aAAa;;EAEnB,YAAY;EACH;EACT,iBAAiB,sBAAsB,SAAS;GAC/C;GACA;GACA,OAAO,QAAQ,gBACZ,CAAC;IAAE,QAAQ;IAAQ,OAAO,QAAQ;IAAe,CAAC,GAClD,EAAE;GACL,YAAY;GACZ,CAAC;EACF,kBAAkB,mBAAmB,QAAQ;EAC7C,MAAM,gBAAgB;AACrB,SAAM,IAAI,gBACT,gEACA;;EAEF,kBAAkB;EAClB,eAAe,CAAC,CAAC,QAAQ,UAAU;EACnC,iBACC,QAAQ,UAAU,uBAAuB,SACtC,QAAQ,SAAS,qBACjB,QAAQ,GACP,OACA;EACL,iBACC,QAAQ,UAAU,iBAAiB,aACjC,MAAM;AACP,KAAE,YAAY,GAAG;;EAEnB,MAAM,uBACL,SACC;AACD,OAAI;AACH,QAAI,QAAQ,UAAU,iBAAiB,SACtC;SAAI,mBAAmB,QACtB,SAAQ,SAAS,gBAAgB,QAChC,QAAQ,OAAO,MAAM;AACpB,aAAO,MAAM,kCAAkC,EAAE;OAChD,CACF;UAGF,OAAM;YAEC,GAAG;AACX,WAAO,MAAM,kCAAkC,EAAE;;;EAGnD,WAAW;EACX,WAAW;EACX;CAED,MAAM,gBAAgB,cAAc,IAAI;AACxC,KAAI,UAAU,cAAc,CAC3B,OAAM;AAGP,QAAO"}
|
package/dist/context/helpers.mjs
CHANGED
|
@@ -9,8 +9,8 @@ import { defu as defu$1 } from "defu";
|
|
|
9
9
|
async function runPluginInit(context) {
|
|
10
10
|
let options = context.options;
|
|
11
11
|
const plugins = options.plugins || [];
|
|
12
|
-
const dbHooks = [];
|
|
13
12
|
const pluginTrustedOrigins = [];
|
|
13
|
+
const dbHooks = [];
|
|
14
14
|
for (const plugin of plugins) if (plugin.init) {
|
|
15
15
|
const initPromise = plugin.init(context);
|
|
16
16
|
let result;
|
|
@@ -19,7 +19,10 @@ async function runPluginInit(context) {
|
|
|
19
19
|
if (typeof result === "object") {
|
|
20
20
|
if (result.options) {
|
|
21
21
|
const { databaseHooks, trustedOrigins, ...restOpts } = result.options;
|
|
22
|
-
if (databaseHooks) dbHooks.push(
|
|
22
|
+
if (databaseHooks) dbHooks.push({
|
|
23
|
+
source: `plugin:${plugin.id}`,
|
|
24
|
+
hooks: databaseHooks
|
|
25
|
+
});
|
|
23
26
|
if (trustedOrigins) pluginTrustedOrigins.push(trustedOrigins);
|
|
24
27
|
options = defu$1(options, restOpts);
|
|
25
28
|
}
|
|
@@ -36,11 +39,14 @@ async function runPluginInit(context) {
|
|
|
36
39
|
};
|
|
37
40
|
else options.trustedOrigins = staticOrigins;
|
|
38
41
|
}
|
|
39
|
-
|
|
42
|
+
if (options.databaseHooks) dbHooks.push({
|
|
43
|
+
source: "user",
|
|
44
|
+
hooks: options.databaseHooks
|
|
45
|
+
});
|
|
40
46
|
context.internalAdapter = createInternalAdapter(context.adapter, {
|
|
41
47
|
options,
|
|
42
48
|
logger: context.logger,
|
|
43
|
-
hooks: dbHooks
|
|
49
|
+
hooks: dbHooks,
|
|
44
50
|
generateId: context.generateId
|
|
45
51
|
});
|
|
46
52
|
context.options = options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.mjs","names":["defu"],"sources":["../../src/context/helpers.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tAwaitableFunction,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\nimport { env } from \"@better-auth/core/env\";\nimport { defu } from \"defu\";\nimport { createInternalAdapter } from \"../db\";\nimport { isPromise } from \"../utils/is-promise\";\nimport { getBaseURL, isDynamicBaseURLConfig } from \"../utils/url\";\n\nexport async function runPluginInit(context: AuthContext) {\n\tlet options = context.options;\n\tconst plugins = options.plugins || [];\n\tconst
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":["defu"],"sources":["../../src/context/helpers.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tAwaitableFunction,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\nimport { env } from \"@better-auth/core/env\";\nimport { defu } from \"defu\";\nimport { createInternalAdapter } from \"../db\";\nimport { isPromise } from \"../utils/is-promise\";\nimport { getBaseURL, isDynamicBaseURLConfig } from \"../utils/url\";\n\nexport async function runPluginInit(context: AuthContext) {\n\tlet options = context.options;\n\tconst plugins = options.plugins || [];\n\tconst pluginTrustedOrigins: NonNullable<\n\t\tBetterAuthOptions[\"trustedOrigins\"]\n\t>[] = [];\n\tconst dbHooks: {\n\t\tsource: string;\n\t\thooks: Exclude<BetterAuthOptions[\"databaseHooks\"], undefined>;\n\t}[] = [];\n\tfor (const plugin of plugins) {\n\t\tif (plugin.init) {\n\t\t\tconst initPromise = plugin.init(context);\n\t\t\tlet result: ReturnType<Required<BetterAuthPlugin>[\"init\"]>;\n\t\t\tif (isPromise(initPromise)) {\n\t\t\t\tresult = await initPromise;\n\t\t\t} else {\n\t\t\t\tresult = initPromise;\n\t\t\t}\n\t\t\tif (typeof result === \"object\") {\n\t\t\t\tif (result.options) {\n\t\t\t\t\tconst { databaseHooks, trustedOrigins, ...restOpts } = result.options;\n\t\t\t\t\tif (databaseHooks) {\n\t\t\t\t\t\tdbHooks.push({\n\t\t\t\t\t\t\tsource: `plugin:${plugin.id}`,\n\t\t\t\t\t\t\thooks: databaseHooks,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (trustedOrigins) {\n\t\t\t\t\t\tpluginTrustedOrigins.push(trustedOrigins);\n\t\t\t\t\t}\n\t\t\t\t\toptions = defu(options, restOpts);\n\t\t\t\t}\n\t\t\t\tif (result.context) {\n\t\t\t\t\t// Use Object.assign to keep the reference to the original context\n\t\t\t\t\tObject.assign(context, result.context);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (pluginTrustedOrigins.length > 0) {\n\t\tconst allSources = [\n\t\t\t...(options.trustedOrigins ? [options.trustedOrigins] : []),\n\t\t\t...pluginTrustedOrigins,\n\t\t];\n\t\tconst staticOrigins = allSources.filter(Array.isArray).flat();\n\t\tconst dynamicOrigins = allSources.filter(\n\t\t\t(s): s is Exclude<typeof s, string[]> => typeof s === \"function\",\n\t\t);\n\t\tif (dynamicOrigins.length > 0) {\n\t\t\toptions.trustedOrigins = async (request) => {\n\t\t\t\tconst resolved = await Promise.all(\n\t\t\t\t\tdynamicOrigins.map((fn) => fn(request)),\n\t\t\t\t);\n\t\t\t\treturn [...staticOrigins, ...resolved.flat()].filter(\n\t\t\t\t\t(v): v is string => typeof v === \"string\" && v !== \"\",\n\t\t\t\t);\n\t\t\t};\n\t\t} else {\n\t\t\toptions.trustedOrigins = staticOrigins;\n\t\t}\n\t}\n\n\t// Add the global database hooks last\n\tif (options.databaseHooks) {\n\t\tdbHooks.push({ source: \"user\", hooks: options.databaseHooks });\n\t}\n\n\tcontext.internalAdapter = createInternalAdapter(context.adapter, {\n\t\toptions,\n\t\tlogger: context.logger,\n\t\thooks: dbHooks,\n\t\tgenerateId: context.generateId,\n\t});\n\tcontext.options = options;\n}\n\nexport function getInternalPlugins(options: BetterAuthOptions) {\n\tconst plugins: BetterAuthPlugin[] = [];\n\tif (options.advanced?.crossSubDomainCookies?.enabled) {\n\t\t// TODO: add internal plugin\n\t}\n\treturn plugins;\n}\n\nexport async function getTrustedOrigins(\n\toptions: BetterAuthOptions,\n\trequest?: Request,\n): Promise<string[]> {\n\tconst trustedOrigins: (string | undefined | null)[] = [];\n\n\tif (isDynamicBaseURLConfig(options.baseURL)) {\n\t\tconst allowedHosts = options.baseURL.allowedHosts;\n\t\tfor (const host of allowedHosts) {\n\t\t\tif (!host.includes(\"://\")) {\n\t\t\t\ttrustedOrigins.push(`https://${host}`);\n\t\t\t\tif (host.includes(\"localhost\") || host.includes(\"127.0.0.1\")) {\n\t\t\t\t\ttrustedOrigins.push(`http://${host}`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttrustedOrigins.push(host);\n\t\t\t}\n\t\t}\n\n\t\tif (options.baseURL.fallback) {\n\t\t\ttry {\n\t\t\t\ttrustedOrigins.push(new URL(options.baseURL.fallback).origin);\n\t\t\t} catch {}\n\t\t}\n\t} else {\n\t\tconst baseURL = getBaseURL(\n\t\t\ttypeof options.baseURL === \"string\" ? options.baseURL : undefined,\n\t\t\toptions.basePath,\n\t\t\trequest,\n\t\t);\n\t\tif (baseURL) {\n\t\t\ttrustedOrigins.push(new URL(baseURL).origin);\n\t\t}\n\t}\n\n\tif (options.trustedOrigins) {\n\t\tif (Array.isArray(options.trustedOrigins)) {\n\t\t\ttrustedOrigins.push(...options.trustedOrigins);\n\t\t}\n\t\tif (typeof options.trustedOrigins === \"function\") {\n\t\t\tconst validOrigins = await options.trustedOrigins(request);\n\t\t\ttrustedOrigins.push(...validOrigins);\n\t\t}\n\t}\n\tconst envTrustedOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS;\n\tif (envTrustedOrigins) {\n\t\ttrustedOrigins.push(...envTrustedOrigins.split(\",\"));\n\t}\n\treturn trustedOrigins.filter((v): v is string => Boolean(v));\n}\n\nexport async function getAwaitableValue<T extends Record<string, any>>(\n\tarr: AwaitableFunction<T>[] | undefined,\n\titem: { field?: string; value: string },\n): Promise<T | undefined> {\n\tif (!arr) return undefined;\n\tfor (const val of arr) {\n\t\tconst value = typeof val === \"function\" ? await val() : val;\n\t\tif (value[item.field ?? \"id\"] === item.value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport async function getTrustedProviders(\n\toptions: BetterAuthOptions,\n\trequest?: Request,\n): Promise<string[]> {\n\tconst trustedProviders = options.account?.accountLinking?.trustedProviders;\n\tif (!trustedProviders) {\n\t\treturn [];\n\t}\n\tif (Array.isArray(trustedProviders)) {\n\t\treturn trustedProviders.filter((v): v is string => Boolean(v));\n\t}\n\tconst resolved = await trustedProviders(request);\n\treturn (resolved ?? []).filter((v): v is string => Boolean(v));\n}\n"],"mappings":"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"}
|
package/dist/cookies/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Session, User } from "../types/models.mjs";
|
|
2
|
-
import "../types/index.mjs";
|
|
3
2
|
import { CookieAttributes, HOST_COOKIE_PREFIX, SECURE_COOKIE_PREFIX, parseSetCookieHeader, setCookieToHeader, splitSetCookieHeader, stripSecureCookiePrefix } from "./cookie-utils.mjs";
|
|
4
3
|
import { createSessionStore, getAccountCookie, getChunkedCookie } from "./session-store.mjs";
|
|
5
4
|
import { BetterAuthCookie, BetterAuthCookies, BetterAuthOptions, GenericEndpointContext } from "@better-auth/core";
|
|
@@ -274,8 +274,9 @@ async function getMigrations(config) {
|
|
|
274
274
|
const type = getType(field, fieldName);
|
|
275
275
|
const builder = db.schema.alterTable(table.table);
|
|
276
276
|
if (field.index) {
|
|
277
|
-
const
|
|
278
|
-
|
|
277
|
+
const indexName = `${table.table}_${fieldName}_${field.unique ? "uidx" : "idx"}`;
|
|
278
|
+
const indexBuilder = db.schema.createIndex(indexName).on(table.table).columns([fieldName]);
|
|
279
|
+
migrations.push(field.unique ? indexBuilder.unique() : indexBuilder);
|
|
279
280
|
}
|
|
280
281
|
const built = builder.addColumn(fieldName, type, (col) => {
|
|
281
282
|
col = field.required !== false ? col.notNull() : col;
|