better-auth 1.6.17 → 1.6.19

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.
@@ -1,19 +1,30 @@
1
1
  import { symmetricDecodeJWT, symmetricEncodeJWT } from "../crypto/jwt.mjs";
2
2
  import { parseCookies } from "./cookie-utils.mjs";
3
3
  import { safeJSONParse } from "@better-auth/core/utils/json";
4
+ import { serializeCookie } from "better-call";
4
5
  import * as z from "zod";
5
6
  //#region src/cookies/session-store.ts
6
- const ALLOWED_COOKIE_SIZE = 4096;
7
- const ESTIMATED_EMPTY_COOKIE_SIZE = 200;
8
- const CHUNK_SIZE = ALLOWED_COOKIE_SIZE - ESTIMATED_EMPTY_COOKIE_SIZE;
9
7
  /**
10
- * Extract the chunk index from a cookie name
8
+ * Per-cookie byte ceiling.
9
+ * Safari's ~4093 floor is the lowest among browsers.
10
+ * Kept a little under it for attributes added after sizing.
11
+ *
12
+ * @see https://datatracker.ietf.org/doc/html/rfc6265#section-6.1
13
+ * @see https://github.com/dotnet/aspnetcore/blob/aa5493528640932601bb82ef3295e4d8ca7e11c5/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs#L40
14
+ */
15
+ const MAX_COOKIE_SIZE = 4050;
16
+ /**
17
+ * Max chunks per cookie.
18
+ * A larger value does not belong in a cookie.
11
19
  */
