UNPKG

@clerk/backend

Version:

Clerk Backend SDK - REST Client for Backend API & JWT verification utilities

1 lines • 435 kB
{"version":3,"sources":["../src/constants.ts","../src/createRedirect.ts","../src/util/mergePreDefinedOptions.ts","../src/util/optionsAssertions.ts","../src/tokens/tokenTypes.ts","../src/tokens/authenticateContext.ts","../src/tokens/authObjects.ts","../src/util/path.ts","../src/api/endpoints/AbstractApi.ts","../src/api/endpoints/ActorTokenApi.ts","../src/api/endpoints/AccountlessApplicationsAPI.ts","../src/api/endpoints/AllowlistIdentifierApi.ts","../src/api/endpoints/APIKeysApi.ts","../src/api/endpoints/BetaFeaturesApi.ts","../src/api/endpoints/BlocklistIdentifierApi.ts","../src/api/endpoints/ClientApi.ts","../src/api/endpoints/DomainApi.ts","../src/api/endpoints/EmailAddressApi.ts","../src/api/endpoints/IdPOAuthAccessTokenApi.ts","../src/api/endpoints/InstanceApi.ts","../src/api/endpoints/InvitationApi.ts","../src/api/endpoints/MachineApi.ts","../src/api/endpoints/M2MTokenApi.ts","../src/api/endpoints/JwksApi.ts","../src/api/endpoints/JwtTemplatesApi.ts","../src/api/endpoints/OrganizationApi.ts","../src/api/endpoints/OAuthApplicationsApi.ts","../src/api/endpoints/PhoneNumberApi.ts","../src/api/endpoints/ProxyCheckApi.ts","../src/api/endpoints/RedirectUrlApi.ts","../src/api/endpoints/SamlConnectionApi.ts","../src/api/endpoints/SessionApi.ts","../src/api/endpoints/SignInTokenApi.ts","../src/api/endpoints/SignUpApi.ts","../src/api/endpoints/TestingTokenApi.ts","../src/api/endpoints/UserApi.ts","../src/api/endpoints/WaitlistEntryApi.ts","../src/api/endpoints/WebhookApi.ts","../src/api/endpoints/BillingApi.ts","../src/api/request.ts","../../../node_modules/.pnpm/map-obj@5.0.2/node_modules/map-obj/index.js","../../../node_modules/.pnpm/change-case@5.4.4/node_modules/change-case/src/index.ts","../../../node_modules/.pnpm/snakecase-keys@9.0.2/node_modules/snakecase-keys/index.js","../src/api/resources/AccountlessApplication.ts","../src/api/resources/ActorToken.ts","../src/api/resources/AllowlistIdentifier.ts","../src/api/resources/APIKey.ts","../src/api/resources/BlocklistIdentifier.ts","../src/api/resources/Session.ts","../src/api/resources/Client.ts","../src/api/resources/CnameTarget.ts","../src/api/resources/Cookies.ts","../src/api/resources/DeletedObject.ts","../src/api/resources/Domain.ts","../src/api/resources/Email.ts","../src/api/resources/IdentificationLink.ts","../src/api/resources/Verification.ts","../src/api/resources/EmailAddress.ts","../src/api/resources/ExternalAccount.ts","../src/api/resources/IdPOAuthAccessToken.ts","../src/api/resources/Instance.ts","../src/api/resources/InstanceRestrictions.ts","../src/api/resources/InstanceSettings.ts","../src/api/resources/Invitation.ts","../src/api/resources/JSON.ts","../src/api/resources/Machine.ts","../src/api/resources/MachineScope.ts","../src/api/resources/MachineSecretKey.ts","../src/api/resources/M2MToken.ts","../src/api/resources/JwtTemplate.ts","../src/api/resources/OauthAccessToken.ts","../src/api/resources/OAuthApplication.ts","../src/api/resources/Organization.ts","../src/api/resources/OrganizationInvitation.ts","../src/api/resources/OrganizationMembership.ts","../src/api/resources/OrganizationSettings.ts","../src/api/resources/PhoneNumber.ts","../src/api/resources/ProxyCheck.ts","../src/api/resources/RedirectUrl.ts","../src/api/resources/SamlConnection.ts","../src/api/resources/SamlAccount.ts","../src/api/resources/SignInTokens.ts","../src/api/resources/SignUpAttempt.ts","../src/api/resources/SMSMessage.ts","../src/api/resources/Token.ts","../src/api/resources/Web3Wallet.ts","../src/api/resources/User.ts","../src/api/resources/WaitlistEntry.ts","../src/api/resources/Feature.ts","../src/api/resources/CommercePlan.ts","../src/api/resources/Deserializer.ts","../src/api/factory.ts","../src/tokens/machine.ts","../src/tokens/authStatus.ts","../src/tokens/clerkRequest.ts","../src/tokens/clerkUrl.ts","../src/tokens/cookie.ts","../src/tokens/keys.ts","../src/tokens/verify.ts","../src/tokens/handshake.ts","../src/tokens/organizationMatcher.ts","../src/tokens/request.ts","../src/tokens/factory.ts","../src/util/decorateObjectWithResources.ts","../src/internal.ts"],"sourcesContent":["export const API_URL = 'https://api.clerk.com';\nexport const API_VERSION = 'v1';\n\nexport const USER_AGENT = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;\nexport const MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60;\nexport const SUPPORTED_BAPI_VERSION = '2025-04-10';\n\nconst Attributes = {\n AuthToken: '__clerkAuthToken',\n AuthSignature: '__clerkAuthSignature',\n AuthStatus: '__clerkAuthStatus',\n AuthReason: '__clerkAuthReason',\n AuthMessage: '__clerkAuthMessage',\n ClerkUrl: '__clerkUrl',\n} as const;\n\nconst Cookies = {\n Session: '__session',\n Refresh: '__refresh',\n ClientUat: '__client_uat',\n Handshake: '__clerk_handshake',\n DevBrowser: '__clerk_db_jwt',\n RedirectCount: '__clerk_redirect_count',\n HandshakeNonce: '__clerk_handshake_nonce',\n} as const;\n\nconst QueryParameters = {\n ClerkSynced: '__clerk_synced',\n SuffixedCookies: 'suffixed_cookies',\n ClerkRedirectUrl: '__clerk_redirect_url',\n // use the reference to Cookies to indicate that it's the same value\n DevBrowser: Cookies.DevBrowser,\n Handshake: Cookies.Handshake,\n HandshakeHelp: '__clerk_help',\n LegacyDevBrowser: '__dev_session',\n HandshakeReason: '__clerk_hs_reason',\n HandshakeNonce: Cookies.HandshakeNonce,\n HandshakeFormat: 'format',\n} as const;\n\nconst Headers = {\n Accept: 'accept',\n AuthMessage: 'x-clerk-auth-message',\n Authorization: 'authorization',\n AuthReason: 'x-clerk-auth-reason',\n AuthSignature: 'x-clerk-auth-signature',\n AuthStatus: 'x-clerk-auth-status',\n AuthToken: 'x-clerk-auth-token',\n CacheControl: 'cache-control',\n ClerkRedirectTo: 'x-clerk-redirect-to',\n ClerkRequestData: 'x-clerk-request-data',\n ClerkUrl: 'x-clerk-clerk-url',\n CloudFrontForwardedProto: 'cloudfront-forwarded-proto',\n ContentType: 'content-type',\n ContentSecurityPolicy: 'content-security-policy',\n ContentSecurityPolicyReportOnly: 'content-security-policy-report-only',\n EnableDebug: 'x-clerk-debug',\n ForwardedHost: 'x-forwarded-host',\n ForwardedPort: 'x-forwarded-port',\n ForwardedProto: 'x-forwarded-proto',\n Host: 'host',\n Location: 'location',\n Nonce: 'x-nonce',\n Origin: 'origin',\n Referrer: 'referer',\n SecFetchDest: 'sec-fetch-dest',\n SecFetchSite: 'sec-fetch-site',\n UserAgent: 'user-agent',\n ReportingEndpoints: 'reporting-endpoints',\n} as const;\n\nconst ContentTypes = {\n Json: 'application/json',\n} as const;\n\n/**\n * @internal\n */\nexport const constants = {\n Attributes,\n Cookies,\n Headers,\n ContentTypes,\n QueryParameters,\n} as const;\n\nexport type Constants = typeof constants;\n","import { buildAccountsBaseUrl } from '@clerk/shared/buildAccountsBaseUrl';\nimport type { SessionStatusClaim } from '@clerk/types';\n\nimport { constants } from './constants';\nimport { errorThrower, parsePublishableKey } from './util/shared';\n\nconst buildUrl = (\n _baseUrl: string | URL,\n _targetUrl: string | URL,\n _returnBackUrl?: string | URL | null,\n _devBrowserToken?: string | null,\n) => {\n if (_baseUrl === '') {\n return legacyBuildUrl(_targetUrl.toString(), _returnBackUrl?.toString());\n }\n\n const baseUrl = new URL(_baseUrl);\n const returnBackUrl = _returnBackUrl ? new URL(_returnBackUrl, baseUrl) : undefined;\n const res = new URL(_targetUrl, baseUrl);\n const isCrossOriginRedirect = `${baseUrl.hostname}:${baseUrl.port}` !== `${res.hostname}:${res.port}`;\n\n if (returnBackUrl) {\n if (isCrossOriginRedirect) {\n returnBackUrl.searchParams.delete(constants.QueryParameters.ClerkSynced);\n }\n\n res.searchParams.set('redirect_url', returnBackUrl.toString());\n }\n // For cross-origin redirects, we need to pass the dev browser token for URL session syncing\n if (isCrossOriginRedirect && _devBrowserToken) {\n res.searchParams.set(constants.QueryParameters.DevBrowser, _devBrowserToken);\n }\n return res.toString();\n};\n\n/**\n * In v5, we deprecated the top-level redirectToSignIn and redirectToSignUp functions\n * in favor of the new auth().redirectToSignIn helpers\n * In order to allow for a smooth transition, we need to support the legacy redirectToSignIn for now\n * as we will remove it in v6.\n * In order to make sure that the legacy function works as expected, we will use legacyBuildUrl\n * to build the url if baseUrl is not provided (which is the case for legacy redirectToSignIn)\n * This function can be safely removed when we remove the legacy redirectToSignIn function\n */\nconst legacyBuildUrl = (targetUrl: string, redirectUrl?: string) => {\n let url;\n if (!targetUrl.startsWith('http')) {\n if (!redirectUrl || !redirectUrl.startsWith('http')) {\n throw new Error('destination url or return back url should be an absolute path url!');\n }\n\n const baseURL = new URL(redirectUrl);\n url = new URL(targetUrl, baseURL.origin);\n } else {\n url = new URL(targetUrl);\n }\n\n if (redirectUrl) {\n url.searchParams.set('redirect_url', redirectUrl);\n }\n\n return url.toString();\n};\n\ntype RedirectAdapter<RedirectReturn> = (url: string) => RedirectReturn;\ntype RedirectToParams = { returnBackUrl?: string | URL | null };\nexport type RedirectFun<ReturnType> = (params?: RedirectToParams) => ReturnType;\n\n/**\n * @internal\n */\ntype CreateRedirect = <ReturnType>(params: {\n publishableKey: string;\n devBrowserToken?: string;\n redirectAdapter: RedirectAdapter<ReturnType>;\n baseUrl: URL | string;\n signInUrl?: URL | string;\n signUpUrl?: URL | string;\n sessionStatus?: SessionStatusClaim | null;\n}) => {\n redirectToSignIn: RedirectFun<ReturnType>;\n redirectToSignUp: RedirectFun<ReturnType>;\n};\n\nexport const createRedirect: CreateRedirect = params => {\n const { publishableKey, redirectAdapter, signInUrl, signUpUrl, baseUrl, sessionStatus } = params;\n const parsedPublishableKey = parsePublishableKey(publishableKey);\n const frontendApi = parsedPublishableKey?.frontendApi;\n const isDevelopment = parsedPublishableKey?.instanceType === 'development';\n const accountsBaseUrl = buildAccountsBaseUrl(frontendApi);\n const hasPendingStatus = sessionStatus === 'pending';\n\n const redirectToTasks = (url: string | URL, { returnBackUrl }: RedirectToParams) => {\n return redirectAdapter(\n buildUrl(baseUrl, `${url}/tasks`, returnBackUrl, isDevelopment ? params.devBrowserToken : null),\n );\n };\n\n const redirectToSignUp = ({ returnBackUrl }: RedirectToParams = {}) => {\n if (!signUpUrl && !accountsBaseUrl) {\n errorThrower.throwMissingPublishableKeyError();\n }\n\n const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;\n\n // Allows redirection to SignInOrUp path\n function buildSignUpUrl(signIn: string | URL | undefined) {\n if (!signIn) {\n return;\n }\n const url = new URL(signIn, baseUrl);\n url.pathname = `${url.pathname}/create`;\n return url.toString();\n }\n\n const targetUrl = signUpUrl || buildSignUpUrl(signInUrl) || accountsSignUpUrl;\n\n if (hasPendingStatus) {\n return redirectToTasks(targetUrl, { returnBackUrl });\n }\n\n return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null));\n };\n\n const redirectToSignIn = ({ returnBackUrl }: RedirectToParams = {}) => {\n if (!signInUrl && !accountsBaseUrl) {\n errorThrower.throwMissingPublishableKeyError();\n }\n\n const accountsSignInUrl = `${accountsBaseUrl}/sign-in`;\n const targetUrl = signInUrl || accountsSignInUrl;\n\n if (hasPendingStatus) {\n return redirectToTasks(targetUrl, { returnBackUrl });\n }\n\n return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null));\n };\n\n return { redirectToSignUp, redirectToSignIn };\n};\n","export function mergePreDefinedOptions<T extends Record<string, any>>(preDefinedOptions: T, options: Partial<T>): T {\n return Object.keys(preDefinedOptions).reduce(\n (obj: T, key: string) => {\n return { ...obj, [key]: options[key] || obj[key] };\n },\n { ...preDefinedOptions },\n );\n}\n","import { parsePublishableKey } from './shared';\n\nexport function assertValidSecretKey(val: unknown): asserts val is string {\n if (!val || typeof val !== 'string') {\n throw Error('Missing Clerk Secret Key. Go to https://dashboard.clerk.com and get your key for your instance.');\n }\n\n //TODO: Check if the key is invalid and throw error\n}\n\nexport function assertValidPublishableKey(val: unknown): asserts val is string {\n parsePublishableKey(val as string | undefined, { fatal: true });\n}\n","export const TokenType = {\n SessionToken: 'session_token',\n ApiKey: 'api_key',\n M2MToken: 'm2m_token',\n OAuthToken: 'oauth_token',\n} as const;\n\n/**\n * @inline\n */\nexport type TokenType = (typeof TokenType)[keyof typeof TokenType];\n\n/**\n * @inline\n */\nexport type SessionTokenType = typeof TokenType.SessionToken;\n/**\n * @inline\n */\nexport type MachineTokenType = Exclude<TokenType, SessionTokenType>;\n","import type { Jwt } from '@clerk/types';\n\nimport { constants } from '../constants';\nimport { decodeJwt } from '../jwt/verifyJwt';\nimport { runtime } from '../runtime';\nimport { assertValidPublishableKey } from '../util/optionsAssertions';\nimport { getCookieSuffix, getSuffixedCookieName, parsePublishableKey } from '../util/shared';\nimport type { ClerkRequest } from './clerkRequest';\nimport { TokenType } from './tokenTypes';\nimport type { AuthenticateRequestOptions } from './types';\n\ninterface AuthenticateContext extends AuthenticateRequestOptions {\n // header-based values\n accept: string | undefined;\n forwardedHost: string | undefined;\n forwardedProto: string | undefined;\n host: string | undefined;\n origin: string | undefined;\n referrer: string | undefined;\n secFetchDest: string | undefined;\n tokenInHeader: string | undefined;\n userAgent: string | undefined;\n\n // cookie-based values\n clientUat: number;\n refreshTokenInCookie: string | undefined;\n sessionTokenInCookie: string | undefined;\n\n // handshake-related values\n devBrowserToken: string | undefined;\n handshakeNonce: string | undefined;\n handshakeRedirectLoopCounter: number;\n handshakeToken: string | undefined;\n\n // url derived from headers\n clerkUrl: URL;\n // enforce existence of the following props\n frontendApi: string;\n instanceType: string;\n publishableKey: string;\n}\n\n/**\n * All data required to authenticate a request.\n * This is the data we use to decide whether a request\n * is in a signed in or signed out state or if we need\n * to perform a handshake.\n */\nclass AuthenticateContext implements AuthenticateContext {\n /**\n * The original Clerk frontend API URL, extracted from publishable key before proxy URL override.\n * Used for backend operations like token validation and issuer checking.\n */\n private originalFrontendApi: string = '';\n\n /**\n * Retrieves the session token from either the cookie or the header.\n *\n * @returns {string | undefined} The session token if available, otherwise undefined.\n */\n public get sessionToken(): string | undefined {\n return this.sessionTokenInCookie || this.tokenInHeader;\n }\n\n public constructor(\n private cookieSuffix: string,\n private clerkRequest: ClerkRequest,\n options: AuthenticateRequestOptions,\n ) {\n if (options.acceptsToken === TokenType.M2MToken || options.acceptsToken === TokenType.ApiKey) {\n // For non-session tokens, we only want to set the header values.\n this.initHeaderValues();\n } else {\n // Even though the options are assigned to this later in this function\n // we set the publishableKey here because it is being used in cookies/headers/handshake-values\n // as part of getMultipleAppsCookie.\n this.initPublishableKeyValues(options);\n this.initHeaderValues();\n // initCookieValues should be used before initHandshakeValues because it depends on suffixedCookies\n this.initCookieValues();\n this.initHandshakeValues();\n }\n\n Object.assign(this, options);\n this.clerkUrl = this.clerkRequest.clerkUrl;\n }\n\n public usesSuffixedCookies(): boolean {\n const suffixedClientUat = this.getSuffixedCookie(constants.Cookies.ClientUat);\n const clientUat = this.getCookie(constants.Cookies.ClientUat);\n const suffixedSession = this.getSuffixedCookie(constants.Cookies.Session) || '';\n const session = this.getCookie(constants.Cookies.Session) || '';\n\n // In the case of malformed session cookies (eg missing the iss claim), we should\n // use the un-suffixed cookies to return signed-out state instead of triggering\n // handshake\n if (session && !this.tokenHasIssuer(session)) {\n return false;\n }\n\n // If there's a token in un-suffixed, and it doesn't belong to this\n // instance, then we must trust suffixed\n if (session && !this.tokenBelongsToInstance(session)) {\n return true;\n }\n\n // If there are no suffixed cookies use un-suffixed\n if (!suffixedClientUat && !suffixedSession) {\n return false;\n }\n\n const { data: sessionData } = decodeJwt(session);\n const sessionIat = sessionData?.payload.iat || 0;\n const { data: suffixedSessionData } = decodeJwt(suffixedSession);\n const suffixedSessionIat = suffixedSessionData?.payload.iat || 0;\n\n // Both indicate signed in, but un-suffixed is newer\n // Trust un-suffixed because it's newer\n if (suffixedClientUat !== '0' && clientUat !== '0' && sessionIat > suffixedSessionIat) {\n return false;\n }\n\n // Suffixed indicates signed out, but un-suffixed indicates signed in\n // Trust un-suffixed because it gets set with both new and old clerk.js,\n // so we can assume it's newer\n if (suffixedClientUat === '0' && clientUat !== '0') {\n return false;\n }\n\n // Suffixed indicates signed in, un-suffixed indicates signed out\n // This is the tricky one\n\n // In production, suffixed_uat should be set reliably, since it's\n // set by FAPI and not clerk.js. So in the scenario where a developer\n // downgrades, the state will look like this:\n // - un-suffixed session cookie: empty\n // - un-suffixed uat: 0\n // - suffixed session cookie: (possibly filled, possibly empty)\n // - suffixed uat: 0\n\n // Our SDK honors client_uat over the session cookie, so we don't\n // need a special case for production. We can rely on suffixed,\n // and the fact that the suffixed uat is set properly means and\n // suffixed session cookie will be ignored.\n\n // The important thing to make sure we have a test that confirms\n // the user ends up as signed out in this scenario, and the suffixed\n // session cookie is ignored\n\n // In development, suffixed_uat is not set reliably, since it's done\n // by clerk.js. If the developer downgrades to a pinned version of\n // clerk.js, the suffixed uat will no longer be updated\n\n // The best we can do is look to see if the suffixed token is expired.\n // This means that, if a developer downgrades, and then immediately\n // signs out, all in the span of 1 minute, then they will inadvertently\n // remain signed in for the rest of that minute. This is a known\n // limitation of the strategy but seems highly unlikely.\n if (this.instanceType !== 'production') {\n const isSuffixedSessionExpired = this.sessionExpired(suffixedSessionData);\n if (suffixedClientUat !== '0' && clientUat === '0' && isSuffixedSessionExpired) {\n return false;\n }\n }\n\n // If a suffixed session cookie exists but the corresponding client_uat cookie is missing, fallback to using\n // unsuffixed cookies.\n // This handles the scenario where an app has been deployed using an SDK version that supports suffixed\n // cookies, but FAPI for its Clerk instance has the feature disabled (eg: if we need to temporarily disable the feature).\n if (!suffixedClientUat && suffixedSession) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Determines if the request came from a different origin based on the referrer header.\n * Used for cross-origin detection in multi-domain authentication flows.\n *\n * @returns {boolean} True if referrer exists and is from a different origin, false otherwise.\n */\n public isCrossOriginReferrer(): boolean {\n if (!this.referrer || !this.clerkUrl.origin) {\n return false;\n }\n\n try {\n if (this.getHeader(constants.Headers.SecFetchSite) === 'cross-site') {\n return true;\n }\n\n const referrerOrigin = new URL(this.referrer).origin;\n return referrerOrigin !== this.clerkUrl.origin;\n } catch {\n // Invalid referrer URL format\n return false;\n }\n }\n\n private initPublishableKeyValues(options: AuthenticateRequestOptions) {\n assertValidPublishableKey(options.publishableKey);\n this.publishableKey = options.publishableKey;\n\n const originalPk = parsePublishableKey(this.publishableKey, {\n fatal: true,\n domain: options.domain,\n isSatellite: options.isSatellite,\n });\n this.originalFrontendApi = originalPk.frontendApi;\n\n const pk = parsePublishableKey(this.publishableKey, {\n fatal: true,\n proxyUrl: options.proxyUrl,\n domain: options.domain,\n isSatellite: options.isSatellite,\n });\n this.instanceType = pk.instanceType;\n this.frontendApi = pk.frontendApi;\n }\n\n private initHeaderValues() {\n this.tokenInHeader = this.parseAuthorizationHeader(this.getHeader(constants.Headers.Authorization));\n this.origin = this.getHeader(constants.Headers.Origin);\n this.host = this.getHeader(constants.Headers.Host);\n this.forwardedHost = this.getHeader(constants.Headers.ForwardedHost);\n this.forwardedProto =\n this.getHeader(constants.Headers.CloudFrontForwardedProto) || this.getHeader(constants.Headers.ForwardedProto);\n this.referrer = this.getHeader(constants.Headers.Referrer);\n this.userAgent = this.getHeader(constants.Headers.UserAgent);\n this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest);\n this.accept = this.getHeader(constants.Headers.Accept);\n }\n\n private initCookieValues() {\n // suffixedCookies needs to be set first because it's used in getMultipleAppsCookie\n this.sessionTokenInCookie = this.getSuffixedOrUnSuffixedCookie(constants.Cookies.Session);\n this.refreshTokenInCookie = this.getSuffixedCookie(constants.Cookies.Refresh);\n this.clientUat = Number.parseInt(this.getSuffixedOrUnSuffixedCookie(constants.Cookies.ClientUat) || '') || 0;\n }\n\n private initHandshakeValues() {\n this.devBrowserToken =\n this.getQueryParam(constants.QueryParameters.DevBrowser) ||\n this.getSuffixedOrUnSuffixedCookie(constants.Cookies.DevBrowser);\n // Using getCookie since we don't suffix the handshake token cookie\n this.handshakeToken =\n this.getQueryParam(constants.QueryParameters.Handshake) || this.getCookie(constants.Cookies.Handshake);\n this.handshakeRedirectLoopCounter = Number(this.getCookie(constants.Cookies.RedirectCount)) || 0;\n this.handshakeNonce =\n this.getQueryParam(constants.QueryParameters.HandshakeNonce) || this.getCookie(constants.Cookies.HandshakeNonce);\n }\n\n private getQueryParam(name: string) {\n return this.clerkRequest.clerkUrl.searchParams.get(name);\n }\n\n private getHeader(name: string) {\n return this.clerkRequest.headers.get(name) || undefined;\n }\n\n private getCookie(name: string) {\n return this.clerkRequest.cookies.get(name) || undefined;\n }\n\n private getSuffixedCookie(name: string) {\n return this.getCookie(getSuffixedCookieName(name, this.cookieSuffix)) || undefined;\n }\n\n private getSuffixedOrUnSuffixedCookie(cookieName: string) {\n if (this.usesSuffixedCookies()) {\n return this.getSuffixedCookie(cookieName);\n }\n return this.getCookie(cookieName);\n }\n\n private parseAuthorizationHeader(authorizationHeader: string | undefined | null): string | undefined {\n if (!authorizationHeader) {\n return undefined;\n }\n\n const [scheme, token] = authorizationHeader.split(' ', 2);\n\n if (!token) {\n // No scheme specified, treat the entire value as the token\n return scheme;\n }\n\n if (scheme === 'Bearer') {\n return token;\n }\n\n // Skip all other schemes\n return undefined;\n }\n\n private tokenHasIssuer(token: string): boolean {\n const { data, errors } = decodeJwt(token);\n if (errors) {\n return false;\n }\n return !!data.payload.iss;\n }\n\n private tokenBelongsToInstance(token: string): boolean {\n if (!token) {\n return false;\n }\n\n const { data, errors } = decodeJwt(token);\n if (errors) {\n return false;\n }\n const tokenIssuer = data.payload.iss.replace(/https?:\\/\\//gi, '');\n // Use original frontend API for token validation since tokens are issued by the actual Clerk API, not proxy\n return this.originalFrontendApi === tokenIssuer;\n }\n\n private sessionExpired(jwt: Jwt | undefined): boolean {\n return !!jwt && jwt?.payload.exp <= (Date.now() / 1000) >> 0;\n }\n}\n\nexport type { AuthenticateContext };\n\nexport const createAuthenticateContext = async (\n clerkRequest: ClerkRequest,\n options: AuthenticateRequestOptions,\n): Promise<AuthenticateContext> => {\n const cookieSuffix = options.publishableKey\n ? await getCookieSuffix(options.publishableKey, runtime.crypto.subtle)\n : '';\n return new AuthenticateContext(cookieSuffix, clerkRequest, options);\n};\n","import { createCheckAuthorization } from '@clerk/shared/authorization';\nimport { __experimental_JWTPayloadToAuthObjectProperties } from '@clerk/shared/jwtPayloadParser';\nimport type {\n CheckAuthorizationFromSessionClaims,\n Jwt,\n JwtPayload,\n PendingSessionOptions,\n ServerGetToken,\n ServerGetTokenOptions,\n SessionStatusClaim,\n SharedSignedInAuthObjectProperties,\n} from '@clerk/types';\n\nimport type { APIKey, CreateBackendApiOptions, IdPOAuthAccessToken, M2MToken } from '../api';\nimport { createBackendApiClient } from '../api';\nimport { isTokenTypeAccepted } from '../internal';\nimport type { AuthenticateContext } from './authenticateContext';\nimport { isMachineTokenType } from './machine';\nimport type { MachineTokenType, SessionTokenType } from './tokenTypes';\nimport { TokenType } from './tokenTypes';\nimport type { AuthenticateRequestOptions, MachineAuthType } from './types';\n\n/**\n * @inline\n */\ntype AuthObjectDebugData = Record<string, any>;\n/**\n * @inline\n */\ntype AuthObjectDebug = () => AuthObjectDebugData;\n\ntype Claims = Record<string, any>;\n\n/**\n * @internal\n */\nexport type SignedInAuthObjectOptions = CreateBackendApiOptions & {\n token: string;\n};\n\n/**\n * @internal\n */\nexport type SignedInAuthObject = SharedSignedInAuthObjectProperties & {\n /**\n * The allowed token type.\n */\n tokenType: SessionTokenType;\n /**\n * A function that gets the current user's [session token](https://clerk.com/docs/backend-requests/resources/session-tokens) or a [custom JWT template](https://clerk.com/docs/backend-requests/jwt-templates).\n */\n getToken: ServerGetToken;\n /**\n * A function that checks if the user has an organization role or custom permission.\n */\n has: CheckAuthorizationFromSessionClaims;\n /**\n * Used to help debug issues when using Clerk in development.\n */\n debug: AuthObjectDebug;\n isAuthenticated: true;\n};\n\n/**\n * @internal\n */\nexport type SignedOutAuthObject = {\n sessionClaims: null;\n sessionId: null;\n sessionStatus: SessionStatusClaim | null;\n actor: null;\n tokenType: SessionTokenType;\n userId: null;\n orgId: null;\n orgRole: null;\n orgSlug: null;\n orgPermissions: null;\n factorVerificationAge: null;\n getToken: ServerGetToken;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n isAuthenticated: false;\n};\n\n/**\n * Extended properties specific to each machine token type.\n * While all machine token types share common properties (id, name, subject, etc),\n * this type defines the additional properties that are unique to each token type.\n *\n * @template TAuthenticated - Whether the machine object is authenticated or not\n */\ntype MachineObjectExtendedProperties<TAuthenticated extends boolean> = {\n api_key: TAuthenticated extends true\n ?\n | { name: string; claims: Claims | null; userId: string; orgId: null }\n | { name: string; claims: Claims | null; userId: null; orgId: string }\n : { name: null; claims: null; userId: null; orgId: null };\n m2m_token: {\n claims: TAuthenticated extends true ? Claims | null : null;\n machineId: TAuthenticated extends true ? string : null;\n };\n oauth_token: {\n userId: TAuthenticated extends true ? string : null;\n clientId: TAuthenticated extends true ? string : null;\n };\n};\n\n/**\n * @internal\n *\n * Uses `T extends any` to create a distributive conditional type.\n * This ensures that union types like `'api_key' | 'oauth_token'` are processed\n * individually, creating proper discriminated unions where each token type\n * gets its own distinct properties (e.g., oauth_token won't have claims).\n */\nexport type AuthenticatedMachineObject<T extends MachineTokenType = MachineTokenType> = T extends any\n ? {\n id: string;\n subject: string;\n scopes: string[];\n getToken: () => Promise<string>;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n tokenType: T;\n isAuthenticated: true;\n } & MachineObjectExtendedProperties<true>[T]\n : never;\n\n/**\n * @internal\n *\n * Uses `T extends any` to create a distributive conditional type.\n * This ensures that union types like `'api_key' | 'oauth_token'` are processed\n * individually, creating proper discriminated unions where each token type\n * gets its own distinct properties (e.g., oauth_token won't have claims).\n */\nexport type UnauthenticatedMachineObject<T extends MachineTokenType = MachineTokenType> = T extends any\n ? {\n id: null;\n subject: null;\n scopes: null;\n getToken: () => Promise<null>;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n tokenType: T;\n isAuthenticated: false;\n } & MachineObjectExtendedProperties<false>[T]\n : never;\n\nexport type InvalidTokenAuthObject = {\n isAuthenticated: false;\n tokenType: null;\n getToken: () => Promise<null>;\n has: () => false;\n debug: AuthObjectDebug;\n};\n\n/**\n * @interface\n */\nexport type AuthObject =\n | SignedInAuthObject\n | SignedOutAuthObject\n | AuthenticatedMachineObject\n | UnauthenticatedMachineObject\n | InvalidTokenAuthObject;\n\nconst createDebug = (data: AuthObjectDebugData | undefined) => {\n return () => {\n const res = { ...data };\n res.secretKey = (res.secretKey || '').substring(0, 7);\n res.jwtKey = (res.jwtKey || '').substring(0, 7);\n return { ...res };\n };\n};\n\n/**\n * @internal\n */\nexport function signedInAuthObject(\n authenticateContext: Partial<AuthenticateContext>,\n sessionToken: string,\n sessionClaims: JwtPayload,\n): SignedInAuthObject {\n const { actor, sessionId, sessionStatus, userId, orgId, orgRole, orgSlug, orgPermissions, factorVerificationAge } =\n __experimental_JWTPayloadToAuthObjectProperties(sessionClaims);\n const apiClient = createBackendApiClient(authenticateContext);\n const getToken = createGetToken({\n sessionId,\n sessionToken,\n fetcher: async (sessionId, template, expiresInSeconds) =>\n (await apiClient.sessions.getToken(sessionId, template || '', expiresInSeconds)).jwt,\n });\n return {\n tokenType: TokenType.SessionToken,\n actor,\n sessionClaims,\n sessionId,\n sessionStatus,\n userId,\n orgId,\n orgRole,\n orgSlug,\n orgPermissions,\n factorVerificationAge,\n getToken,\n has: createCheckAuthorization({\n orgId,\n orgRole,\n orgPermissions,\n userId,\n factorVerificationAge,\n features: (sessionClaims.fea as string) || '',\n plans: (sessionClaims.pla as string) || '',\n }),\n debug: createDebug({ ...authenticateContext, sessionToken }),\n isAuthenticated: true,\n };\n}\n\n/**\n * @internal\n */\nexport function signedOutAuthObject(\n debugData?: AuthObjectDebugData,\n initialSessionStatus?: SessionStatusClaim,\n): SignedOutAuthObject {\n return {\n tokenType: TokenType.SessionToken,\n sessionClaims: null,\n sessionId: null,\n sessionStatus: initialSessionStatus ?? null,\n userId: null,\n actor: null,\n orgId: null,\n orgRole: null,\n orgSlug: null,\n orgPermissions: null,\n factorVerificationAge: null,\n getToken: () => Promise.resolve(null),\n has: () => false,\n debug: createDebug(debugData),\n isAuthenticated: false,\n };\n}\n\n/**\n * @internal\n */\nexport function authenticatedMachineObject<T extends MachineTokenType>(\n tokenType: T,\n token: string,\n verificationResult: MachineAuthType,\n debugData?: AuthObjectDebugData,\n): AuthenticatedMachineObject<T> {\n const baseObject = {\n id: verificationResult.id,\n subject: verificationResult.subject,\n getToken: () => Promise.resolve(token),\n has: () => false,\n debug: createDebug(debugData),\n isAuthenticated: true,\n };\n\n // Type assertions are safe here since we know the verification result type matches the tokenType.\n // We need these assertions because TS can't infer the specific type\n // just from the tokenType discriminator.\n\n switch (tokenType) {\n case TokenType.ApiKey: {\n const result = verificationResult as APIKey;\n return {\n ...baseObject,\n tokenType,\n name: result.name,\n claims: result.claims,\n scopes: result.scopes,\n userId: result.subject.startsWith('user_') ? result.subject : null,\n orgId: result.subject.startsWith('org_') ? result.subject : null,\n } as unknown as AuthenticatedMachineObject<T>;\n }\n case TokenType.M2MToken: {\n const result = verificationResult as M2MToken;\n return {\n ...baseObject,\n tokenType,\n claims: result.claims,\n scopes: result.scopes,\n machineId: result.subject,\n } as unknown as AuthenticatedMachineObject<T>;\n }\n case TokenType.OAuthToken: {\n const result = verificationResult as IdPOAuthAccessToken;\n return {\n ...baseObject,\n tokenType,\n scopes: result.scopes,\n userId: result.subject,\n clientId: result.clientId,\n } as unknown as AuthenticatedMachineObject<T>;\n }\n default:\n throw new Error(`Invalid token type: ${tokenType}`);\n }\n}\n\n/**\n * @internal\n */\nexport function unauthenticatedMachineObject<T extends MachineTokenType>(\n tokenType: T,\n debugData?: AuthObjectDebugData,\n): UnauthenticatedMachineObject<T> {\n const baseObject = {\n id: null,\n subject: null,\n scopes: null,\n has: () => false,\n getToken: () => Promise.resolve(null),\n debug: createDebug(debugData),\n isAuthenticated: false,\n };\n\n switch (tokenType) {\n case TokenType.ApiKey: {\n return {\n ...baseObject,\n tokenType,\n name: null,\n claims: null,\n scopes: null,\n userId: null,\n orgId: null,\n } as unknown as UnauthenticatedMachineObject<T>;\n }\n case TokenType.M2MToken: {\n return {\n ...baseObject,\n tokenType,\n claims: null,\n scopes: null,\n machineId: null,\n } as unknown as UnauthenticatedMachineObject<T>;\n }\n case TokenType.OAuthToken: {\n return {\n ...baseObject,\n tokenType,\n scopes: null,\n userId: null,\n clientId: null,\n } as unknown as UnauthenticatedMachineObject<T>;\n }\n default:\n throw new Error(`Invalid token type: ${tokenType}`);\n }\n}\n\n/**\n * @internal\n */\nexport function invalidTokenAuthObject(): InvalidTokenAuthObject {\n return {\n isAuthenticated: false,\n tokenType: null,\n getToken: () => Promise.resolve(null),\n has: () => false,\n debug: () => ({}),\n };\n}\n\n/**\n * Auth objects moving through the server -> client boundary need to be serializable\n * as we need to ensure that they can be transferred via the network as pure strings.\n * Some frameworks like Remix or Next (/pages dir only) handle this serialization by simply\n * ignoring any non-serializable keys, however Nextjs /app directory is stricter and\n * throws an error if a non-serializable value is found.\n *\n * @internal\n */\nexport const makeAuthObjectSerializable = <T extends Record<string, unknown>>(obj: T): T => {\n // remove any non-serializable props from the returned object\n\n const { debug, getToken, has, ...rest } = obj as unknown as AuthObject;\n return rest as unknown as T;\n};\n\n/**\n * A function that fetches a session token from the Clerk API.\n *\n * @param sessionId - The ID of the session\n * @param template - The JWT template name to use for token generation\n * @param expiresInSeconds - Optional expiration time in seconds for the token\n * @returns A promise that resolves to the token string\n */\ntype TokenFetcher = (sessionId: string, template?: string, expiresInSeconds?: number) => Promise<string>;\n\n/**\n * Factory function type that creates a getToken function for auth objects.\n *\n * @param params - Configuration object containing session information and token fetcher\n * @returns A ServerGetToken function that can be used to retrieve tokens\n */\ntype CreateGetToken = (params: { sessionId: string; sessionToken: string; fetcher: TokenFetcher }) => ServerGetToken;\n\n/**\n * Creates a token retrieval function for authenticated sessions.\n *\n * This factory function returns a getToken function that can either return the raw session token\n * or generate a JWT using a specified template with optional custom expiration.\n *\n * @param params - Configuration object\n * @param params.sessionId - The session ID for token generation\n * @param params.sessionToken - The raw session token to return when no template is specified\n * @param params.fetcher - Function to fetch tokens from the Clerk API\n *\n * @returns A function that retrieves tokens based on the provided options\n */\nconst createGetToken: CreateGetToken = params => {\n const { fetcher, sessionToken, sessionId } = params || {};\n\n return async (options: ServerGetTokenOptions = {}) => {\n if (!sessionId) {\n return null;\n }\n\n if (options.template || options.expiresInSeconds !== undefined) {\n return fetcher(sessionId, options.template, options.expiresInSeconds);\n }\n\n return sessionToken;\n };\n};\n\n/**\n * @internal\n */\nexport const getAuthObjectFromJwt = (\n jwt: Jwt,\n { treatPendingAsSignedOut = true, ...options }: PendingSessionOptions & Partial<AuthenticateContext>,\n) => {\n const authObject = signedInAuthObject(options, jwt.raw.text, jwt.payload);\n\n if (treatPendingAsSignedOut && authObject.sessionStatus === 'pending') {\n return signedOutAuthObject(options, authObject.sessionStatus);\n }\n\n return authObject;\n};\n\n/**\n * @internal\n * Returns an auth object matching the requested token type(s).\n *\n * If the parsed token type does not match any in acceptsToken, returns:\n * - an invalid token auth object if the token is not in the accepted array\n * - an unauthenticated machine object for machine tokens, or\n * - a signed-out session object otherwise.\n *\n * This ensures the returned object always matches the developer's intent.\n */\nexport const getAuthObjectForAcceptedToken = ({\n authObject,\n acceptsToken = TokenType.SessionToken,\n}: {\n authObject: AuthObject;\n acceptsToken: AuthenticateRequestOptions['acceptsToken'];\n}): AuthObject => {\n // 1. any token: return as-is\n if (acceptsToken === 'any') {\n return authObject;\n }\n\n // 2. array of tokens: must match one of the accepted types\n if (Array.isArray(acceptsToken)) {\n if (!isTokenTypeAccepted(authObject.tokenType, acceptsToken)) {\n return invalidTokenAuthObject();\n }\n return authObject;\n }\n\n // 3. single token: must match exactly, else return appropriate unauthenticated object\n if (!isTokenTypeAccepted(authObject.tokenType, acceptsToken)) {\n if (isMachineTokenType(acceptsToken)) {\n return unauthenticatedMachineObject(acceptsToken, authObject.debug);\n }\n return signedOutAuthObject(authObject.debug);\n }\n\n // 4. default: return as-is\n return authObject;\n};\n","const SEPARATOR = '/';\nconst MULTIPLE_SEPARATOR_REGEX = new RegExp('(?<!:)' + SEPARATOR + '{1,}', 'g');\n\ntype PathString = string | null | undefined;\n\nexport function joinPaths(...args: PathString[]): string {\n return args\n .filter(p => p)\n .join(SEPARATOR)\n .replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR);\n}\n","import type { RequestFunction } from '../request';\n\nexport abstract class AbstractAPI {\n constructor(protected request: RequestFunction) {}\n\n protected requireId(id: string) {\n if (!id) {\n throw new Error('A valid resource ID is required.');\n }\n }\n}\n","import { joinPaths } from '../../util/path';\nimport type { ActorToken } from '../resources/ActorToken';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/actor_tokens';\n\ntype ActorTokenActorCreateParams = {\n /**\n * The ID of the actor.\n */\n sub: string;\n /**\n * Additional properties of the actor.\n */\n additionalProperties?: { [k: string]: any };\n};\n\ntype ActorTokenCreateParams = {\n /**\n * The ID of the user being impersonated.\n */\n userId: string;\n /**\n * The actor payload. It needs to include a sub property which should contain the ID of the actor.\n *\n * @remarks\n * This whole payload will be also included in the JWT session token.\n */\n actor: ActorTokenActorCreateParams;\n /**\n * Optional parameter to specify the life duration of the actor token in seconds.\n *\n * @remarks\n * By default, the duration is 1 hour.\n */\n expiresInSeconds?: number | undefined;\n /**\n * The maximum duration that the session which will be created by the generated actor token should last.\n *\n * @remarks\n * By default, the duration of a session created via an actor token, lasts 30 minutes.\n */\n sessionMaxDurationInSeconds?: number | undefined;\n};\n\nexport class ActorTokenAPI extends AbstractAPI {\n public async create(params: ActorTokenCreateParams) {\n return this.request<ActorToken>({\n method: 'POST',\n path: basePath,\n bodyParams: params,\n });\n }\n\n public async revoke(actorTokenId: string) {\n this.requireId(actorTokenId);\n return this.request<ActorToken>({\n method: 'POST',\n path: joinPaths(basePath, actorTokenId, 'revoke'),\n });\n }\n}\n","import { joinPaths } from '../../util/path';\nimport type { AccountlessApplication } from '../resources/AccountlessApplication';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/accountless_applications';\n\nexport class AccountlessApplicationAPI extends AbstractAPI {\n public async createAccountlessApplication(params?: { requestHeaders?: Headers }) {\n const headerParams = params?.requestHeaders ? Object.fromEntries(params.requestHeaders.entries()) : undefined;\n return this.request<AccountlessApplication>({\n method: 'POST',\n path: basePath,\n headerParams,\n });\n }\n\n public async completeAccountlessApplicationOnboarding(params?: { requestHeaders?: Headers }) {\n const headerParams = params?.requestHeaders ? Object.fromEntries(params.requestHeaders.entries()) : undefined;\n return this.request<AccountlessApplication>({\n method: 'POST',\n path: joinPaths(basePath, 'complete'),\n headerParams,\n });\n }\n}\n","import type { ClerkPaginationRequest } from '@clerk/types';\n\nimport { joinPaths } from '../../util/path';\nimport type { AllowlistIdentifier } from '../resources/AllowlistIdentifier';\nimport type { DeletedObject } from '../resources/DeletedObject';\nimport type { PaginatedResourceResponse } from '../resources/Deserializer';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/allowlist_identifiers';\n\ntype AllowlistIdentifierCreateParams = {\n identifier: string;\n notify: boolean;\n};\n\nexport class AllowlistIdentifierAPI extends AbstractAPI {\n public async getAllowlistIdentifierList(params: ClerkPaginationRequest = {}) {\n return this.request<PaginatedResourceResponse<AllowlistIdentifier[]>>({\n method: 'GET',\n path: basePath,\n queryParams: { ...params, paginated: true },\n });\n }\n\n public async createAllowlistIdentifier(params: AllowlistIdentifierCreateParams) {\n return this.request<AllowlistIdentifier>({\n method: 'POST',\n path: basePath,\n bodyParams: params,\n });\n }\n\n public async deleteAllowlistIdentifier(allowlistIdentifierId: string) {\n this.requireId(allowlistIdentifierId);\n return this.request<DeletedObject>({\n method: 'DELETE',\n path: joinPaths(basePath, allowlistIdentifierId),\n });\n }\n}\n","import { joinPaths } from '../../util/path';\nimport type { APIKey } from '../resources/APIKey';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/api_keys';\n\ntype CreateAPIKeyParams = {\n type?: 'api_key';\n /**\n * API key name\n */\n name: string;\n /**\n * user or organization ID the API key is associated with\n */\n subject: string;\n /**\n * API key description\n */\n description?: string | null;\n claims?: Record<string, any> | null;\n scopes?: string[];\n createdBy?: string | null;\n secondsUntilExpiration?: number | null;\n};\n\ntype RevokeAPIKeyParams = {\n /**\n * API key ID\n */\n apiKeyId: string;\n /**\n * Reason for revocation\n */\n revocationReason?: string | null;\n};\n\nexport class APIKeysAPI extends AbstractAPI {\n async create(params: CreateAPIKeyParams) {\n return this.request<APIKey>({\n method: 'POST',\n path: basePath,\n bodyParams: params,\n });\n }\n\n async revoke(params: RevokeAPIKeyParams) {\n const { apiKeyId, ...bodyParams } = params;\n\n this.requireId(apiKeyId);\n\n return this.request<APIKey>({\n method: 'POST',\n path: joinPaths(basePath, apiKeyId, 'revoke'),\n bodyParams,\n });\n }\n\n async getSecret(apiKeyId: string) {\n this.requireId(apiKeyId);\n\n return this.request<{ secret: string }>({\n method: 'GET',\n path: joinPaths(basePath, apiKeyId, 'secret'),\n });\n }\n\n async verifySecret(secret: string) {\n return this.request<APIKey>({\n method: 'POST',\n path: joinPaths(basePath, 'verify'),\n bodyParams: { secret },\n });\n }\n}\n","import { joinPaths } from '../../util/path';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/beta_features';\n\ntype ChangeDomainParams = {\n /**\n * The new home URL of the production instance e.g. https://www.example.com\n */\n homeUrl?: string;\n /**\n * Whether this is a domain for a secondary app, meaning that any subdomain\n * provided is significant and will be stored as part of the domain. This is\n * useful for supporting multiple apps (one primary and multiple secondaries)\n * on the same root domain (eTLD+1).\n */\n isSecondary?: boolean;\n};\n\nexport class BetaFeaturesAPI extends AbstractAPI {\n /**\n * Change the domain of a production instance.\n *\n * Changing the domain requires updating the DNS records accordingly, deploying new SSL certificates,\n * updating your Social Connection's redirect URLs and setting the new keys in your code.\n *\n * @remarks\n * WARNING: Changing your domain will invalidate all current user sessions (i.e. users will be logged out).\n * Also, while your application is being deployed, a small downtime is expected to occur.\n */\n public async changeDomain(params: ChangeDomainParams) {\n return this.request<void>({\n method: 'POST',\n path: joinPaths(basePath, 'change_domain'),\n bodyParams: params,\n });\n }\n}\n","import type { ClerkPaginationRequest } from '@clerk/types';\n\nimport { joinPaths } from '../../util/path';\nimport type { BlocklistIdentifier } from '../resources/BlocklistIdentifier';\nimport type { DeletedObject } from '../resources/DeletedObject';\nimport type { PaginatedResourceResponse } from '../resources/Deserializer';\nimport { AbstractAPI } from './AbstractApi';\n\nconst basePath = '/blocklist_identifiers';\n\ntype BlocklistIdentifierCreateParams = {\n identifier: string;\n};\n\nexport class BlocklistIdentifierAPI extends AbstractAPI {\n public async getBlocklistIdentifierList(params: ClerkPaginationRequest = {}) {\n return this.request<PaginatedResourceResponse<BlocklistIdentifier[]>>({\n method: 'GET',\n path: basePath,\n queryParams: params,\n });\n }\n\n public async createBlocklistIdentifier(params: BlocklistIdentifierCreateParams) {\n return this.request<BlocklistIdentifier>({\n method: 'POST',\n path: basePath,\n bodyParams: params,\n });\n }\n\n public async deleteBlocklistIdentifier(blocklistIdentifierId: string) {\n this.requireId(blocklistIdentifierId);\n return this.request<DeletedObject>({\n method: 'DELETE',\n path: joinPaths(basePath, blocklistIdentifierId),\n });\n }\n}\n","im