12
- function getChunkIndex(cookieName) {
13
- const parts = cookieName.split(".");
14
- const lastPart = parts[parts.length - 1];
15
- const index = parseInt(lastPart || "0", 10);
16
- return isNaN(index) ? 0 : index;
20
+ const MAX_COOKIE_CHUNKS = 100;
21
+ /**
22
+ * Largest value that keeps the serialized cookie within {@link MAX_COOKIE_SIZE},
23
+ * measured with the real `serializeCookie` writer so it stays in sync with the
24
+ * wire. Non-positive when the name and attributes alone overflow.
25
+ */
26
+ function getMaxCookieValueSize(name, options) {
27
+ return MAX_COOKIE_SIZE - serializeCookie(name, "", { ...options }).length;
17
28
  }
18
29
  /**
19
30
  * Read all existing chunks from cookies
@@ -25,27 +36,24 @@ function readExistingChunks(cookieName, ctx) {
25
36
  return chunks;
26
37
  }
27
38
  /**
28
- * Get the full session data by joining all chunks
29
- */
30
- function joinChunks(chunks) {
31
- return Object.keys(chunks).sort((a, b) => {
32
- return getChunkIndex(a) - getChunkIndex(b);
33
- }).map((key) => chunks[key]).join("");
34
- }
35
- /**
36
39
  * Split a cookie value into chunks if needed
37
40
  */
38
41
  function chunkCookie(storeName, cookie, chunks, logger) {
39
- const chunkCount = Math.ceil(cookie.value.length / CHUNK_SIZE);
40
- if (chunkCount === 1) {
42
+ const chunkSize = getMaxCookieValueSize(`${cookie.name}.${MAX_COOKIE_CHUNKS - 1}`, cookie.attributes);
43
+ const chunkCount = chunkSize > 0 ? Math.ceil(cookie.value.length / chunkSize) : Infinity;
44
+ if (chunkCount <= 1) {
41
45
  chunks[cookie.name] = cookie.value;
42
46
  return [cookie];
43
47
  }
48
+ if (chunkCount > MAX_COOKIE_CHUNKS) {
49
+ logger.warn(`${storeName} cookie is too large to store even after chunking, so the cache was skipped. Reduce the cached data or use a database session.`);
50
+ return [];
51
+ }
44
52
  const cookies = [];
45
53
  for (let i = 0; i < chunkCount; i++) {
46
54
  const name = `${cookie.name}.${i}`;
47
- const start = i * CHUNK_SIZE;
48
- const value = cookie.value.substring(start, start + CHUNK_SIZE);
55
+ const start = i * chunkSize;
56
+ const value = cookie.value.substring(start, start + chunkSize);
49
57
  cookies.push({
50
58
  ...cookie,
51
59
  name,
@@ -54,11 +62,10 @@ function chunkCookie(storeName, cookie, chunks, logger) {
54
62
  chunks[name] = value;
55
63
  }
56
64
  logger.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, {
57
- message: `${storeName} cookie exceeds allowed ${ALLOWED_COOKIE_SIZE} bytes.`,
58
- emptyCookieSize: ESTIMATED_EMPTY_COOKIE_SIZE,
65
+ message: `${storeName} cookie exceeds the ${MAX_COOKIE_SIZE} byte limit and was split into ${chunkCount} chunks.`,
59
66
  valueSize: cookie.value.length,
60
67
  chunkCount,
61
- chunks: cookies.map((c) => c.value.length + ESTIMATED_EMPTY_COOKIE_SIZE)
68
+ chunkSizes: cookies.map((c) => c.value.length)
62
69
  });
63
70
  return cookies;
64
71
  }
@@ -78,26 +85,22 @@ function getCleanCookies(chunks, cookieOptions) {
78
85
  return cleanedChunks;
79
86
  }
80
87
  /**
81
- * Create a session store for handling cookie chunking.
82
- * When session data exceeds 4KB, it automatically splits it into multiple cookies.
88
+ * Store that splits a cookie into numbered chunks when its serialized form
89
+ * would exceed the per-cookie byte limit, expiring stale chunks as needed.
83
90
  *
84
- * Based on next-auth's SessionStore implementation.
85
91
  * @see https://github.com/nextauthjs/next-auth/blob/27b2519b84b8eb9cf053775dea29d577d2aa0098/packages/next-auth/src/core/lib/cookie.ts
86
92
  */
87
93
  const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => {
88
94
  const chunks = readExistingChunks(cookieName, ctx);
89
95
  const logger = ctx.context.logger;
96
+ const expireExistingChunks = () => {
97
+ const expired = getCleanCookies(chunks, cookieOptions);
98
+ for (const name in chunks) delete chunks[name];
99
+ return expired;
100
+ };
90
101
  return {
91
- getValue() {
92
- return joinChunks(chunks);
93
- },
94
- hasChunks() {
95
- return Object.keys(chunks).length > 0;
96
- },
97
102
  chunk(value, options) {
98
- const cleanedChunks = getCleanCookies(chunks, cookieOptions);
99
- for (const name in chunks) delete chunks[name];
100
- const cookies = cleanedChunks;
103
+ const cookies = expireExistingChunks();
101
104
  const chunked = chunkCookie(storeName, {
102
105
  name: cookieName,
103
106
  value,
@@ -110,9 +113,7 @@ const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => {
110
113
  return Object.values(cookies);
111
114
  },
112
115
  clean() {
113
- const cleanedChunks = getCleanCookies(chunks, cookieOptions);
114
- for (const name in chunks) delete chunks[name];
115
- return Object.values(cleanedChunks);
116
+ return Object.values(expireExistingChunks());
116
117
  },
117
118
  setCookies(cookies) {
118
119
  for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes);
@@ -148,18 +149,8 @@ async function setAccountCookie(c, accountData) {
148
149
  ...accountDataCookie.attributes
149
150
  };
150
151
  const data = await symmetricEncodeJWT(accountData, c.context.secretConfig, "better-auth-account", options.maxAge);
151
- if (data.length > ALLOWED_COOKIE_SIZE) {
152
- const accountStore = createAccountStore(accountDataCookie.name, options, c);
153
- const cookies = accountStore.chunk(data, options);
154
- accountStore.setCookies(cookies);
155
- } else {
156
- const accountStore = createAccountStore(accountDataCookie.name, options, c);
157
- if (accountStore.hasChunks()) {
158
- const cleanCookies = accountStore.clean();
159
- accountStore.setCookies(cleanCookies);
160
- }
161
- c.setCookie(accountDataCookie.name, data, options);
162
- }
152
+ const accountStore = createAccountStore(accountDataCookie.name, options, c);
153
+ accountStore.setCookies(accountStore.chunk(data, options));
163
154
  }
164
155
  async function getAccountCookie(c) {
165
156
  const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name);
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "1.6.17";
2
+ var version = "1.6.19";
3
3
  //#endregion
4
4
  export { version };
@@ -104,6 +104,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
104
104
  method: "POST";
105
105
  body: z.ZodObject<{
106
106
  client_id: z.ZodString;
107
+ user_id: z.ZodOptional<z.ZodString>;
107
108
  scope: z.ZodOptional<z.ZodString>;
108
109
  }, z.core.$strip>;
109
110
  error: z.ZodObject<{
@@ -9,6 +9,7 @@ import * as z from "zod";
9
9
  const defaultCharset = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
10
10
  const deviceCodeBodySchema = z.object({
11
11
  client_id: z.string().meta({ description: "The client ID of the application" }),
12
+ user_id: z.string().meta({ description: "The user ID to which the device code should be pre-bound." }).optional(),
12
13
  scope: z.string().meta({ description: "Space-separated list of scopes" }).optional()
13
14
  });
14
15
  const deviceCodeErrorSchema = z.object({
@@ -99,7 +100,7 @@ Follow [rfc8628#section-3.2](https://datatracker.ietf.org/doc/html/rfc8628#secti
99
100
  data: {
100
101
  deviceCode,
101
102
  userCode,
102
- userId: null,
103
+ userId: ctx.body.user_id || null,
103
104
  expiresAt,
104
105
  status: "pending",
105
106
  pollingInterval: ms(opts.interval),
@@ -341,7 +342,7 @@ const deviceVerify = createAuthEndpoint("/device", {
341
342
  });
342
343
  const session = await getSessionFromCtx(ctx);
343
344
  if (session?.user?.id && !deviceCodeRecord.userId && deviceCodeRecord.status === "pending") {
344
- if (await ctx.context.adapter.update({
345
+ if (await ctx.context.adapter.incrementOne({
345
346
  model: "deviceCode",
346
347
  where: [
347
348
  {
@@ -358,7 +359,8 @@ const deviceVerify = createAuthEndpoint("/device", {
358
359
  value: null
359
360
  }
360
361
  ],
361
- update: { userId: session.user.id }
362
+ increment: {},
363
+ set: { userId: session.user.id }
362
364
  })) deviceCodeRecord.userId = session.user.id;
363
365
  }
364
366
  return ctx.json({
@@ -48,7 +48,7 @@ import { OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_SCRIPT_CSP_HASH, oauthPopup }
48
48
  import { OAuthProxyOptions, oAuthProxy } from "./oauth-proxy/index.mjs";
49
49
  import { OneTapOptions, oneTap } from "./one-tap/index.mjs";
50
50
  import { OneTimeTokenOptions, oneTimeToken } from "./one-time-token/index.mjs";
51
- import { FieldSchema, OpenAPIModelSchema, Path, generator } from "./open-api/generator.mjs";
51
+ import { FieldSchema, OpenAPIModelSchema, OpenAPIParameter, OpenAPISchema, Path, generator } from "./open-api/generator.mjs";
52
52
  import { OpenAPIOptions, openAPI } from "./open-api/index.mjs";
53
53
  import { PhoneNumberOptions, UserWithPhoneNumber } from "./phone-number/types.mjs";
54
54
  import { phoneNumber } from "./phone-number/index.mjs";
@@ -66,4 +66,4 @@ import { USERNAME_ERROR_CODES } from "./username/error-codes.mjs";
66
66
  import { UsernameOptions, username } from "./username/index.mjs";
67
67
  import { hasPermission } from "./organization/has-permission.mjs";
68
68
  import { DefaultOrganizationPlugin, DynamicAccessControlEndpoints, OrganizationCreator, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "./organization/organization.mjs";
69
- export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, Client, CloudflareTurnstileOptions, CodeVerificationValue, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthAccessToken, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberSchema, microsoftEntraId, ms, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oauthPopup, oidcProvider, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
69
+ export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, Client, CloudflareTurnstileOptions, CodeVerificationValue, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthAccessToken, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberSchema, microsoftEntraId, ms, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oauthPopup, oidcProvider, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
@@ -8,6 +8,16 @@ interface LastLoginMethodClientConfig {
8
8
  * @default "better-auth.last_used_login_method"
9
9
  */
10
10
  cookieName?: string | undefined;
11
+ /**
12
+ * Domain for the cookie. Required when using cross-subdomain cookies
13
+ * so the client can properly clear the cookie set by the server.
14
+ *
15
+ * Should match the `domain` value in your server's
16
+ * `crossSubDomainCookies` configuration.
17
+ *
18
+ * @example ".example.com"
19
+ */
20
+ domain?: string | undefined;
11
21
  }
12
22
  /**
13
23
  * Client-side plugin to retrieve the last used login method
@@ -19,7 +19,10 @@ const lastLoginMethodClient = (config = {}) => {
19
19
  return getCookieValue(cookieName);
20
20
  },
21
21
  clearLastUsedLoginMethod: () => {
22
- if (typeof document !== "undefined") document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
22
+ if (typeof document !== "undefined") {
23
+ const domainPart = config.domain ? ` domain=${config.domain};` : "";
24
+ document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;${domainPart}`;
25
+ }
23
26
  },
24
27
  isLastUsedLoginMethod: (method) => {
25
28
  return getCookieValue(cookieName) === method;
@@ -3,7 +3,7 @@ import { generateRandomString } from "../../crypto/random.mjs";
3
3
  import { expireCookie } from "../../cookies/index.mjs";
4
4
  import { getAwaitableValue } from "../../context/helpers.mjs";
5
5
  import { setOAuthState } from "../../api/state/oauth.mjs";
6
- import { generateGenericState } from "../../state.mjs";
6
+ import { INTERNAL_STATE_KEYS, generateGenericState } from "../../state.mjs";
7
7
  import { HIDE_METADATA } from "../../utils/hide-metadata.mjs";
8
8
  import { PACKAGE_VERSION } from "../../version.mjs";
9
9
  import { OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_MESSAGE_TYPE, POPUP_MARKER_COOKIE } from "./constants.mjs";
@@ -132,8 +132,9 @@ const oauthPopupStart = createAuthEndpoint("/oauth-popup/start", {
132
132
  let url;
133
133
  try {
134
134
  const codeVerifier = generateRandomString(128);
135
+ const parsedAdditionalData = c.query.additionalData ? safeJSONParse(c.query.additionalData) ?? {} : {};
135
136
  const stateData = {
136
- ...c.query.additionalData ? safeJSONParse(c.query.additionalData) ?? {} : {},
137
+ ...Object.fromEntries(Object.entries(parsedAdditionalData).filter(([key]) => !INTERNAL_STATE_KEYS.has(key))),
137
138
  callbackURL,
138
139
  codeVerifier,
139
140
  errorURL: c.query.errorCallbackURL,
@@ -4,66 +4,75 @@ import { OpenAPIParameter, OpenAPISchemaType } from "better-call";
4
4
 
5
5
  //#region src/plugins/open-api/generator.d.ts
6
6
  interface Path {
7
- get?: {
8
- tags?: string[];
9
- operationId?: string;
10
- description?: string;
11
- security?: [{
12
- bearerAuth: string[];
13
- }];
14
- parameters?: OpenAPIParameter[];
15
- responses?: { [key in string]: {
16
- description?: string;
17
- content: {
18
- "application/json": {
19
- schema: {
20
- type?: OpenAPISchemaType;
21
- properties?: Record<string, any>;
22
- required?: string[];
23
- $ref?: string;
24
- };
25
- };
26
- };
27
- } };
28
- } | undefined;
29
- post?: {
30
- tags?: string[];
31
- operationId?: string;
32
- description?: string;
33
- security?: [{
34
- bearerAuth: string[];
35
- }];
36
- parameters?: OpenAPIParameter[];
37
- requestBody?: {
38
- content: {
39
- "application/json": {
40
- schema: {
41
- type?: OpenAPISchemaType;
42
- properties?: Record<string, any>;
43
- required?: string[];
44
- $ref?: string;
45
- };
46
- };
47
- };
48
- };
49
- responses?: { [key in string]: {
50
- description?: string;
51
- content: {
52
- "application/json": {
53
- schema: {
54
- type?: OpenAPISchemaType;
55
- properties?: Record<string, any>;
56
- required?: string[];
57
- $ref?: string;
58
- };
59
- };
60
- };
61
- } };
62
- } | undefined;
7
+ get?: OpenAPIOperation | undefined;
8
+ post?: OpenAPIOperation | undefined;
9
+ put?: OpenAPIOperation | undefined;
10
+ patch?: OpenAPIOperation | undefined;
11
+ delete?: OpenAPIOperation | undefined;
63
12
  }
13
+ type OpenAPISchemaPrimitiveType = OpenAPISchemaType | "null";
14
+ type OpenAPISchema = {
15
+ type?: OpenAPISchemaPrimitiveType | OpenAPISchemaPrimitiveType[];
16
+ properties?: Record<string, OpenAPISchema>;
17
+ required?: string[];
18
+ $ref?: string;
19
+ description?: string;
20
+ default?: unknown;
21
+ readOnly?: boolean;
22
+ format?: string;
23
+ deprecated?: boolean;
24
+ enum?: unknown[];
25
+ items?: OpenAPISchema;
26
+ minLength?: number;
27
+ maxLength?: number;
28
+ minimum?: number;
29
+ maximum?: number;
30
+ additionalProperties?: boolean | OpenAPISchema;
31
+ propertyNames?: OpenAPISchema;
32
+ allOf?: OpenAPISchema[];
33
+ anyOf?: OpenAPISchema[];
34
+ oneOf?: OpenAPISchema[];
35
+ const?: unknown;
36
+ example?: unknown;
37
+ };
38
+ type OpenAPIParameter$1 = Omit<OpenAPIParameter, "schema"> & {
39
+ schema?: OpenAPISchema;
40
+ };
41
+ type OpenAPIMediaTypeObject = {
42
+ schema?: OpenAPISchema;
43
+ };
44
+ type OpenAPIResponseContent = {
45
+ "application/json"?: OpenAPIMediaTypeObject;
46
+ "text/plain"?: OpenAPIMediaTypeObject;
47
+ "text/html"?: OpenAPIMediaTypeObject;
48
+ [contentType: string]: OpenAPIMediaTypeObject | undefined;
49
+ };
50
+ type OpenAPIResponse = {
51
+ description?: string;
52
+ content?: OpenAPIResponseContent;
53
+ };
54
+ type OpenAPIRequestBody = {
55
+ required?: boolean;
56
+ content: {
57
+ "application/json": {
58
+ schema: OpenAPISchema;
59
+ };
60
+ };
61
+ };
62
+ type OpenAPIOperation = {
63
+ tags?: string[];
64
+ operationId?: string;
65
+ description?: string;
66
+ security?: [{
67
+ bearerAuth: string[];
68
+ }];
69
+ parameters?: OpenAPIParameter$1[];
70
+ requestBody?: OpenAPIRequestBody;
71
+ responses?: Record<string, OpenAPIResponse>;
72
+ };
64
73
  type FieldSchema = {
65
74
  type: DBFieldType;
66
- default?: (DBFieldAttributeConfig["defaultValue"] | "Generated at runtime") | undefined;
75
+ default?: DBFieldAttributeConfig["defaultValue"] | undefined;
67
76
  readOnly?: boolean | undefined;
68
77
  format?: string;
69
78
  };
@@ -111,4 +120,4 @@ declare function generator(ctx: AuthContext, options: BetterAuthOptions): Promis
111
120
  paths: Record<string, Path>;
112
121
  }>;
113
122
  //#endregion
114
- export { FieldSchema, OpenAPIModelSchema, Path, generator };
123
+ export { FieldSchema, OpenAPIModelSchema, OpenAPIParameter$1 as OpenAPIParameter, OpenAPISchema, Path, generator };