diff --git a/.changeset/typedoc-objects-jsdoc.md b/.changeset/typedoc-objects-jsdoc.md new file mode 100644 index 00000000000..d5d63921f86 --- /dev/null +++ b/.changeset/typedoc-objects-jsdoc.md @@ -0,0 +1,13 @@ +--- +'@clerk/backend': patch +'@clerk/clerk-js': patch +'@clerk/expo': patch +'@clerk/express': patch +'@clerk/nextjs': patch +'@clerk/react': patch +'@clerk/shared': patch +'@clerk/ui': patch +'@clerk/vue': patch +--- + +Add and improve JSDoc comments across public types and methods to support generated reference documentation for the `/objects` docs section. Exports a few previously-internal types (`OnEventListener`, `OffEventListener`, `ClerkOptionsNavigation`) so they can be referenced from the generated docs. diff --git a/.prettierignore b/.prettierignore index 67a5a3fc40e..da490cc898c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -23,4 +23,6 @@ packages/clerk-js/src/core/resources/index.ts packages/shared/src/compiled /**/CHANGELOG.md renovate.json5 +# Frozen snapshots of TypeDoc-generated MDX; must match raw `extract-methods.mjs` output. +.typedoc/__tests__/__snapshots__/ CLAUDE.md diff --git a/.typedoc/__tests__/__snapshots__/api-key-resource-methods-create.mdx b/.typedoc/__tests__/__snapshots__/api-key-resource-methods-create.mdx new file mode 100644 index 00000000000..8a60ae22d3d --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/api-key-resource-methods-create.mdx @@ -0,0 +1,21 @@ +### `create()` + +Creates a new API key. + +Returns an [`APIKeyResource`](/docs/reference/types/api-key-resource) object that includes the `secret` property. +> [!WARNING] +> Make sure to store the API key secret immediately after creation, as it will not be available again. + +```typescript +function create(params: CreateAPIKeyParams): Promise +``` + +#### `CreateAPIKeyParams` + + +| Property | Type | Description | +| ------ | ------ | ------ | +| `description?` | `string` | The description of the API key. | +| `name` | `string` | The name of the API key. | +| `secondsUntilExpiration?` | `number` | The number of seconds until the API key expires. Set to `null` or omit to create a key that never expires. | +| `subject?` | `string` | The user or organization ID to associate the API key with. If not provided, defaults to the [Active Organization](!active-organization), then the current User. | diff --git a/.typedoc/__tests__/__snapshots__/clerk-methods-handle-email-link-verification.mdx b/.typedoc/__tests__/__snapshots__/clerk-methods-handle-email-link-verification.mdx new file mode 100644 index 00000000000..9622ed9de65 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk-methods-handle-email-link-verification.mdx @@ -0,0 +1,18 @@ +### `handleEmailLinkVerification()` + +Completes an email link verification flow started by `Clerk.client.signIn.createEmailLinkFlow` or `Clerk.client.signUp.createEmailLinkFlow`, by processing the verification results from the redirect URL query parameters. This method should be called after the user is redirected back from visiting the verification link in their email. + +```typescript +function handleEmailLinkVerification(params: { onVerifiedOnOtherDevice?: () => void; redirectUrl?: string; redirectUrlComplete?: string }, customNavigate?: (to: string) => Promise): Promise +``` + +#### Parameters + + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `params` | \{ onVerifiedOnOtherDevice?: () => void; redirectUrl?: string; redirectUrlComplete?: string; \} | Allows you to define the URLs where the user should be redirected to on successful verification or pending/completed sign-up or sign-in attempts. If the email link is successfully verified on another device, there's a callback function parameter that allows custom code execution. | +| `params.onVerifiedOnOtherDevice?` | () => void | Callback function to be executed after successful email link verification on another device. | +| `params.redirectUrl?` | `string` | The full URL to navigate to after successful email link verification on the same device, but without completing sign-in or sign-up. | +| `params.redirectUrlComplete?` | `string` | The full URL to navigate to after successful email link verification on completed sign-up or sign-in on the same device. | +| `customNavigate?` | (to: string) => Promise\ | A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. | diff --git a/.typedoc/__tests__/__snapshots__/clerk-methods-handle-redirect-callback.mdx b/.typedoc/__tests__/__snapshots__/clerk-methods-handle-redirect-callback.mdx new file mode 100644 index 00000000000..6c50c100af8 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk-methods-handle-redirect-callback.mdx @@ -0,0 +1,15 @@ +### `handleRedirectCallback()` + +Completes a custom OAuth or SAML redirect flow that was started by calling [`SignIn.authenticateWithRedirect(params)`](/docs/reference/objects/sign-in) or [`SignUp.authenticateWithRedirect(params)`](/docs/reference/objects/sign-up). + +```typescript +function handleRedirectCallback(params: HandleOAuthCallbackParams, customNavigate?: (to: string) => Promise): Promise +``` + +#### Parameters + + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `params` | [`HandleOAuthCallbackParams`](/docs/reference/types/handle-o-auth-callback-params) | Additional props that define where the user will be redirected to at the end of a successful OAuth or SAML flow. | +| `customNavigate?` | (to: string) => Promise\ | A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. | diff --git a/.typedoc/__tests__/__snapshots__/clerk-methods-join-waitlist.mdx b/.typedoc/__tests__/__snapshots__/clerk-methods-join-waitlist.mdx new file mode 100644 index 00000000000..cb76cd60a96 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk-methods-join-waitlist.mdx @@ -0,0 +1,14 @@ +### `joinWaitlist()` + +Create a new waitlist entry programmatically. Requires that you set your app's sign-up mode to [**Waitlist**](/docs/guides/secure/restricting-access#waitlist) in the Clerk Dashboard. + +```typescript +function joinWaitlist(params: JoinWaitlistParams): Promise +``` + +#### `JoinWaitlistParams` + + +| Property | Type | Description | +| ------ | ------ | ------ | +| `emailAddress` | `string` | The email address of the user to add to the waitlist. | diff --git a/.typedoc/__tests__/__snapshots__/clerk-methods-sign-out.mdx b/.typedoc/__tests__/__snapshots__/clerk-methods-sign-out.mdx new file mode 100644 index 00000000000..ea575168ea9 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk-methods-sign-out.mdx @@ -0,0 +1,15 @@ +### `signOut()` + +Signs out the current user on single-session instances, or all users on multi-session instances. + +```typescript +function signOut(options?: SignOutOptions): Promise +``` + +#### `SignOutOptions` + + +| Property | Type | Description | +| ------ | ------ | ------ | +| `redirectUrl?` | `string` | Specify a redirect URL to navigate to after sign-out is complete. | +| `sessionId?` | `string` | Specify a specific session to sign out. Useful for multi-session applications. | diff --git a/.typedoc/__tests__/__snapshots__/clerk-properties.mdx b/.typedoc/__tests__/__snapshots__/clerk-properties.mdx new file mode 100644 index 00000000000..914cd9313f9 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk-properties.mdx @@ -0,0 +1,21 @@ +| Property | Type | Description | +| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `apiKeys` | [`APIKeysNamespace`](/docs/reference/objects/api-keys) | The `APIKeys` object used for managing API keys. | +| `billing` | [`BillingNamespace`](/docs/reference/objects/billing) | The `Billing` object used for managing billing. | +| `client` | undefined \| [ClientResource](/docs/reference/objects/client) | The `Client` object for the current window. | +| `domain` | `string` | The current Clerk app's domain. Prefixed with `clerk.` on production if not already prefixed. Returns `""` when ran on the server. | +| `instanceType` | undefined \| "production" \| "development" | Indicates whether the Clerk instance is running in a production or development environment. | +| `isSatellite` | `boolean` | Indicates whether the instance is a satellite app. | +| `isSignedIn` | `boolean` | Indicates whether the current user has a valid signed-in client session. | +| `isStandardBrowser` | undefined \| boolean | Indicates whether the instance is being loaded in a standard browser environment. Set to `false` on native platforms where cookies cannot be set. When `undefined`, Clerk assumes a standard browser. | +| `loaded` | `boolean` | Indicates whether the `Clerk` object is ready for use. Set to `false` when the `status` is `"loading"`. Set to `true` when the `status` is `"ready"` or `"degraded"`. | +| `oauthApplication` | [`OAuthApplicationNamespace`](../o-auth-application-namespace.mdx) | OAuth application helpers (e.g. consent metadata for custom consent UIs). | +| `organization` | undefined \| null \| [OrganizationResource](/docs/reference/objects/organization) | A shortcut to the last active `Session.user.organizationMemberships` which holds an instance of a `Organization` object. If the session is `null` or `undefined`, the user field will match. | +| `proxyUrl` | undefined \| string | **Required for applications that run behind a reverse proxy**. Your Clerk app's proxy URL. Can be either a relative path (`/__clerk`) or a full URL (`https:///__clerk`). | +| `publishableKey` | `string` | Your Clerk [Publishable Key](!publishable-key). | +| `sdkMetadata` | undefined \| \{ environment?: string; name: string; version: string; \} | If present, contains information about the SDK that the host application is using. For example, if Clerk is loaded through `@clerk/nextjs`, this would be `{ name: '@clerk/nextjs', version: '1.0.0' }`. You don't need to set this value yourself unless you're [developing an SDK](/docs/guides/development/sdk-development/overview). | +| `session` | undefined \| null \| [SignedInSessionResource](/docs/reference/objects/session) | The currently active `Session`, which is guaranteed to be one of the sessions in `Client.sessions`. If there is no active session, this field will be `null`. If the session is loading, this field will be `undefined`. | +| `status` | "error" \| "degraded" \| "loading" \| "ready" | The status of the `Clerk` instance. Possible values are:
  • `"error"`: Set when hotloading `clerk-js` or `Clerk.load()` failed.
  • `"loading"`: Set during initialization.
  • `"ready"`: Set when Clerk is fully operational.
  • `"degraded"`: Set when Clerk is partially operational.
| +| `telemetry` | undefined \| \{ isDebug: boolean; isEnabled: boolean; record: void; recordLog: void; \} | [Telemetry](/docs/guides/how-clerk-works/security/clerk-telemetry) configuration. | +| `user` | undefined \| null \| [UserResource](/docs/reference/objects/user) | A shortcut to `Session.user` which holds the currently active `User` object. If the session is `null` or `undefined`, the user field will match. | +| `version` | undefined \| string | The Clerk SDK version number. | diff --git a/.typedoc/__tests__/__snapshots__/clerk.mdx b/.typedoc/__tests__/__snapshots__/clerk.mdx new file mode 100644 index 00000000000..8ea6508d37a --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/clerk.mdx @@ -0,0 +1 @@ +The `Clerk` class serves as the central interface for working with Clerk's authentication and user management functionality in your application. As a top-level class in the Clerk SDK, it provides access to key methods and properties for managing users, sessions, API keys, billing, organizations, and more. diff --git a/.typedoc/__tests__/__snapshots__/session-resource-methods-check-authorization.mdx b/.typedoc/__tests__/__snapshots__/session-resource-methods-check-authorization.mdx new file mode 100644 index 00000000000..0e0568beadd --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/session-resource-methods-check-authorization.mdx @@ -0,0 +1,7 @@ +### `checkAuthorization()` + +Checks if the user is [authorized for the specified Role, Permission, Feature, or Plan](/docs/guides/secure/authorization-checks) or requires the user to [reverify their credentials](/docs/guides/secure/reverification) if their last verification is older than allowed. + +```typescript +function checkAuthorization(isAuthorizedParams: CheckAuthorizationParams): boolean +``` diff --git a/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-code-send-code.mdx b/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-code-send-code.mdx new file mode 100644 index 00000000000..6715e7476f4 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-code-send-code.mdx @@ -0,0 +1,15 @@ +### `emailCode.sendCode()` + +Sends an email code to sign-in. + +```typescript +function sendCode(params?: SignInFutureEmailCodeSendParams): Promise<{ error: null | ClerkError }> +``` + +#### `SignInFutureEmailCodeSendParams` + + +| Property | Type | Description | +| ------ | ------ | ------ | +| `emailAddress?` | `string` | The user's email address. Only supported if [Email address](/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. | +| `emailAddressId?` | `string` | The ID for the user's email address that will receive an email with the one-time authentication code. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. | diff --git a/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-link.mdx b/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-link.mdx new file mode 100644 index 00000000000..b2f588fd6fb --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/sign-in-future-resource-methods-email-link.mdx @@ -0,0 +1,6 @@ +### `emailLink` + + +| Property | Type | Description | +| ------ | ------ | ------ | +| `verification` | null \| \{ createdSessionId: string; status: "expired" \| "failed" \| "verified" \| "client_mismatch"; verifiedFromTheSameClient: boolean; \} | The verification status of the email link. This property is populated by reading query parameters from the URL after the user visits the email link. Returns `null` if no verification status is available. | diff --git a/.typedoc/__tests__/__snapshots__/user-resource-properties.mdx b/.typedoc/__tests__/__snapshots__/user-resource-properties.mdx new file mode 100644 index 00000000000..31a3f8a43a5 --- /dev/null +++ b/.typedoc/__tests__/__snapshots__/user-resource-properties.mdx @@ -0,0 +1,36 @@ +| Property | Type | Description | +| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `backupCodeEnabled` | `boolean` | Indicates whether the user has enabled backup codes. | +| `createdAt` | null \| Date | The date and time when the user was created. | +| `createOrganizationEnabled` | `boolean` | Indicates whether the user can create organizations. | +| `createOrganizationsLimit` | null \| number | The maximum number of organizations the user can create. | +| `deleteSelfEnabled` | `boolean` | Indicates whether the user can delete their own account. | +| `emailAddresses` | [EmailAddressResource](/docs/reference/types/email-address)[] | An array of all the `EmailAddress` objects associated with the user. Includes the primary. | +| `enterpriseAccounts` | [EnterpriseAccountResource](/docs/reference/types/enterprise-account)[] | An array of all the `EnterpriseAccount` objects associated with the user via enterprise SSO. | +| `externalAccounts` | [ExternalAccountResource](/docs/reference/types/external-account)[] | An array of all the `ExternalAccount` objects associated with the user via OAuth. | +| `externalId` | null \| string | The user's ID as used in your external systems. Must be unique across your instance. | +| `firstName` | null \| string | The user's first name. | +| `fullName` | null \| string | The user's full name. | +| `hasImage` | `boolean` | Indicates whether the user has uploaded an image or one was copied from OAuth. Returns `false` if Clerk is displaying an avatar for the user. | +| `id` | `string` | The unique identifier of the user. | +| `imageUrl` | `string` | Holds the default avatar or user's uploaded profile image. Compatible with Clerk's [Image Optimization](/docs/guides/development/image-optimization). | +| `lastName` | null \| string | The user's last name. | +| `lastSignInAt` | null \| Date | The date and time when the user last signed in. | +| `legalAcceptedAt` | null \| Date | The date and time when the user accepted the legal compliance documents. `null` if [**Require express consent to legal documents**](/docs/guides/secure/legal-compliance) is not enabled. | +| `organizationMemberships` | [OrganizationMembershipResource](/docs/reference/types/organization-membership)[] | An array of all the `OrganizationMembership` objects associated with the user. | +| `passkeys` | [PasskeyResource](/docs/reference/types/passkey-resource)[] | An array of all the `Passkey` objects associated with the user. | +| `passwordEnabled` | `boolean` | Indicates whether the user has a password on their account. | +| `phoneNumbers` | [PhoneNumberResource](/docs/reference/types/phone-number)[] | An array of all the `PhoneNumber` objects associated with the user. Includes the primary. | +| `primaryEmailAddress` | null \| [EmailAddressResource](/docs/reference/types/email-address) | The user's primary email address. | +| `primaryEmailAddressId` | null \| string | The ID of the user's primary email address. | +| `primaryPhoneNumber` | null \| [PhoneNumberResource](/docs/reference/types/phone-number) | The user's primary phone number. | +| `primaryPhoneNumberId` | null \| string | The ID of the user's primary phone number. | +| `primaryWeb3Wallet` | null \| [Web3WalletResource](/docs/reference/types/web3-wallet) | The user's primary Web3 wallet. | +| `primaryWeb3WalletId` | null \| string | The ID of the user's primary Web3 wallet. | +| `publicMetadata` | [UserPublicMetadata](/docs/reference/types/metadata#user-public-metadata) | Metadata that can be read from the Frontend API and Backend API and can be set only from the Backend API. | +| `totpEnabled` | `boolean` | Indicates whether the user has enabled TOTP. | +| `twoFactorEnabled` | `boolean` | Indicates whether the user has enabled two-factor authentication. | +| `unsafeMetadata` | [UserUnsafeMetadata](/docs/reference/types/metadata#user-unsafe-metadata) | Metadata that can be read and set from the Frontend API. It's considered unsafe because it can be modified from the frontend. There is also an `unsafeMetadata` attribute in the [`SignUp`](/docs/reference/objects/sign-up-future) object. The value of that field will be automatically copied to the user's unsafe metadata once the sign-up is complete. | +| `updatedAt` | null \| Date | The date and time when the user was last updated. | +| `username` | null \| string | The user's username. | +| `web3Wallets` | [Web3WalletResource](/docs/reference/types/web3-wallet)[] | An array of all the `Web3Wallet` objects associated with the user. Includes the primary. | diff --git a/.typedoc/__tests__/extract-methods.test.ts b/.typedoc/__tests__/extract-methods.test.ts new file mode 100644 index 00000000000..6992eb3dc2e --- /dev/null +++ b/.typedoc/__tests__/extract-methods.test.ts @@ -0,0 +1,88 @@ +import { readFile } from 'fs/promises'; +import { join } from 'path'; +import { describe, expect, it } from 'vitest'; + +/** + * Snapshots for `extract-methods.mjs` output. Each `.mdx` under `__snapshots__/` is a frozen copy of a representative file produced by `typedoc:generate`. Refactors to the plugin or its helpers should leave these files byte-identical; a diff means the change is observable in the published docs and needs a human decision. + * + * Run `pnpm typedoc:generate` first to populate `.typedoc/docs/`, then `vitest run` here. + * To intentionally update a snapshot after reviewing the diff: `vitest run -u`. + * + * Coverage targets one case per non-trivial code path: + * + * - `methods/sign-out.mdx` – simple zero-arg callable + * - `methods/handle-redirect-callback.mdx` – multi-param `parametersTable` with nested rows + * - `methods/handle-email-link-verification.mdx` – required parent (`params`) flattened to `.` + * - `methods/join-waitlist.mdx` – single nominal-param section (`JoinWaitlistParams`) + * - `methods/create.mdx` (api-key) – another single-nominal-param case + warning callout + * - `methods/check-authorization.mdx` – generic instantiation (`CheckAuthorization`) + * - `methods/email-code-send-code.mdx` – qualified name from `@extractMethods` parent + * - `methods/email-link.mdx` – `@extractMethods` namespace index (non-callables) + * - `properties.mdx` (clerk) – properties table sliced from already-prettified page + * - `clerk.mdx` – main page after Properties has been stripped + * - `properties.mdx` (user-resource) – properties with external type links and metadata + */ +const DOCS_DIR = join(process.cwd(), 'docs'); + +async function readGenerated(relPath: string) { + return readFile(join(DOCS_DIR, relPath), 'utf-8'); +} + +describe('extract-methods snapshots', () => { + it('simple callable: clerk.signOut()', async () => { + const content = await readGenerated('shared/clerk/methods/sign-out.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk-methods-sign-out.mdx'); + }); + + it('multi-param method with nested rows: clerk.handleRedirectCallback()', async () => { + const content = await readGenerated('shared/clerk/methods/handle-redirect-callback.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk-methods-handle-redirect-callback.mdx'); + }); + + it('required-parent flatten uses `.` not `?.`: clerk.handleEmailLinkVerification()', async () => { + const content = await readGenerated('shared/clerk/methods/handle-email-link-verification.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk-methods-handle-email-link-verification.mdx'); + }); + + it('single nominal-param section: clerk.joinWaitlist()', async () => { + const content = await readGenerated('shared/clerk/methods/join-waitlist.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk-methods-join-waitlist.mdx'); + }); + + it('single nominal-param + warning callout: apiKeys.create()', async () => { + const content = await readGenerated('shared/api-key-resource/methods/create.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/api-key-resource-methods-create.mdx'); + }); + + it('generic instantiation: session.checkAuthorization()', async () => { + const content = await readGenerated('shared/session-resource/methods/check-authorization.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/session-resource-methods-check-authorization.mdx'); + }); + + it('@extractMethods child: signInFuture.emailCode.sendCode()', async () => { + const content = await readGenerated('shared/sign-in-future-resource/methods/email-code-send-code.mdx'); + await expect(content).toMatchFileSnapshot( + './__snapshots__/sign-in-future-resource-methods-email-code-send-code.mdx', + ); + }); + + it('@extractMethods namespace index: signInFuture.emailLink', async () => { + const content = await readGenerated('shared/sign-in-future-resource/methods/email-link.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/sign-in-future-resource-methods-email-link.mdx'); + }); + + it('properties extracted + prettier-aligned: clerk', async () => { + const content = await readGenerated('shared/clerk/properties.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk-properties.mdx'); + }); + + it('main page after Properties strip: clerk', async () => { + const content = await readGenerated('shared/clerk/clerk.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/clerk.mdx'); + }); + + it('properties with external type links: user-resource', async () => { + const content = await readGenerated('shared/user-resource/properties.mdx'); + await expect(content).toMatchFileSnapshot('./__snapshots__/user-resource-properties.mdx'); + }); +}); diff --git a/.typedoc/__tests__/file-structure.test.ts b/.typedoc/__tests__/file-structure.test.ts index 983a0972d5b..5aca0e62a03 100644 --- a/.typedoc/__tests__/file-structure.test.ts +++ b/.typedoc/__tests__/file-structure.test.ts @@ -2,10 +2,7 @@ import { readdir } from 'fs/promises'; import { join, relative } from 'path'; import { describe, expect, it } from 'vitest'; -// Same function as in custom-router.mjs -function toKebabCase(str: string) { - return str.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase(); -} +import { toUrlSlug } from '../slug.mjs'; const OUTPUT_LOCATION = `${process.cwd()}/docs`; @@ -47,11 +44,29 @@ describe('Typedoc output', () => { it('should only have these nested folders', async () => { const folders = await scanDirectory('directory'); - const nestedFolders = folders.filter(folder => !isTopLevelPath(folder)); + const nestedFolders = folders.filter(folder => !isTopLevelPath(folder)).sort((a, b) => a.localeCompare(b)); expect(nestedFolders).toMatchInlineSnapshot(` [ "react/legacy", + "shared/api-key-resource", + "shared/api-key-resource/methods", + "shared/billing-namespace", + "shared/billing-namespace/methods", + "shared/clerk", + "shared/clerk/methods", + "shared/client-resource", + "shared/client-resource/methods", + "shared/organization-resource", + "shared/organization-resource/methods", + "shared/session-resource", + "shared/session-resource/methods", + "shared/sign-in-future-resource", + "shared/sign-in-future-resource/methods", + "shared/sign-up-future-resource", + "shared/sign-up-future-resource/methods", + "shared/user-resource", + "shared/user-resource/methods", ] `); }); @@ -64,7 +79,7 @@ describe('Typedoc output', () => { }); it('should only contain kebab-cased files', async () => { const files = await scanDirectory('file'); - const incorrectFiles = files.filter(file => file !== toKebabCase(file)); + const incorrectFiles = files.filter(file => file !== toUrlSlug(file)); expect(incorrectFiles).toHaveLength(0); }); diff --git a/.typedoc/comment-utils.mjs b/.typedoc/comment-utils.mjs new file mode 100644 index 00000000000..6375ceba798 --- /dev/null +++ b/.typedoc/comment-utils.mjs @@ -0,0 +1,77 @@ +// @ts-check +import { Comment } from 'typedoc'; + +const TODO_WORD = /\bTODO\b/i; + +/** + * @param {import('typedoc').Comment | undefined} comment + */ +function commentContainsTodo(comment) { + if (!comment) { + return false; + } + const chunks = []; + if (comment.summary?.length) { + chunks.push(Comment.combineDisplayParts(comment.summary)); + } + for (const tag of comment.blockTags ?? []) { + if (tag.content?.length) { + chunks.push(Comment.combineDisplayParts(tag.content)); + } + } + return chunks.some(text => TODO_WORD.test(text)); +} + +/** + * Drop display parts from the first `TODO` onward; truncate the containing text part if `TODO` appears mid-string. + * + * @param {import('typedoc').CommentDisplayPart[] | undefined} parts + * @returns {import('typedoc').CommentDisplayPart[]} + */ +function stripTodoFromDisplayParts(parts) { + if (!parts?.length) { + return parts ?? []; + } + /** @type {import('typedoc').CommentDisplayPart[]} */ + const out = []; + for (const p of parts) { + if (p.kind === 'text' && 'text' in p && typeof p.text === 'string') { + const match = TODO_WORD.exec(p.text); + if (match) { + const before = p.text.slice(0, match.index).trimEnd(); + if (before.length) { + out.push(/** @type {import('typedoc').CommentDisplayPart} */ ({ kind: 'text', text: before })); + } + return out; + } + } + out.push(p); + } + return out; +} + +/** + * Returns a clone with `TODO` and everything after it removed from the summary and from any block tag that contains `TODO`. + * Comments without `TODO` are returned unchanged (same reference). Undefined in, undefined out. + * + * @param {import('typedoc').Comment | undefined} comment + * @returns {import('typedoc').Comment | undefined} + */ +export function applyTodoStrippingToComment(comment) { + if (!comment) { + return undefined; + } + if (!commentContainsTodo(comment)) { + return comment; + } + const c = comment.clone(); + if (c.summary?.length && TODO_WORD.test(Comment.combineDisplayParts(c.summary))) { + c.summary = stripTodoFromDisplayParts(c.summary); + } + for (const tag of c.blockTags ?? []) { + if (tag.content?.length && TODO_WORD.test(Comment.combineDisplayParts(tag.content))) { + tag.content = stripTodoFromDisplayParts(tag.content); + } + } + return c; +} diff --git a/.typedoc/custom-plugin.mjs b/.typedoc/custom-plugin.mjs index e7132279b63..f4b65d3f5cd 100644 --- a/.typedoc/custom-plugin.mjs +++ b/.typedoc/custom-plugin.mjs @@ -1,4 +1,5 @@ // @ts-check - Enable TypeScript checks for safer MDX post-processing and link rewriting +import { Converter } from 'typedoc'; import { MarkdownPageEvent } from 'typedoc-plugin-markdown'; /** @@ -62,6 +63,7 @@ const LINK_REPLACEMENTS = [ ['user-resource', '/docs/reference/objects/user'], ['session-status-claim', '/docs/reference/types/session-status'], ['user-organization-invitation-resource', '/docs/reference/types/user-organization-invitation'], + ['organization-custom-role-key', '/docs/reference/types/organization-custom-role-key'], ['organization-membership-resource', '/docs/reference/types/organization-membership'], ['organization-suggestion-resource', '/docs/reference/types/organization-suggestion'], ['organization-resource', '/docs/reference/objects/organization'], @@ -70,6 +72,7 @@ const LINK_REPLACEMENTS = [ ['organization-membership-request-resource', '/docs/reference/types/organization-membership-request'], ['o-auth-consent-info', '/docs/reference/types/oauth-consent-info'], ['o-auth-consent-scope', '/docs/reference/types/oauth-consent-scope'], + ['o-auth-strategy', '/docs/reference/types/sso#o-auth-strategy'], ['session', '/docs/reference/backend/types/backend-session'], ['session-activity', '/docs/reference/backend/types/backend-session-activity'], ['organization', '/docs/reference/backend/types/backend-organization'], @@ -82,7 +85,10 @@ const LINK_REPLACEMENTS = [ ['enterprise-account-connection', '/docs/reference/backend/types/backend-enterprise-account-connection'], ['enterprise-connection', '/docs/reference/backend/types/backend-enterprise-connection'], ['enterprise-connection-oauth-config', '/docs/reference/backend/types/backend-enterprise-connection-oauth-config'], - ['enterprise-connection-saml-connection', '/docs/reference/backend/types/backend-enterprise-connection-saml-connection'], + [ + 'enterprise-connection-saml-connection', + '/docs/reference/backend/types/backend-enterprise-connection-saml-connection', + ], ['external-account', '/docs/reference/backend/types/backend-external-account'], ['phone-number', '/docs/reference/backend/types/backend-phone-number'], ['saml-account', '/docs/reference/backend/types/backend-saml-account'], @@ -114,6 +120,14 @@ const LINK_REPLACEMENTS = [ ['deleted-object-resource', '/docs/reference/types/deleted-object-resource'], ['checkout-flow-resource', '/docs/reference/hooks/use-checkout#checkout-flow-resource'], ['organization-creation-defaults-resource', '#organization-creation-defaults-resource'], + ['billing-namespace', '/docs/reference/objects/billing'], + ['api-keys-namespace', '/docs/reference/objects/api-keys'], + ['client-resource', '/docs/reference/objects/client'], + ['redirect-options', '/docs/reference/types/redirect-options'], + ['handle-o-auth-callback-params', '/docs/reference/types/handle-o-auth-callback-params'], + ['session-task', '/docs/reference/types/session-task'], + ['public-user-data', '/docs/reference/types/public-user-data'], + ['session-status', '/docs/reference/types/session-status'], ]; /** @@ -132,14 +146,33 @@ const LINK_REPLACEMENTS = [ function getRelativeLinkReplacements() { return LINK_REPLACEMENTS.map(([fileName, newPath]) => { return { - // Match both path and optional anchor - pattern: new RegExp(`\\((?:(?:\\.{1,2}\\/)+[^()]*?|)${fileName}\\.mdx(#[^)]+)?\\)`, 'g'), + // Match both flat links and nested object-doc links + // Also matches optional anchors (#) + pattern: new RegExp(`\\((?:(?:\\.{1,2}\\/)+[^()]*?|)(?:${fileName}\\/)?${fileName}\\.mdx(#[^)]+)?\\)`, 'g'), // Preserve the anchor in replacement if it exists replace: (/** @type {string} */ _match, anchor = '') => `(${newPath}${anchor})`, }; }); } +/** + * First pass of `MarkdownPageEvent.END`: rewrite `(foo.mdx)` / relative paths to `/docs/...` (see {@link LINK_REPLACEMENTS}). + * Used by `extract-methods.mjs`, which does not go through the renderer hook. + * + * @param {string} contents + */ +export function applyRelativeLinkReplacements(contents) { + if (!contents) { + return contents; + } + let out = contents; + for (const { pattern, replace } of getRelativeLinkReplacements()) { + // @ts-ignore — string | function + out = out.replace(pattern, replace); + } + return out; +} + function getCatchAllReplacements() { return [ { @@ -147,96 +180,175 @@ function getCatchAllReplacements() { replace: '[ClerkAPIResponseError](/docs/reference/types/clerk-api-response-error)', }, { - pattern: /(?/g, - replace: '[`Appearance`](/docs/guides/customizing-clerk/appearance-prop/overview)', + pattern: /(?/g, + replace: '[Appearance](/docs/guides/customizing-clerk/appearance-prop/overview)', + }, + { + pattern: /(? `[${type}](/docs/reference/types/errors)`, + }, + { + pattern: /(? - `[\`${type}\`](/docs/reference/types/errors)`, + pattern: /(? { + if (!inner.includes('|')) { + return full; + } + const id = placeholders.length; + placeholders.push(full); + return `\uE000${id}\uE001`; + }); + return { text, placeholders }; +} + +/** + * @param {string} text + * @param {string[]} placeholders + */ +function restoreProtectedInlineCodeSpans(text, placeholders) { + return text.replace(PIPE_CODE_PH, (_, /** @type {string} */ i) => placeholders[Number(i)] ?? ''); +} + +/** + * Remove the Properties section (heading + table) from reference object pages (e.g. `shared/clerk/clerk.mdx`); the table body (no heading) is copied into `shared//properties.mdx` by `extract-methods.mjs`. + * + * @param {string} contents + */ +export function stripReferenceObjectPropertiesSection(contents) { + if (!contents) { + return contents; + } + const stripped = contents.replace(/\r\n/g, '\n').replace(/\n## Properties\n+[\s\S]*$/, ''); + return stripped.trimEnd() + '\n'; +} + +/** + * Second pass of `MarkdownPageEvent.END` (after {@link applyRelativeLinkReplacements}). + * Used by `extract-methods.mjs`, which writes MDX outside TypeDoc and never hits that hook. + * + * Skips ATX heading lines (`#` … `######`) so titles like `#### SetActiveParams` are never linkified. + * (A lone `(? { + if (ATX_HEADING_LINE.test(line.replace(/\r$/, ''))) { + return line; + } + const { text: withPh, placeholders } = protectPipeDelimitedInlineCodeSpans(line); + let out = withPh; + for (const { pattern, replace } of getCatchAllReplacements()) { + // @ts-ignore — string | function + out = out.replace(pattern, replace); + } + return restoreProtectedInlineCodeSpans(out, placeholders); + }, + ) + .join('\n'); +} + /** * @param {import('typedoc-plugin-markdown').MarkdownApplication} app */ export function load(app) { + /** + * `@generateWithEmptyComment` exists only to make "intentionally undocumented" explicit at the source. + * Strip it from the model post-resolve so the markdown plugin sees a comment indistinguishable from `/** *​/` — + * otherwise the table renderer treats the modifier as content and drops the `-` placeholder in the description column. + */ + app.converter.on(Converter.EVENT_RESOLVE_END, context => { + for (const reflection of Object.values(context.project.reflections)) { + reflection.comment?.modifierTags?.delete('@generateWithEmptyComment'); + } + }); + app.renderer.on(MarkdownPageEvent.END, output => { const fileName = output.url.split('/').pop(); - const linkReplacements = getRelativeLinkReplacements(); - for (const { pattern, replace } of linkReplacements) { - if (output.contents) { - output.contents = output.contents.replace(pattern, replace); - } + if (output.contents) { + output.contents = applyRelativeLinkReplacements(output.contents); } - const catchAllReplacements = getCatchAllReplacements(); - - for (const { pattern, replace } of catchAllReplacements) { - if (output.contents) { - // @ts-ignore - Mixture of string and function replacements - output.contents = output.contents.replace(pattern, replace); - } + if (output.contents) { + output.contents = applyCatchAllMdReplacements(output.contents); } if (fileName) { diff --git a/.typedoc/custom-router.mjs b/.typedoc/custom-router.mjs index 97cf8acef8d..b56f1eb57e8 100644 --- a/.typedoc/custom-router.mjs +++ b/.typedoc/custom-router.mjs @@ -1,6 +1,14 @@ // @ts-check +import { ReflectionKind } from 'typedoc'; import { MemberRouter } from 'typedoc-plugin-markdown'; +import { REFERENCE_OBJECT_PAGE_SYMBOLS } from './reference-objects.mjs'; +import { toUrlSlug } from './slug.mjs'; +import { isInlineModifierWithoutStandalonePage } from './standalone-page-tag.mjs'; + +/** @type {Set} */ +const REFERENCE_OBJECT_SYMBOL_NAMES = new Set(Object.values(REFERENCE_OBJECT_PAGE_SYMBOLS)); + /** * From a filepath divided by `/` only keep the first and last part * @param {string} filePath @@ -13,13 +21,6 @@ function flattenDirName(filePath) { return filePath; } -/** - * @param {string} str - */ -function toKebabCase(str) { - return str.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase(); -} - /** * @param {import('typedoc-plugin-markdown').MarkdownApplication} app */ @@ -47,7 +48,20 @@ class ClerkRouter extends MemberRouter { const isExactMatch = page.url.toLocaleLowerCase().endsWith('readme.mdx'); const isMatchWithNumber = page.url.toLocaleLowerCase().match(/readme-\d+\.mdx$/); - return !(isExactMatch || isMatchWithNumber); + if (isExactMatch || isMatchWithNumber) { + return false; + } + + /** + * `@inline` marks types that should be expanded at use sites, not documented as their own page unless `@standalonePage` is also set (see `standalone-page-tag.mjs`). + * TypeDoc still assigns `fullUrls` for exported aliases, so we also strip links in the theme's `referenceType` partial (`custom-theme.mjs`). + */ + const model = page.model; + if (model && isInlineModifierWithoutStandalonePage(/** @type {import('typedoc').Reflection} */ (model))) { + return false; + } + + return true; }); return modifiedPages; @@ -59,7 +73,7 @@ class ClerkRouter extends MemberRouter { getIdealBaseName(reflection) { const original = super.getIdealBaseName(reflection); // Convert URLs (by default camelCase) to kebab-case - let filePath = toKebabCase(original); + let filePath = toUrlSlug(original); /** * By default, the paths are deeply nested, e.g.: @@ -72,6 +86,22 @@ class ClerkRouter extends MemberRouter { */ filePath = flattenDirName(filePath); + /** + * Put each reference object in its own folder alongside `properties.mdx` and `methods/` from `extract-methods.mjs`. + * E.g. `shared/clerk.mdx` -> `shared/clerk/clerk.mdx`, `shared/clerk/properties.mdx`, and `shared/clerk/methods/`. + */ + if ( + (reflection.kind === ReflectionKind.Interface || reflection.kind === ReflectionKind.Class) && + REFERENCE_OBJECT_SYMBOL_NAMES.has(reflection.name) + ) { + const kebab = toUrlSlug(reflection.name); + const m = filePath.match(/^([^/]+)\/([^/]+)$/); + if (m) { + const [, pkg] = m; + return `${pkg}/${kebab}/${kebab}`; + } + } + return filePath; } } diff --git a/.typedoc/custom-theme.mjs b/.typedoc/custom-theme.mjs index ec1c32fa2dd..dc06bc65608 100644 --- a/.typedoc/custom-theme.mjs +++ b/.typedoc/custom-theme.mjs @@ -1,7 +1,985 @@ // @ts-check -import { ReflectionKind, ReflectionType, UnionType } from 'typedoc'; +import { ArrayType, i18n, IntersectionType, ReferenceType, ReflectionKind, ReflectionType, UnionType } from 'typedoc'; import { MarkdownTheme, MarkdownThemeContext } from 'typedoc-plugin-markdown'; +import { applyTodoStrippingToComment } from './comment-utils.mjs'; +import { backTicks, heading, htmlTable, removeLineBreaks, table } from './markdown-helpers.mjs'; +import { REFERENCE_OBJECTS_LIST } from './reference-objects.mjs'; +import { isInlineModifierWithoutStandalonePage } from './standalone-page-tag.mjs'; +import { unwrapOptional } from './type-utils.mjs'; + +export { REFERENCE_OBJECTS_LIST }; + +/** + * Unwrap optional TypeDoc types so referenced object shapes are still found. + * + * @param {import('typedoc').Type} t + * @returns {import('typedoc').Type} + */ +/** + * Prefer structural checks over `instanceof` so we still match when multiple TypeDoc copies are loaded (otherwise `instanceof IntersectionType` is false at render time). + * + * @param {import('typedoc').Type | undefined} t + * @returns {t is import('typedoc').IntersectionType} + */ +function isIntersectionTypeDoc(t) { + const o = /** @type {{ type?: string; types?: import('typedoc').Type[] } | null} */ (t); + return Boolean(o && typeof o === 'object' && o.type === 'intersection' && Array.isArray(o.types)); +} + +/** + * @param {import('typedoc').Type | undefined} t + * @returns {t is import('typedoc').ReferenceType} + */ +function isReferenceTypeDoc(/** @type {import('typedoc').Type | undefined} */ t) { + return Boolean(t && typeof t === 'object' && /** @type {{ type?: string }} */ (t).type === 'reference'); +} + +/** + * @param {import('typedoc').Type | undefined} t + * @returns {t is import('typedoc').ReflectionType} + */ +function isReflectionTypeDoc(/** @type {import('typedoc').Type | undefined} */ t) { + return Boolean(t && typeof t === 'object' && /** @type {{ type?: string }} */ (t).type === 'reflection'); +} + +/** + * @param {import('typedoc').Type | undefined} t + * @returns {boolean} + */ +function isUnionTypeDoc(/** @type {import('typedoc').Type | undefined} */ t) { + const o = /** @type {{ type?: string; types?: import('typedoc').Type[] } | null} */ (t); + return Boolean(o && typeof o === 'object' && o.type === 'union' && Array.isArray(o.types)); +} + +/** + * Stock `typedoc-plugin-markdown` `arrayType` only wraps `elementType.type === 'union'`. + * For `T | T[]` where `T` is an `@inline` alias to a union, the element is still a `reference` in the model but renders as `"a" \| "b"`, producing `"a" \| "b"[]` (wrong binding). Instead, parens the array type whenever the reference inlines to a union RHS so it produces `("a" \| "b")[]`. + * E.g. `status` in `GetUserOrganizationSuggestionsParams`. + * + * @param {import('typedoc').Type | undefined} elementType + * @returns {boolean} + */ +function isArrayElementReferenceInliningToUnion(elementType) { + if (!isReferenceTypeDoc(elementType)) { + return false; + } + const ref = /** @type {import('typedoc').ReferenceType} */ (elementType); + if (!ref.reflection) { + return false; + } + if (!isInlineModifierWithoutStandalonePage(ref.reflection)) { + return false; + } + const decl = /** @type {import('typedoc').DeclarationReflection} */ (ref.reflection); + if (!decl.kindOf?.(ReflectionKind.TypeAlias) || !decl.type) { + return false; + } + return isUnionTypeDoc(decl.type); +} + +/** + * When `ReferenceType.reflection` is unset (common for imported aliases), resolve by name in the converted project. + * + * @param {import('typedoc').ProjectReflection | undefined} project + * @param {string} name + * @returns {import('typedoc').DeclarationReflection | undefined} + */ +function findNamedTypeDeclaration(project, name) { + if (!project?.reflections) { + return undefined; + } + for (const r of Object.values(project.reflections)) { + if (r.name !== name) { + continue; + } + if (r.kind === ReflectionKind.TypeAlias || r.kind === ReflectionKind.Interface) { + return /** @type {import('typedoc').DeclarationReflection} */ (r); + } + } + return undefined; +} + +/** + * Prefer `packages/shared/src/types/strategies.ts` when multiple type aliases share the name `OAuthStrategy`. + * + * @param {import('typedoc').ProjectReflection | undefined} project + * @returns {import('typedoc').DeclarationReflection | undefined} + */ +function findOAuthStrategyDeclaration(project) { + if (!project) { + return undefined; + } + /** @param {import('typedoc').Reflection} r */ + const sourcePath = r => { + const sources = /** @type {{ sources?: object[] }} */ (r).sources; + const s = sources?.[0]; + if (!s) { + return ''; + } + const raw = /** @type {{ file?: { fullFileName?: string }; fullFileName?: string }} */ (s); + const p = raw.file?.fullFileName ?? raw.fullFileName ?? ''; + return String(p).replace(/\\/g, '/'); + }; + + const byKind = + typeof project.getReflectionsByKind === 'function' + ? project.getReflectionsByKind(ReflectionKind.TypeAlias).filter(r => r.name === 'OAuthStrategy') + : Object.values(project.reflections ?? {}).filter( + r => + r.name === 'OAuthStrategy' && + /** @type {import('typedoc').Reflection} */ (r).kindOf?.(ReflectionKind.TypeAlias), + ); + if (byKind.length === 0) { + return findNamedTypeDeclaration(project, 'OAuthStrategy'); + } + if (byKind.length === 1) { + return /** @type {import('typedoc').DeclarationReflection} */ (byKind[0]); + } + const fromStrategies = byKind.find(r => sourcePath(r).includes('strategies')); + return /** @type {import('typedoc').DeclarationReflection | undefined} */ (fromStrategies ?? byKind[0]); +} + +/** + * Stock `someType` uses `instanceof UnionType`; duplicate Typedoc copies in the tree break that check and unions fall through to `backTicks(model.toString())`, bypassing {@link unionType} entirely (including OAuth collapse). + * + * @param {import('typedoc').Type | undefined} model + * @returns {import('typedoc').UnionType | undefined} + */ +function coerceUnionTypeIfNeeded(model) { + if (!model || typeof model !== 'object') { + return undefined; + } + if (model instanceof UnionType) { + return model; + } + const o = /** @type {{ type?: string; types?: import('typedoc').SomeType[] }} */ (model); + if (o.type === 'union' && Array.isArray(o.types) && o.types.length) { + return new UnionType(o.types); + } + return undefined; +} + +/** + * TypeScript normalizes `OAuthStrategy` to a large union of `oauth_*` string literals plus `` `oauth_custom_${string}` ``. That is not a {@link ReferenceType}, so the theme prints every literal. Collapse **only** when the union clearly matches that expanded Clerk shape, then render a link to `OAuthStrategy`. + * + * Guards (all must pass): many `oauth_` literals, fingerprint literals present, optional `oauth_custom_` template arm, `OAuthStrategy` exists and is not `@inline`. Skips ambiguous cases so other unions are unchanged. + * + * @param {import('typedoc').Type | undefined} t + * @returns {import('typedoc').Type[]} + */ +function flattenUnionTypeMembersForOAuthCollapse(t) { + if (!t || typeof t !== 'object') { + return []; + } + const o = /** @type {{ type?: string; types?: import('typedoc').Type[] }} */ (t); + if (o.type === 'union' && Array.isArray(o.types)) { + /** @type {import('typedoc').Type[]} */ + const acc = []; + for (const inner of o.types) { + acc.push(...flattenUnionTypeMembersForOAuthCollapse(inner)); + } + return acc; + } + return [t]; +} + +/** + * @param {import('typedoc').Type} t + */ +function isExpandedOAuthStrategyUnionArm(t) { + const o = /** @type {{ type?: string; value?: unknown; head?: string; tail?: unknown }} */ (t); + if (o.type === 'literal' && typeof o.value === 'string') { + return o.value.startsWith('oauth_'); + } + if (o.type === 'templateLiteral' && typeof o.head === 'string') { + return o.head === 'oauth_custom_'; + } + return false; +} + +/** Minimum distinct `oauth_*` literal arms before we treat the union as “expanded OAuthStrategy”. */ +const OAUTH_STRATEGY_COLLAPSE_MIN_LITERAL_ARMS = 12; + +/** + * @param {import('typedoc').UnionType} model + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @returns {import('typedoc').UnionType | undefined} + */ +function tryCollapseExpandedOAuthStrategyUnion(model, ctx) { + const project = ctx.page?.project; + if (!project) { + return undefined; + } + const oauthDecl = findOAuthStrategyDeclaration(project); + if (!oauthDecl?.kindOf(ReflectionKind.TypeAlias)) { + return undefined; + } + if (oauthDecl.comment?.hasModifier('@inline')) { + return undefined; + } + + const members = flattenUnionTypeMembersForOAuthCollapse(model); + const oauthArms = members.filter(isExpandedOAuthStrategyUnionArm); + if (oauthArms.length < OAUTH_STRATEGY_COLLAPSE_MIN_LITERAL_ARMS) { + return undefined; + } + + const literalVals = oauthArms + .filter(u => /** @type {{ type?: string }} */ (u).type === 'literal') + .map(u => /** @type {{ value?: unknown }} */ (/** @type {unknown} */ (u)).value) + .filter(/** @return {v is string} */ v => typeof v === 'string'); + const literalSet = new Set(literalVals); + if (!literalSet.has('oauth_google') || (!literalSet.has('oauth_facebook') && !literalSet.has('oauth_github'))) { + return undefined; + } + + const hasCustomTemplateArm = oauthArms.some(u => { + const o = /** @type {{ type?: string; head?: string }} */ (u); + return o.type === 'templateLiteral' && o.head === 'oauth_custom_'; + }); + /** Without the template arm, require an even larger literal set (avoids small hand-written unions). */ + if (!hasCustomTemplateArm && literalVals.length < 20) { + return undefined; + } + + const ref = ReferenceType.createResolvedReference('OAuthStrategy', oauthDecl, project); + /** @type {import('typedoc').Type[]} */ + const out = []; + let i = 0; + while (i < members.length) { + if (isExpandedOAuthStrategyUnionArm(members[i])) { + out.push(ref); + i++; + while (i < members.length && isExpandedOAuthStrategyUnionArm(members[i])) { + i++; + } + } else { + out.push(members[i]); + i++; + } + } + return new UnionType(/** @type {import('typedoc').SomeType[]} */ (/** @type {unknown} */ (out))); +} + +/** + * Collect documented property reflections from one intersection arm (object literal, type alias, interface, nested `&`). + * E.g. `{ a: string } & { b: number }` => `[{ name: 'a', type: 'string' }, { name: 'b', type: 'number' }]` + * + * @param {import('typedoc').Type} t + * @param {Set} visitedReflectionIds + * @param {import('typedoc').ProjectReflection | undefined} project + * @returns {import('typedoc').DeclarationReflection[]} + */ +function collectPropertyReflectionsFromIntersectionArm(t, visitedReflectionIds, project) { + const unwrapped = unwrapOptional(t); + if (!unwrapped) { + return []; + } + + if (isReflectionTypeDoc(unwrapped)) { + const decl = unwrapped.declaration; + if (!decl) { + return []; + } + if (decl.signatures?.length && !decl.children?.length) { + return []; + } + return (decl.children ?? []).filter(c => c.kind === ReflectionKind.Property); + } + + if (isReferenceTypeDoc(unwrapped)) { + let ref = unwrapped.reflection; + if (!ref && unwrapped.name && project) { + ref = findNamedTypeDeclaration(project, unwrapped.name); + } + if (!ref) { + return []; + } + const declRef = /** @type {import('typedoc').DeclarationReflection | undefined} */ ( + 'kind' in ref ? ref : undefined + ); + if (!declRef) { + return []; + } + const id = declRef.id; + if (id != null) { + if (visitedReflectionIds.has(id)) { + return []; + } + visitedReflectionIds.add(id); + } + try { + if (declRef.kind === ReflectionKind.TypeAlias) { + if (declRef.children?.length) { + return declRef.children.filter( + /** @param {import('typedoc').DeclarationReflection} c */ + c => c.kind === ReflectionKind.Property, + ); + } + if (declRef.type) { + return collectPropertyReflectionsFromIntersectionArm(declRef.type, visitedReflectionIds, project); + } + return []; + } + if ( + (declRef.kind === ReflectionKind.Interface || declRef.kind === ReflectionKind.Class) && + declRef.children?.length + ) { + return declRef.children.filter( + /** @param {import('typedoc').DeclarationReflection} c */ + c => c.kind === ReflectionKind.Property, + ); + } + } finally { + if (id != null) { + visitedReflectionIds.delete(id); + } + } + return []; + } + + if (isIntersectionTypeDoc(unwrapped)) { + /** @type {import('typedoc').DeclarationReflection[]} */ + const out = []; + for (const arm of unwrapped.types) { + out.push(...collectPropertyReflectionsFromIntersectionArm(arm, visitedReflectionIds, project)); + } + return out; + } + + if (isUnionTypeDoc(unwrapped)) { + return collectPropertyReflectionsFromUnionObjectArms(unwrapped, visitedReflectionIds, project); + } + + return []; +} + +/** + * Merge intersection arms into one property list (later duplicate names override earlier ones, then sort by name). + * type A = type B & type C; type A's properties will be the union of B's and C's properties. + * E.g. `ClerkOptions` in clerk.ts + * + * @param {import('typedoc').IntersectionType} intersection + * @param {import('typedoc').ProjectReflection | undefined} project + * @returns {import('typedoc').DeclarationReflection[]} + */ +function mergeIntersectionPropertyReflections(intersection, project) { + /** @type {Map} */ + const byName = new Map(); + const visited = new Set(); + for (const arm of intersection.types) { + for (const p of collectPropertyReflectionsFromIntersectionArm(arm, visited, project)) { + byName.set(p.name, p); + } + } + return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)); +} + +/** + * For properties typed something like `false \| { a?: … }`, `getFlattenedDeclarations` does not walk the union, so nested keys never become table rows. Collect object members from each union arm (primitives/literals yield nothing). + * E.g. `telemetry` prop in clerk.ts + * + * @param {import('typedoc').Type | undefined} t + * @param {Set} visitedReflectionIds + * @param {import('typedoc').ProjectReflection | undefined} project + * @returns {import('typedoc').DeclarationReflection[]} + */ +function collectPropertyReflectionsFromUnionObjectArms(t, visitedReflectionIds, project) { + const unwrapped = unwrapOptional(t); + if (!unwrapped || /** @type {{ type?: string }} */ (unwrapped).type !== 'union') { + return []; + } + const union = /** @type {import('typedoc').UnionType} */ (unwrapped); + /** @type {Map} */ + const byName = new Map(); + for (const arm of union.types) { + for (const p of collectPropertyReflectionsFromIntersectionArm(arm, visitedReflectionIds, project)) { + byName.set(p.name, p); + } + } + return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)); +} + +/** + * Appends `parent.child` rows for union object arms (e.g. `false \| { disabled?: … }`). **Only** used when building {@link clerkTypeDeclarationTable}; we intentionally do **not** hook `helpers.getFlattenedDeclarations` globally — otherwise top-level `propertiesTable` output (e.g. `Clerk`) would gain synthetic rows like `client.*` for every property whose type is a union such as `ClientResource \| undefined`. + * + * @template {import('typedoc').DeclarationReflection} T + * @param {T[]} base + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext['helpers']} helpers + * @param {import('typedoc').ProjectReflection} project + * @returns {T[]} + */ +function appendUnionObjectChildPropertyRows(base, helpers, project) { + /** @type {T[]} */ + const out = []; + for (const prop of base) { + out.push(prop); + if (prop.name.includes('.')) { + continue; + } + const nested = collectPropertyReflectionsFromUnionObjectArms(helpers.getDeclarationType(prop), new Set(), project); + for (const child of nested) { + out.push( + /** @type {T} */ ( + /** @type {unknown} */ ({ + ...child, + name: `${prop.name}.${child.name}`, + getFullName: () => prop.getFullName(), + getFriendlyFullName: () => prop.getFriendlyFullName(), + }) + ), + ); + } + } + return out; +} + +/** + * @param {import('typedoc').ParameterReflection[]} parameters + */ +function hasDefaultValuesForParameters(parameters) { + const defaultValues = parameters.map( + param => param.defaultValue !== '{}' && param.defaultValue !== '...' && !!param.defaultValue, + ); + return !defaultValues.every(value => !value); +} + +/** + * Object shape for a parameter: inline `{ … }`, optional-wrapped, or reference to a type alias / interface. + * + * @param {import('typedoc').Type | undefined} t + * @returns {import('typedoc').DeclarationReflection | undefined} + */ +function getParameterObjectShapeDeclaration(t) { + if (!t || typeof t !== 'object') { + return undefined; + } + const o = + /** @type {{ type?: string; declaration?: import('typedoc').DeclarationReflection; elementType?: import('typedoc').Type }} */ ( + /** @type {unknown} */ (t) + ); + if (o.type === 'optional' && o.elementType) { + return getParameterObjectShapeDeclaration(o.elementType); + } + if (o.type === 'reflection' && o.declaration) { + const d = o.declaration; + if (d.kind === ReflectionKind.TypeLiteral || d.kind === ReflectionKind.Interface) { + return d; + } + } + if (o.type === 'reference') { + const ref = /** @type {import('typedoc').ReferenceType} */ (t); + const sym = ref.reflection; + if (!sym) { + return undefined; + } + const target = /** @type {import('typedoc').DeclarationReflection} */ (sym); + if (sym.kind === ReflectionKind.TypeAlias && target.type) { + return getParameterObjectShapeDeclaration(target.type); + } + if (sym.kind === ReflectionKind.Interface) { + return target; + } + } + return undefined; +} + +/** + * Same as typedoc-plugin-markdown `member.parametersTable`, but avoids useless duplicate rows when a one-property object has **no** property-level JSDoc (the description lives only on `@param`). When the sole property **does** have its own documentation, we flatten so both rows appear. + * + * @param {import('typedoc').DeclarationReflection | undefined} decl + */ +function shouldFlattenInlineObjectParameter(decl) { + if (!decl?.children?.length) { + return false; + } + if (decl.kind !== ReflectionKind.TypeLiteral && decl.kind !== ReflectionKind.Interface) { + return false; + } + if (decl.children.length > 1) { + return true; + } + const only = decl.children[0]; + return Boolean(only?.comment?.hasVisibleComponent()); +} + +/** + * Same as typedoc-plugin-markdown `member.parametersTable`, with `shouldFlattenInlineObjectParameter` and `getParameterObjectShapeDeclaration`. + * + * @this {import('typedoc-plugin-markdown').MarkdownThemeContext} + * @param {import('typedoc').ParameterReflection[]} model + */ +function clerkParametersTable(model) { + const tableColumnsOptions = /** @type {{ leftAlignHeaders?: boolean; hideDefaults?: boolean }} */ ( + this.options.getValue('tableColumnSettings') ?? {} + ); + const leftAlignHeadings = tableColumnsOptions.leftAlignHeaders; + /** + * @param {import('typedoc').ParameterReflection} current + * @param {import('typedoc').ParameterReflection[]} acc + * @returns {import('typedoc').ParameterReflection[]} + */ + const parseParams = (current, acc) => { + const decl = getParameterObjectShapeDeclaration(current.type); + const shouldFlatten = shouldFlattenInlineObjectParameter(decl); + return shouldFlatten ? [...acc, current, ...flattenParams(current)] : [...acc, current]; + }; + /** + * Joins flattened names with `?.` when the parent is optional (so `options?.foo` reflects the type at runtime) and `.` when required (`options.foo`). Same logic recurses for deeper inline shapes: separator between each level depends on **that** level's optionality. + * + * @param {import('typedoc').ParameterReflection} current + * @returns {import('typedoc').ParameterReflection[]} + */ + const flattenParams = current => { + const decl = getParameterObjectShapeDeclaration(current.type); + const separator = current.flags?.isOptional ? '?.' : '.'; + return ( + decl?.children?.reduce( + /** + * @param {import('typedoc').ParameterReflection[]} acc + * @param {import('typedoc').DeclarationReflection} child + * @returns {import('typedoc').ParameterReflection[]} + */ + (acc, child) => { + const childObj = { + ...child, + name: `${current.name}${separator}${child.name}`, + }; + return parseParams( + /** @type {import('typedoc').ParameterReflection} */ (/** @type {unknown} */ (childObj)), + acc, + ); + }, + /** @type {import('typedoc').ParameterReflection[]} */ ([]), + ) ?? [] + ); + }; + const showDefaults = !tableColumnsOptions.hideDefaults && hasDefaultValuesForParameters(model); + const parsedParams = /** @type {import('typedoc').ParameterReflection[]} */ ( + model.reduce( + (acc, current) => parseParams(current, acc), + /** @type {import('typedoc').ParameterReflection[]} */ ([]), + ) + ); + const hasComments = parsedParams.some(param => Boolean(param.comment)); + const theme = /** @type {Record string>} */ (/** @type {unknown} */ (i18n)); + const headers = [ReflectionKind.singularString(ReflectionKind.Parameter), theme.theme_type()]; + if (showDefaults) { + headers.push(theme.theme_default_value()); + } + if (hasComments) { + headers.push(theme.theme_description()); + } + const firstOptionalParamIndex = model.findIndex(parameter => parameter.flags.isOptional); + /** @type {string[][]} */ + const rows = []; + parsedParams.forEach((parameter, i) => { + const row = []; + const isOptional = parameter.flags.isOptional || (firstOptionalParamIndex !== -1 && i > firstOptionalParamIndex); + const rest = parameter.flags?.isRest ? '...' : ''; + const optional = isOptional ? '?' : ''; + row.push(`${rest}${backTicks(`${parameter.name}${optional}`)}`); + if (parameter.type) { + const displayType = + parameter.type instanceof ReflectionType + ? this.partials.reflectionType(parameter.type, { + forceCollapse: true, + }) + : this.partials.someType(parameter.type); + row.push(removeLineBreaks(displayType)); + } + if (showDefaults) { + row.push(backTicks(this.helpers.getParameterDefaultValue(parameter))); + } + if (hasComments) { + if (parameter.comment) { + row.push(this.partials.comment(parameter.comment, { isTableColumn: true })); + } else { + row.push('-'); + } + } + rows.push(row); + }); + return this.options.getValue('parametersFormat') == 'table' + ? table(headers, rows, leftAlignHeadings) + : htmlTable(headers, rows, leftAlignHeadings); +} + +/** + * Used in `clerkTypeDeclarationTable()` to determine if the table should be displayed as an HTML table. + * + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} context + * @param {import('typedoc').ReflectionKind | undefined} kind + */ +function clerkShouldDisplayHtmlTable(context, kind) { + if ( + kind && + [ReflectionKind.CallSignature, ReflectionKind.Variable, ReflectionKind.TypeAlias].includes(kind) && + context.options.getValue('typeDeclarationFormat') == 'htmlTable' + ) { + return true; + } + if (kind === ReflectionKind.Property && context.options.getValue('propertyMembersFormat') == 'htmlTable') { + return true; + } + return false; +} + +/** + * Same rules as typedoc-plugin-markdown `shouldDisplayHTMLTable` in `member.propertiesTable.js` (that helper is not exported). Drives **property-style** tables: `propertiesFormat`, `interfacePropertiesFormat`, etc. + * + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} context + * @param {import('typedoc').ReflectionKind | undefined} kind + */ +function propertiesTableUsesHtmlTable(context, kind) { + if (context.options.getValue('propertiesFormat') === 'htmlTable') { + return true; + } + if (kind === ReflectionKind.Interface && context.options.getValue('interfacePropertiesFormat') === 'htmlTable') { + return true; + } + if (kind === ReflectionKind.Class && context.options.getValue('classPropertiesFormat') === 'htmlTable') { + return true; + } + if (kind === ReflectionKind.TypeAlias && context.options.getValue('typeAliasPropertiesFormat') === 'htmlTable') { + return true; + } + return false; +} + +/** + * Renders a pipe or HTML table using {@link propertiesTableUsesHtmlTable} and `tableColumnSettings.leftAlignHeaders`, matching `member.propertiesTable` output conventions. + * + * @this {import('typedoc-plugin-markdown').MarkdownThemeContext} + * @param {{ + * headers: string[]; + * rows: string[][]; + * kind?: import('typedoc').ReflectionKind; + * }} args + */ +function renderPropertiesFormatTable(args) { + const tableColumnsOptions = /** @type {{ leftAlignHeaders?: boolean }} */ ( + this.options.getValue('tableColumnSettings') ?? {} + ); + const leftAlignHeadings = tableColumnsOptions.leftAlignHeaders; + const kind = args.kind ?? ReflectionKind.TypeAlias; + const useHtml = propertiesTableUsesHtmlTable(this, kind); + return useHtml + ? htmlTable(args.headers, args.rows, leftAlignHeadings) + : table(args.headers, args.rows, leftAlignHeadings); +} + +/** + * Same logic as typedoc-plugin-markdown `member.typeDeclarationTable`, but **always** runs `getFlattenedDeclarations` and then {@link appendUnionObjectChildPropertyRows} (union-object arm rows like `telemetry.*`). The default plugin skips flattening in `compact` mode, which hides nested keys like `telemetry.disabled`. + * + * @this {import('typedoc-plugin-markdown').MarkdownThemeContext} + * @param {import('typedoc').DeclarationReflection[]} model + * @param {{ kind?: import('typedoc').ReflectionKind }} options + */ +function clerkTypeDeclarationTable(model, options) { + const tableColumnsOptions = /** @type {{ leftAlignHeaders?: boolean; hideSources?: boolean }} */ ( + this.options.getValue('tableColumnSettings') ?? {} + ); + const leftAlignHeadings = tableColumnsOptions.leftAlignHeaders; + // typedoc-plugin-markdown's `TypeDeclarationVisibility.Compact` is just the string `'compact'`. + const isCompact = this.options.getValue('typeDeclarationVisibility') === 'compact'; + const hasSources = !tableColumnsOptions.hideSources && !this.options.getValue('disableSources'); + const headers = []; + const baseDeclarations = this.helpers.getFlattenedDeclarations(model, { + includeSignatures: true, + }); + const project = this.page?.project ?? this.page?.model?.project; + const declarations = project + ? appendUnionObjectChildPropertyRows(baseDeclarations, this.helpers, project) + : baseDeclarations; + const hasDefaultValues = declarations.some( + declaration => Boolean(declaration.defaultValue) && declaration.defaultValue !== '...', + ); + const hasComments = declarations.some(declaration => Boolean(declaration.comment)); + const theme = /** @type {Record string>} */ (/** @type {unknown} */ (i18n)); + headers.push(theme.theme_name()); + headers.push(theme.theme_type()); + if (hasDefaultValues) { + headers.push(theme.theme_default_value()); + } + if (hasComments) { + headers.push(theme.theme_description()); + } + if (hasSources) { + headers.push(theme.theme_defined_in()); + } + /** @type {string[][]} */ + const rows = []; + declarations.forEach(declaration => { + const declType = /** @type {{ declaration?: import('typedoc').DeclarationReflection } | undefined} */ ( + /** @type {unknown} */ (declaration.type) + ); + const optional = declaration.flags.isOptional ? '?' : ''; + const isSignature = declType?.declaration?.signatures?.length || declaration.signatures?.length; + const row = []; + const nameColumn = []; + if (this.router.hasUrl(declaration) && this.router.getAnchor(declaration)) { + nameColumn.push(``); + } + const name = backTicks(`${declaration.name}${isSignature ? '()' : ''}${optional}`); + nameColumn.push(name); + row.push(nameColumn.join(' ')); + if (isCompact && declaration.type instanceof ReflectionType) { + row.push( + this.partials.reflectionType(declaration.type, { + forceCollapse: isCompact, + }), + ); + } else { + const type = []; + const signatures = declaration.signatures; + if (signatures?.length) { + signatures.forEach(sig => { + type.push(`${this.partials.signatureParameters(sig.parameters || [])} => `); + }); + type.push(this.partials.someType(declaration.type)); + } else { + type.push(this.partials.someType(declaration.type)); + } + row.push(type.join('')); + } + if (hasDefaultValues) { + row.push( + !declaration.defaultValue || declaration.defaultValue === '...' ? '-' : backTicks(declaration.defaultValue), + ); + } + if (hasComments) { + const commentsOut = []; + if (declaration.comment) { + commentsOut.push( + this.partials.comment(declaration.comment, { + isTableColumn: true, + }), + ); + } + if (declType?.declaration?.signatures?.length) { + for (const sig of declType.declaration.signatures) { + if (sig.comment) { + commentsOut.push( + this.partials.comment(sig.comment, { + isTableColumn: true, + }), + ); + } + } + } + if (commentsOut.length) { + row.push(commentsOut.join('\n\n')); + } else { + row.push('-'); + } + } + if (hasSources) { + row.push(this.partials.sources(declaration, { hideLabel: true })); + } + rows.push(row); + }); + return clerkShouldDisplayHtmlTable(this, options?.kind) + ? htmlTable(headers, rows, leftAlignHeadings) + : table(headers, rows, leftAlignHeadings); +} + +/** + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {import('typedoc').DeclarationReflection} model + * @param {{ nested?: boolean; headingLevel?: number }} opts + * @param {import('typedoc').DeclarationReflection[]} mergedChildren + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext['partials']} superPartials + */ +function renderMergedIntersectionDeclaration(ctx, model, opts, mergedChildren, superPartials) { + /** @type {string[]} */ + const md = []; + const headingLevel = opts.headingLevel ?? 2; + const nested = opts.nested ?? false; + + if (!nested && model.sources && !ctx.options.getValue('disableSources')) { + md.push(superPartials.sources(model)); + } + if (model?.documents) { + md.push(superPartials.documents(model, { headingLevel })); + } + if (model.comment) { + md.push( + ctx.partials.comment(model.comment, { + headingLevel, + showSummary: true, + showTags: false, + }), + ); + } + + const synthetic = /** @type {import('typedoc').DeclarationReflection} */ ( + /** @type {unknown} */ ({ + children: mergedChildren, + parent: model, + kind: ReflectionKind.TypeLiteral, + }) + ); + md.push(superPartials.typeDeclaration(synthetic, { headingLevel })); + + if (model.comment) { + md.push( + ctx.partials.comment(model.comment, { + headingLevel, + showSummary: false, + showTags: true, + showReturns: true, + }), + ); + } + md.push(superPartials.inheritance(model, { headingLevel: opts.headingLevel ?? headingLevel })); + return md.filter(Boolean).join('\n\n'); +} + +/** + * Union of literals with JSDoc on each `|` arm: **## Properties** + a table via {@link renderPropertiesFormatTable} (same formatting rules as `member.propertiesTable`). + * + * @this {import('typedoc-plugin-markdown').MarkdownThemeContext} + * @param {import('typedoc').DeclarationReflection} model + * @param {{ headingLevel?: number }} options + */ +function clerkLiteralUnionAsPropertiesTable(model, options) { + const unionType = /** @type {import('typedoc').UnionType} */ (model.type); + const headingLevel = options.headingLevel ?? 2; + const ti = /** @type {{ theme_type: () => string; theme_description: () => string }} */ ( + /** @type {unknown} */ (i18n) + ); + + const headers = [ReflectionKind.singularString(ReflectionKind.Property), ti.theme_type(), ti.theme_description()]; + + /** @type {string[][]} */ + const rows = []; + unionType.types.forEach((type, i) => { + const typeStr = removeLineBreaks(this.partials.someType(type)); + const anchorRaw = typeStr.replace(/^`|`$/g, '').replace(/"/g, '').trim(); + const anchorId = anchorRaw.toLowerCase().replace(/[^a-z0-9]/g, '') || `member-${i}`; + + const propertyCell = [``, backTicks(anchorRaw || `member-${i}`)].join(' '); + + const summary = unionType.elementSummaries?.[i]; + const description = summary ? this.helpers.getCommentParts(summary) : '-'; + + rows.push([propertyCell, typeStr, description]); + }); + + const tableBody = renderPropertiesFormatTable.call(this, { + headers, + rows, + kind: ReflectionKind.TypeAlias, + }); + + return [heading(headingLevel, ReflectionKind.pluralString(ReflectionKind.Property)), tableBody].join('\n\n'); +} + +/** + * Same as typedoc-plugin-markdown `member.declaration`, but type aliases whose value is a **union of only literals** (no `ReflectionType` members) still get a "Type declaration" section when TypeDoc populated {@link UnionType.elementSummaries} from JSDoc before each `|` arm. + * + * Stock `hasTypeDeclaration` required `types.some(t => t instanceof ReflectionType)`, so `SessionStatus` never reached {@link MarkdownThemeContext.partials.typeDeclarationUnionContainer} and only the summary line was emitted. + * + * @this {import('typedoc-plugin-markdown').MarkdownThemeContext} + * @param {import('typedoc').DeclarationReflection} model + * @param {{ headingLevel?: number; nested?: boolean }} [options] + */ +function clerkDeclaration(model, options = { headingLevel: 2, nested: false }) { + const md = []; + const opts = { + nested: false, + ...options, + }; + const headingLevel = opts.headingLevel ?? 2; + const optionsWithHeading = { ...options, headingLevel }; + + if (!opts.nested && model.sources && !this.options.getValue('disableSources')) { + md.push(this.partials.sources(model)); + } + if (model?.documents) { + md.push(this.partials.documents(model, { headingLevel })); + } + /** @type {import('typedoc').DeclarationReflection | undefined} */ + let typeDeclaration = + model.type && 'declaration' in model.type + ? /** @type {{ declaration?: import('typedoc').DeclarationReflection }} */ (model.type).declaration + : undefined; + if (model.type instanceof ArrayType && model.type?.elementType instanceof ReflectionType) { + typeDeclaration = model.type?.elementType?.declaration; + } + const hasTypeDeclaration = + Boolean(typeDeclaration) || + (model.type instanceof UnionType && + (model.type.types.some(type => type instanceof ReflectionType) || Boolean(model.type.elementSummaries?.length))); + if (model.comment) { + md.push( + this.partials.comment(model.comment, { + headingLevel, + showSummary: true, + showTags: false, + }), + ); + } + if (model.type instanceof IntersectionType) { + model.type?.types?.forEach(intersectionType => { + if ( + intersectionType instanceof ReflectionType && + !intersectionType.declaration.signatures && + intersectionType.declaration.children + ) { + md.push(heading(headingLevel, i18n.theme_type_declaration())); + md.push( + this.partials.typeDeclaration(intersectionType.declaration, { + headingLevel, + }), + ); + } + }); + } + if (model.typeParameters) { + md.push(heading(headingLevel, ReflectionKind.pluralString(ReflectionKind.TypeParameter))); + if (this.helpers.useTableFormat('parameters')) { + md.push(this.partials.typeParametersTable(model.typeParameters)); + } else { + md.push( + this.partials.typeParametersList(model.typeParameters, { + headingLevel, + }), + ); + } + } + if (hasTypeDeclaration) { + if (model.type instanceof UnionType) { + if (this.helpers.hasUsefulTypeDetails(model.type)) { + md.push(heading(headingLevel, i18n.theme_type_declaration())); + md.push(this.partials.typeDeclarationUnionContainer(model, optionsWithHeading)); + } + } else if (typeDeclaration) { + const useHeading = + typeDeclaration.children?.length && + (model.kind !== ReflectionKind.Property || this.helpers.useTableFormat('properties')); + if (useHeading) { + md.push(heading(headingLevel, i18n.theme_type_declaration())); + } + md.push(this.partials.typeDeclarationContainer(model, typeDeclaration, optionsWithHeading)); + } + } + if (model.comment) { + md.push( + this.partials.comment(model.comment, { + headingLevel, + showSummary: false, + showTags: true, + showReturns: true, + }), + ); + } + md.push(this.partials.inheritance(model, { headingLevel })); + return md.join('\n\n'); +} + /** * @param {import('typedoc-plugin-markdown').MarkdownApplication} app */ @@ -29,6 +1007,24 @@ class ClerkMarkdownTheme extends MarkdownTheme { */ const unionCommentMap = new Map(); +/** + * Only for the specified pages do we remove function-valued members from property tables in the "Properties" section. + * (Created for the extract-methods script as these methods will be extracted to separate files.) + * + * @param {string | undefined} pageUrl - The URL of the page to check. + * @param {readonly string[]} allowlist - The list of pages to check. + */ +function pageMatchesAllowlist(pageUrl, allowlist) { + if (!pageUrl) { + return false; + } + const normalized = pageUrl.replace(/\\/g, '/').replace(/^\.\//, ''); + return allowlist.some(entry => { + const e = entry.replace(/\\/g, '/').replace(/^\/+/, ''); + return normalized === e || normalized.endsWith(`/${e}`) || normalized.endsWith(e); + }); +} + /** * Our custom Clerk theme * @extends MarkdownThemeContext @@ -48,6 +1044,110 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { this.partials = { ...superPartials, + /** + * Ensure unions always route through `unionType` (OAuth collapse) even when `instanceof UnionType` fails. + * + * @param {import('typedoc').Type | undefined} model + * @param {Parameters[1]} [options] + */ + someType: (model, options) => { + const ut = coerceUnionTypeIfNeeded(model); + if (ut) { + const collapsed = tryCollapseExpandedOAuthStrategyUnion(ut, this); + const toRender = collapsed ?? ut; + return superPartials.someType.call(this, toRender, options); + } + return superPartials.someType.call( + this, + /** @type {import('typedoc').SomeType | undefined} */ (/** @type {unknown} */ (model)), + options, + ); + }, + /** + * Stock `comments.comment` prints every {@link Comment.modifierTags} as **`TitleCase`** before the summary (it does not consult `notRenderedTags`; that option only filters block tags). `@inline` / `@inlineType` are router/type hints; `@experimental` is SDK-only guidance — none of these must appear in property tables or prose. + * + * @param {import('typedoc').Comment} model + * @param {Parameters[1]} [options] + */ + comment: (model, options) => { + if (!model) { + return superPartials.comment.call(this, model, options); + } + const modelToRender = applyTodoStrippingToComment(model) ?? model; + const hidden = new Set(['@inline', '@inlineType', '@experimental', '@standalonePage']); + const modTags = Array.from(modelToRender.modifierTags ?? []); + if (modTags.some(/** @param {string} t */ t => hidden.has(t))) { + const clone = Object.assign(Object.create(Object.getPrototypeOf(modelToRender)), modelToRender, { + modifierTags: new Set(modTags.filter(/** @param {string} t */ t => !hidden.has(t))), + }); + return superPartials.comment.call(this, clone, options); + } + return superPartials.comment.call(this, modelToRender, options); + }, + /** + * Remove the blockquote signature line. + * + * @returns {string} + */ + declarationTitle: () => '', + /** + * TypeDoc's default links every {@link ReferenceType} to a URL. Types marked `@inline` are expanded at use sites and (via the router) have no standalone page — linking produces broken relative `.mdx` paths in extracted method docs. Render the **aliased type** (RHS) so literals and unions show as `'phone_code'`, not `PhoneCodeStrategy`, unless `@standalonePage` is set (`standalone-page-tag.mjs`). + * + * @param {import('typedoc').ReferenceType} model + */ + referenceType: model => { + if (isInlineModifierWithoutStandalonePage(model.reflection)) { + const decl = /** @type {import('typedoc').DeclarationReflection} */ (model.reflection); + // Generic instantiation, e.g. `Fn` — let `someType` apply type arguments. + if (model.typeArguments?.length) { + return removeLineBreaks(this.partials.someType(model)); + } + if (decl.kindOf(ReflectionKind.TypeAlias) && decl.type) { + return removeLineBreaks(this.partials.someType(decl.type)); + } + return backTicks(decl.name); + } + return superPartials.referenceType.call(this, model); + }, + /** + * On allowlisted reference-object pages, drop function-valued members and `@extractMethods` namespace parents from property tables (they are documented under `methods/`). + * `extract-methods.mjs` reuses this partial for nominal param tables and nested `@extractMethods` docs on the same URL; pass `applyAllowlistedPropertyTableRowFilters: false` so rows are not stripped. + * + * @param {import('typedoc').DeclarationReflection[]} model + * @param {Parameters[1] & { applyAllowlistedPropertyTableRowFilters?: boolean }} [options] + */ + propertiesTable: (model, options) => { + if (!Array.isArray(model)) { + return superPartials.propertiesTable(/** @type {any} */ (model), options); + } + + const allowlisted = pageMatchesAllowlist(this.page?.url, REFERENCE_OBJECTS_LIST); + const applyAllowlistFilters = allowlisted && options?.applyAllowlistedPropertyTableRowFilters !== false; + const filtered = applyAllowlistFilters + ? model.filter( + prop => !isCallableInterfaceProperty(prop, this.helpers) && !prop.comment?.hasModifier('@extractMethods'), + ) + : model; + return superPartials.propertiesTable(filtered, options); + }, + /** + * Parameter tables: same as the stock partial except single-property inline object params are not expanded to nested rows. + * + * @param {import('typedoc').ParameterReflection[]} model + */ + parametersTable: model => { + return clerkParametersTable.call(this, model); + }, + /** + * In `compact` mode the default plugin skips `getFlattenedDeclarations`, so union object members never get rows. + * Delegate to {@link clerkTypeDeclarationTable} which always flattens and applies {@link appendUnionObjectChildPropertyRows}. + * + * @param {import('typedoc').DeclarationReflection[]} model + * @param {{ kind?: import('typedoc').ReflectionKind }} options + */ + typeDeclarationTable: (model, options) => { + return clerkTypeDeclarationTable.call(this, model, options); + }, /** * This hides the "Type parameters" section and the signature title from the output (by default). Shows the signature title if the `@displayFunctionSignature` tag is present. * @param {import('typedoc').SignatureReflection} model @@ -88,7 +1188,9 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { // Find the immediate next heading after '## Parameters' const nextHeadingIndex = splitOutput.findIndex((item, index) => { // Skip the items before the parameters - if (index <= parametersIndex) return false; + if (index <= parametersIndex) { + return false; + } // Find the next heading return item.startsWith('##') || item.startsWith('\n##'); }); @@ -319,20 +1421,22 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { * @param {{ headingLevel: number, nested?: boolean }} options */ declaration: (model, options = { headingLevel: 2, nested: false }) => { - // Create a local override - const localPartials = { - ...this.partials, - declarationTitle: () => '', - }; - // Store original so that we can restore it later - const originalPartials = this.partials; - + const opts = { nested: false, ...options }; const customizedModel = model; customizedModel.typeParameters = undefined; - this.partials = localPartials; - const output = superPartials.declaration(customizedModel, options); - this.partials = originalPartials; + if (!opts.nested && model.type && isIntersectionTypeDoc(model.type)) { + const merged = mergeIntersectionPropertyReflections( + /** @type {import('typedoc').IntersectionType} */ (model.type), + model.project, + ); + if (merged.length > 0) { + const output = renderMergedIntersectionDeclaration(this, customizedModel, opts, merged, superPartials); + return output.replace(/^## Type declaration$/gm, ''); + } + } + + const output = clerkDeclaration.call(this, customizedModel, options); // Remove the "Type declaration" heading from the output // This heading is generated by the original declaration partial @@ -374,7 +1478,8 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { * @param {import('typedoc').UnionType} model */ unionType: model => { - const defaultOutput = superPartials.unionType(model); + const collapsed = tryCollapseExpandedOAuthStrategyUnion(model, this); + const defaultOutput = superPartials.unionType(collapsed ?? model); const output = defaultOutput // Escape stuff that would be turned into markdown @@ -430,6 +1535,20 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { * @param {{ headingLevel: number }} options */ typeDeclarationUnionContainer: (model, options) => { + const optionsWithHeading = { ...options, headingLevel: options?.headingLevel ?? 2 }; + + if (model.type instanceof UnionType) { + const ut = model.type; + const unionReturnHeadings = model.comment?.getTag('@unionReturnHeadings'); + if ( + !ut.types.some(arm => arm instanceof ReflectionType) && + ut.elementSummaries?.length && + !unionReturnHeadings + ) { + return clerkLiteralUnionAsPropertiesTable.call(this, model, optionsWithHeading); + } + } + /** * @type {string[]} */ @@ -507,7 +1626,10 @@ ${tabs} * @param {import('typedoc').ArrayType} model */ arrayType: model => { - const defaultOutput = superPartials.arrayType(model); + const el = model.elementType; + const theType = this.partials.someType(el); + const needsParens = el.type === 'union' || isArrayElementReferenceInliningToUnion(el); + const defaultOutput = needsParens ? `(${theType})[]` : `${theType}[]`; const output = defaultOutput // Remove any backticks @@ -637,3 +1759,99 @@ function swap(arr, i, j) { arr[j] = t; return arr; } + +/** + * @param {import('typedoc').DeclarationReflection} prop + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext['helpers']} helpers + */ +function isCallableInterfaceProperty(prop, helpers) { + // Use the declared value type for properties. `getDeclarationType` mirrors accessor/parameter behavior and can return the wrong node when TypeDoc attaches signatures to the property (same class of bug as TypeAlias + `decl.type`). + const t = + (prop.kind === ReflectionKind.Property || prop.kind === ReflectionKind.Variable) && prop.type + ? prop.type + : helpers.getDeclarationType(prop); + return isCallablePropertyValueType(t, helpers, new Set()); +} + +/** + * True when the property's value type is callable (function type, union/intersection of callables, or reference to a type alias of a function type). Object types with properties (e.g. namespaces) stay false. + * E.g. `navigate: CustomNavigation` in clerk.ts + * + * @param {import('typedoc').Type | undefined} t + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext['helpers']} helpers + * @param {Set} seenReflectionIds + * @returns {boolean} + */ +function isCallablePropertyValueType(t, helpers, seenReflectionIds) { + if (!t) { + return false; + } + if (t.type === 'optional' && 'elementType' in t) { + return isCallablePropertyValueType( + /** @type {{ elementType: import('typedoc').Type }} */ (t).elementType, + helpers, + seenReflectionIds, + ); + } + if (t instanceof UnionType) { + const nonNullish = t.types.filter( + u => !(u.type === 'intrinsic' && ['undefined', 'null'].includes(/** @type {{ name: string }} */ (u).name)), + ); + if (nonNullish.length === 0) { + return false; + } + return nonNullish.every(u => isCallablePropertyValueType(u, helpers, seenReflectionIds)); + } + if (t instanceof IntersectionType) { + return t.types.some(u => isCallablePropertyValueType(u, helpers, seenReflectionIds)); + } + if (t instanceof ReflectionType) { + const decl = t.declaration; + const callSigs = decl.signatures?.length ?? 0; + const hasProps = (decl.children?.length ?? 0) > 0; + const hasIndex = (decl.indexSignatures?.length ?? 0) > 0; + return callSigs > 0 && !hasProps && !hasIndex; + } + if (t instanceof ReferenceType) { + /** + * Unresolved reference (`reflection` missing): TypeDoc did not link the symbol (not in entry graph, external, filtered, etc.). We cannot tell a function alias from an interface, so we only treat a few **name** patterns as callable (`*Function`, `*Listener`). For anything else, ensure the type is part of the documented program so `reflection` resolves and the structural checks above apply — do not add one-off type names here. + * E.g. `CustomNavigation`, `RouterFn`, etc. + */ + if (!t.reflection && typeof t.name === 'string' && /(?:Function|Listener)$/.test(t.name)) { + return true; + } + const ref = t.reflection; + if (!ref) { + return false; + } + const refId = ref.id; + if (refId != null && seenReflectionIds.has(refId)) { + return false; + } + if (refId != null) { + seenReflectionIds.add(refId); + } + try { + const decl = /** @type {import('typedoc').DeclarationReflection} */ (ref); + /** + * For `type Fn = (a: T) => U`, TypeDoc may attach call signatures to the TypeAlias reflection. `getDeclarationType` then returns `signatures[0].type` (here `U`), not the full function type, so we mis-classify properties typed as that alias (e.g. `navigate: CustomNavigation`) as non-callable. + * Prefer `decl.type` (the full RHS) for type aliases. + */ + const typeToCheck = + decl.kind === ReflectionKind.TypeAlias && decl.type + ? decl.type + : (helpers.getDeclarationType(decl) ?? decl.type); + if (typeToCheck) { + return isCallablePropertyValueType(typeToCheck, helpers, seenReflectionIds); + } + } finally { + if (refId != null) { + seenReflectionIds.delete(refId); + } + } + return false; + } + return false; +} + +export { isCallableInterfaceProperty }; diff --git a/.typedoc/extract-methods.mjs b/.typedoc/extract-methods.mjs new file mode 100644 index 00000000000..138a388fa9d --- /dev/null +++ b/.typedoc/extract-methods.mjs @@ -0,0 +1,1283 @@ +// @ts-check +/** + * TypeDoc plugin that runs during the markdown render pass. For each reference-object page listed in {@link REFERENCE_OBJECT_CONFIG} (e.g. `shared/clerk/clerk.mdx`), this listener: + * + * - copies the body of the page's `## Properties` section (table only, no heading) into a sibling `properties.mdx`, + * - mutates `output.contents` to drop the `## Properties` section from the main page, + * - writes one `methods/.mdx` per callable child on the reflection (and on any `extraMethodInterfaces`), alongside the main page in that resource folder. + * + * Must load **after** `custom-plugin.mjs` so its `MarkdownPageEvent.END` listener — which applies link replacements to `output.contents` — runs first. The Properties body we copy out is then already in its final, replaced form. + * + * Like `extract-returns-and-params.mjs`, parameter tables are not hand-built: they use the same `MarkdownThemeContext.partials` as TypeDoc markdown output (`parametersTable`/`propertiesTable`, which call `someType` and therefore pick up `custom-theme.mjs` union `<code>` behavior). The theme context comes from `theme.getRenderContext(output)` on the live page event — no second TypeDoc convert pass. + * + * Inline object namespaces tagged **`@extractMethods`** on the parent property are omitted from the main Properties table (see `custom-theme.mjs`). For each direct member: callables become `methods/-.mdx` via `buildMethodMdx`; non-callables become a heading + property table via `buildPropertyTableDocMdx`. + */ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { + Comment, + IntersectionType, + OptionalType, + ReferenceType, + ReflectionKind, + ReflectionType, + UnionType, +} from 'typedoc'; +import { MarkdownPageEvent } from 'typedoc-plugin-markdown'; + +import { applyTodoStrippingToComment } from './comment-utils.mjs'; +import { + applyCatchAllMdReplacements, + applyRelativeLinkReplacements, + stripReferenceObjectPropertiesSection, +} from './custom-plugin.mjs'; +import { isCallableInterfaceProperty } from './custom-theme.mjs'; +import { removeLineBreaks } from './markdown-helpers.mjs'; +import { REFERENCE_OBJECT_CONFIG } from './reference-objects.mjs'; +import { toFileSlug } from './slug.mjs'; +import { isInlineModifierWithoutStandalonePage } from './standalone-page-tag.mjs'; +import { unwrapOptional } from './type-utils.mjs'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** + * @param {number} level + * @param {string} text + */ +function markdownHeading(level, text) { + const l = Math.min(Math.max(level, 1), 6); + return `${'#'.repeat(l)} ${text}`; +} + +/** + * Heading whose visible title is a type/identifier (nominal single-parameter object sections) needs to get wrapped in backticks. + * + * @param {number} level + * @param {string} text + */ +function markdownHeadingInlineCode(level, text) { + const l = Math.min(Math.max(level, 1), 6); + const t = text.trim(); + return `${'#'.repeat(l)} \`${t}\``; +} + +/** + * Same as typedoc-plugin-markdown `removeLineBreaks` for table cells. + * + * @param {string | undefined} str + */ +function removeLineBreaksForTableCell(str) { + return str?.replace(/\r?\n/g, ' ').replace(/ {2,}/g, ' '); +} + +/** + * TypeDoc `code` display parts often already include backticks (same as {@link Comment.combineDisplayParts}). + * Wrapping again would produce `` `Client` `` in MDX. + * + * @param {string} text + */ +function codeDisplayPartToMarkdown(text) { + const trimmed = text.trim(); + if (trimmed.length >= 2 && trimmed.startsWith('`') && trimmed.endsWith('`')) { + return trimmed; + } + return `\`${text}\``; +} + +/** + * @param {import('typedoc').CommentDisplayPart[] | undefined} parts + */ +function displayPartsToString(parts) { + if (!parts?.length) { + return ''; + } + return parts + .map(p => { + if (p.kind === 'text') { + return p.text; + } + if (p.kind === 'code') { + return codeDisplayPartToMarkdown(p.text); + } + if (p.kind === 'inline-tag') { + return p.text; + } + if (p.kind === 'relative-link') { + return p.text; + } + return ''; + }) + .join(''); +} + +/** + * @param {import('typedoc').ProjectReflection} project + * @param {string} name + * @param {string} [sourcePathHint] e.g. `types/clerk` + */ +function findInterfaceOrClass(project, name, sourcePathHint) { + /** @type {import('typedoc').DeclarationReflection[]} */ + const candidates = []; + for (const r of Object.values(project.reflections)) { + if (r.name !== name) { + continue; + } + if (!r.kindOf(ReflectionKind.Interface) && !r.kindOf(ReflectionKind.Class)) { + continue; + } + candidates.push(/** @type {import('typedoc').DeclarationReflection} */ (r)); + } + if (candidates.length === 0) { + return undefined; + } + if (candidates.length === 1) { + return candidates[0]; + } + if (sourcePathHint) { + const hit = candidates.find(c => c.sources?.some(s => s.fileName.replace(/\\/g, '/').includes(sourcePathHint))); + if (hit) { + return hit; + } + } + return candidates[0]; +} + +/** + * Walk instantiated generic / alias chains (e.g. `CheckAuthorization` → `CheckAuthorizationFn` → `(…) => boolean`) until we find a {@link ReflectionType} call signature. Uses reflection IDs to avoid infinite loops. + * + * @param {import('typedoc').Type | undefined} t + * @param {Set} visitedReflectionIds + * @returns {import('typedoc').SignatureReflection | undefined} + */ +function getCallSignatureFromType(t, visitedReflectionIds) { + if (!t || typeof t !== 'object') { + return undefined; + } + const tag = /** @type {{ type?: string }} */ (t).type; + if (tag === 'optional' && 'elementType' in t) { + return getCallSignatureFromType( + /** @type {{ elementType: import('typedoc').Type }} */ (t).elementType, + visitedReflectionIds, + ); + } + if (t instanceof ReflectionType) { + if (t.declaration?.signatures?.length) { + return t.declaration.signatures[0]; + } + return undefined; + } + if (t instanceof ReferenceType) { + const target = t.reflection; + if ( + target && + 'signatures' in target && + /** @type {{ signatures?: import('typedoc').SignatureReflection[] }} */ (target).signatures?.length + ) { + return /** @type {import('typedoc').DeclarationReflection} */ (target).signatures[0]; + } + if (!target || !('kind' in target)) { + return undefined; + } + const decl = /** @type {import('typedoc').DeclarationReflection} */ (target); + const id = decl.id; + if (id != null) { + if (visitedReflectionIds.has(id)) { + return undefined; + } + visitedReflectionIds.add(id); + } + try { + if (decl.kind === ReflectionKind.TypeAlias && decl.type) { + return getCallSignatureFromType(decl.type, visitedReflectionIds); + } + } finally { + if (id != null) { + visitedReflectionIds.delete(id); + } + } + return undefined; + } + if (t instanceof UnionType) { + for (const arm of t.types) { + const sig = getCallSignatureFromType(arm, visitedReflectionIds); + if (sig) { + return sig; + } + } + return undefined; + } + if (t instanceof IntersectionType) { + for (const arm of t.types) { + const sig = getCallSignatureFromType(arm, visitedReflectionIds); + if (sig) { + return sig; + } + } + } + return undefined; +} + +/** + * @param {import('typedoc').DeclarationReflection} decl + * @returns {import('typedoc').SignatureReflection | undefined} + */ +function getPrimaryCallSignature(decl) { + if (decl.signatures?.length) { + return decl.signatures[0]; + } + const t = decl.type; + if (t && 'declaration' in t && t.declaration?.signatures?.length) { + return t.declaration.signatures[0]; + } + // E.g. `navigate: CustomNavigation` — for `type Fn = () => void`, signatures often live on the inner `declaration` of `alias.type` (ReflectionType), not on `alias.signatures` (see `custom-theme.mjs` `isCallablePropertyValueType`). + if (t && typeof t === 'object' && 'type' in t && /** @type {{ type?: string }} */ (t).type === 'reference') { + const ref = /** @type {import('typedoc').ReferenceType} */ (t); + const target = ref.reflection; + const sigs = + target && 'signatures' in target + ? /** @type {{ signatures?: import('typedoc').SignatureReflection[] }} */ (target).signatures + : undefined; + if (sigs?.length) { + return sigs[0]; + } + const aliasTarget = /** @type {import('typedoc').DeclarationReflection | undefined} */ ( + target && 'kind' in target ? target : undefined + ); + if (aliasTarget?.kind === ReflectionKind.TypeAlias && aliasTarget.type && 'declaration' in aliasTarget.type) { + const inner = /** @type {import('typedoc').ReflectionType} */ (aliasTarget.type).declaration; + if (inner?.signatures?.length) { + return inner.signatures[0]; + } + } + // `type X = SomeFn` — RHS is often ReferenceType (generic alias), not ReflectionType; recurse (e.g. `checkAuthorization: CheckAuthorization`). + if (aliasTarget?.kind === ReflectionKind.TypeAlias && aliasTarget.type) { + const fromRhs = getCallSignatureFromType(aliasTarget.type, new Set()); + if (fromRhs) { + return fromRhs; + } + } + const fromRef = getCallSignatureFromType(ref, new Set()); + if (fromRef) { + return fromRef; + } + } + return undefined; +} + +/** + * For `prop: OuterAlias` where `type OuterAlias = SomeFn`, maps generic parameter names on `SomeFn` to the instantiated type arguments (e.g. `Params` → `CheckAuthorizationParams`). + * + * @param {import('typedoc').DeclarationReflection} propertyDecl + * @returns {Map | undefined} + */ +function getGenericInstantiationMapFromCallableProperty(propertyDecl) { + const t = unwrapOptional(propertyDecl.type); + if (!(t instanceof ReferenceType) || !t.reflection) { + return undefined; + } + const alias = /** @type {import('typedoc').DeclarationReflection} */ (t.reflection); + if (!alias.kindOf(ReflectionKind.TypeAlias) || !alias.type) { + return undefined; + } + const inner = unwrapOptional(alias.type); + if (!(inner instanceof ReferenceType) || !inner.typeArguments?.length || !inner.reflection) { + return undefined; + } + const generic = /** @type {import('typedoc').DeclarationReflection} */ (inner.reflection); + const tpls = generic.typeParameters; + if (!tpls?.length) { + return undefined; + } + /** @type {Map} */ + const map = new Map(); + for (let i = 0; i < inner.typeArguments.length; i++) { + const tp = tpls[i]; + const arg = inner.typeArguments[i]; + if (tp?.name && arg) { + map.set(tp.name, arg); + } + } + return map.size ? map : undefined; +} + +/** + * Replace references to generic type parameters with instantiated types from {@link getGenericInstantiationMapFromCallableProperty}. + * + * @param {import('typedoc').Type | undefined} t + * @param {Map | undefined} map + * @returns {import('typedoc').Type | undefined} + */ +function substituteGenericParamRefsInType(t, map) { + if (!t || !map?.size) { + return t; + } + if (/** @type {{ type?: string }} */ (t).type === 'optional' && 'elementType' in t) { + const el = /** @type {{ elementType: import('typedoc').Type }} */ (t).elementType; + const next = substituteGenericParamRefsInType(el, map); + if (next && next !== el) { + return new OptionalType(/** @type {import('typedoc').SomeType} */ (/** @type {unknown} */ (next))); + } + return t; + } + if (t instanceof ReferenceType && map.has(t.name)) { + return map.get(t.name) ?? t; + } + return t; +} + +/** + * @param {import('typedoc').SignatureReflection} sig + * @param {Map | undefined} instantiationMap + */ +function signatureWithInstantiation(sig, instantiationMap) { + if (!instantiationMap?.size) { + return sig; + } + const parameters = (sig.parameters ?? []).map(p => { + const newType = substituteGenericParamRefsInType(p.type, instantiationMap); + if (newType === p.type) { + return p; + } + return Object.assign(Object.create(Object.getPrototypeOf(p)), p, { type: newType }); + }); + const newReturn = substituteGenericParamRefsInType(sig.type, instantiationMap) ?? sig.type; + const out = Object.assign(Object.create(Object.getPrototypeOf(sig)), sig, { + parameters, + type: newReturn, + typeParameters: undefined, + }); + if (sig.project) { + out.project = sig.project; + } + return out; +} + +/** + * Must stay aligned with allowlisted `propertiesTable` filtering in `custom-theme.mjs` (`isCallableInterfaceProperty` and `@extractMethods`: extracted here, not listed as properties). Nested tables pass `applyAllowlistedPropertyTableRowFilters: false`. + * + * @param {import('typedoc').DeclarationReflection} decl + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + */ +function shouldExtractCallableMember(decl, ctx) { + if (decl.kind === ReflectionKind.Method) { + return true; + } + if ( + decl.kind === ReflectionKind.Property || + decl.kind === ReflectionKind.Accessor || + decl.kind === ReflectionKind.Variable + ) { + return isCallableInterfaceProperty(decl, ctx.helpers); + } + return false; +} + +/** + * Object-literal (or single object arm of `T | null`) property rows for a properties table. + * + * @param {import('typedoc').SomeType | undefined} valueType + * @returns {import('typedoc').DeclarationReflection[] | undefined} + */ +function resolveObjectShapeMembersForPropertyTable(valueType) { + let t = unwrapOptional(valueType, { deep: true }); + if (t instanceof UnionType) { + const objectArms = t.types.filter(u => u instanceof ReflectionType && (u.declaration?.children?.length ?? 0) > 0); + if (objectArms.length !== 1) { + return undefined; + } + t = /** @type {import('typedoc').ReflectionType} */ (objectArms[0]); + } + if (!(t instanceof ReflectionType)) { + return undefined; + } + const kids = t.declaration?.children ?? []; + return kids.filter( + c => c.kind === ReflectionKind.Property || c.kind === ReflectionKind.Variable || c.kind === ReflectionKind.Accessor, + ); +} + +/** + * @param {string} parentName + * @param {import('typedoc').DeclarationReflection} nestedDecl + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + */ +function buildPropertyTableDocMdx(parentName, nestedDecl, ctx) { + const qualifiedName = `${parentName}.${nestedDecl.name}`; + const title = `### \`${qualifiedName}\``; + const description = commentSummaryAndBody(nestedDecl.comment); + const propsUnsorted = resolveObjectShapeMembersForPropertyTable(nestedDecl.type); + if (!propsUnsorted?.length) { + return ''; + } + /** Match nominal param tables and merged intersection holders: stable A–Z by property name (TypeDoc inline literal `children` order is declaration order). */ + const props = [...propsUnsorted].sort((a, b) => a.name.localeCompare(b.name)); + const tableMd = renderMemberTableOmittingExampleBlocks(props, ctx, () => + ctx.partials.propertiesTable( + props, + /** @type {Parameters[1]} */ + ({ + kind: ReflectionKind.Interface, + isEventProps: false, + applyAllowlistedPropertyTableRowFilters: false, + }), + ), + ); + const chunks = [title, '', description, '', tableMd].filter(Boolean); + const raw = chunks.join('\n\n'); + return `${applyCatchAllMdReplacements(applyRelativeLinkReplacements(raw)).trim()}\n`; +} + +/** + * Parent-level property table for an `@extractMethods` namespace. + * Lists non-callable direct members on the namespace (e.g. `verifications.emailAddress`, `verifications.phoneNumber`). + * + * @param {import('typedoc').DeclarationReflection} parentDecl + * @param {import('typedoc').DeclarationReflection[]} nonCallableMembers + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + */ +function buildExtractMethodsNamespacePropertyTableMdx(parentDecl, nonCallableMembers, ctx) { + if (!nonCallableMembers.length) { + return ''; + } + const title = `### \`${parentDecl.name}\``; + const description = commentSummaryAndBody(parentDecl.comment); + const props = [...nonCallableMembers].sort((a, b) => a.name.localeCompare(b.name)); + const tableMd = renderMemberTableOmittingExampleBlocks(props, ctx, () => + ctx.partials.propertiesTable( + props, + /** @type {Parameters[1]} */ + ({ + kind: ReflectionKind.Interface, + isEventProps: false, + applyAllowlistedPropertyTableRowFilters: false, + }), + ), + ); + if (!tableMd?.trim()) { + return ''; + } + const raw = [title, '', description, '', tableMd].filter(Boolean).join('\n\n'); + return `${applyCatchAllMdReplacements(applyRelativeLinkReplacements(raw)).trim()}\n`; +} + +/** + * @param {string} markdown + * @returns {string | undefined} Body under `## Properties` (no heading), or undefined + */ +function extractPropertiesSectionBody(markdown) { + const normalized = markdown.replace(/\r\n/g, '\n'); + const m = normalized.match(/(^|\n)## Properties\n+/); + if (!m || m.index === undefined) { + return undefined; + } + const start = m.index + m[0].length; + const rest = normalized.slice(start); + const nextH2 = rest.search(/\n## /); + const section = nextH2 === -1 ? rest : rest.slice(0, nextH2); + const trimmed = section.trim(); + return trimmed.length ? trimmed : undefined; +} + +/** + * Split the `## Properties` section out of page contents, returning the body (no heading) and the page contents with the Properties section removed. + * + * Operates on the in-memory `output.contents` of a `MarkdownPageEvent`; the caller writes `properties.mdx` and assigns the stripped string back to `output.contents`. The page's own END pipeline (link replacements) has already run by the time we get called, so the Properties body is in its final, replaced form — no re-application needed. + * + * @param {string} contents + * @returns {{ propertiesBody: string | undefined, stripped: string }} + */ +function splitPropertiesFromContents(contents) { + if (!contents) { + return { propertiesBody: undefined, stripped: contents }; + } + const propertiesBody = extractPropertiesSectionBody(contents); + const stripped = stripReferenceObjectPropertiesSection(contents); + return { propertiesBody, stripped }; +} + +/** + * Plain TypeScript-like type text for ```typescript``` fences (no markdown / backticks from {@link MarkdownThemeContext.partials.someType}). + * + * @param {import('typedoc').Type | undefined} t + */ +function typeStringForTypeScriptFence(t) { + if (!t) { + return 'unknown'; + } + return removeLineBreaks(t.toString()); +} + +/** + * @param {import('typedoc').SignatureReflection} sig + * @param {string} memberName + * @param {Map | undefined} instantiationMap + */ +function formatTypeScriptSignature(sig, memberName, instantiationMap) { + const hideOuterTypeParams = Boolean(instantiationMap?.size) && (sig.typeParameters?.length ?? 0) > 0; + const typeParamStr = + !hideOuterTypeParams && sig.typeParameters?.length ? `<${sig.typeParameters.map(tp => tp.name).join(', ')}>` : ''; + const params = + sig.parameters?.map(p => { + const opt = p.flags.isOptional ? '?' : ''; + const rest = p.flags.isRest ? '...' : ''; + const t = substituteGenericParamRefsInType(p.type, instantiationMap) ?? p.type; + const typeStr = typeStringForTypeScriptFence(t); + return `${rest}${p.name}${opt}: ${typeStr}`; + }) ?? []; + const retT = substituteGenericParamRefsInType(sig.type, instantiationMap) ?? sig.type; + const ret = retT ? typeStringForTypeScriptFence(retT) : 'void'; + // Qualified names (`emailCode.sendCode`) aren't valid in `function foo.bar()` syntax; use the bare last segment — the parent is already in the heading above. + const displayName = memberName.includes('.') ? memberName.split('.').pop() : memberName; + return `function ${displayName}${typeParamStr}(${params.join(', ')}): ${ret}`; +} + +/** + * `@returns - foo` is often stored with a leading dash, which renders as a bullet. Normalize to prose for "Returns …" lines. + * @param {string} body + */ +function normalizeReturnsBody(body) { + return body.replace(/^\s*[-*]\s+/, '').trim(); +} + +/** + * Lowercase the first character so the line reads "Returns an …" not "Returns An …". + * @param {string} body + */ +function lowercaseFirstCharacter(body) { + if (!body) { + return body; + } + return body.charAt(0).toLowerCase() + body.slice(1); +} + +/** + * @param {import('typedoc').CommentTag} tag + */ +function formatReturnsLineFromTag(tag) { + const raw = Comment.combineDisplayParts(tag.content).trim(); + if (!raw) { + return ''; + } + const body = lowercaseFirstCharacter(normalizeReturnsBody(raw)); + return `Returns ${body}`; +} + +/** + * @param {import('typedoc').Comment | undefined} comment + */ +/** + * `typedoc-plugin-markdown` table partials include `@example` in Description cells. For extract-methods, we want to exclude examples from the generated output. + * + * Uses the same `getFlattenedDeclarations` list as `propertiesTable` so nested property rows omit examples too. + * + * @template T + * @param {import('typedoc').Reflection[]} roots + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {() => T} render + * @returns {T} + */ +function renderMemberTableOmittingExampleBlocks(roots, ctx, render) { + const flatten = + typeof ctx.helpers?.getFlattenedDeclarations === 'function' + ? ctx.helpers.getFlattenedDeclarations( + /** @type {import('typedoc').DeclarationReflection[]} */ (/** @type {unknown} */ (roots)), + ) + : roots; + /** @type {Set} */ + const processedComments = new Set(); + /** @type {{ ref: import('typedoc').Reflection; orig: import('typedoc').Comment }[]} */ + const restore = []; + for (const r of flatten) { + const c = 'comment' in r ? r.comment : undefined; + if (!c?.getTag('@example') || processedComments.has(c)) { + continue; + } + processedComments.add(c); + const next = c.clone(); + next.removeTags('@example'); + for (const ref of flatten) { + if (ref.comment === c) { + ref.comment = next; + restore.push({ ref, orig: c }); + } + } + } + try { + return render(); + } finally { + for (const { ref, orig } of restore) { + ref.comment = orig; + } + } +} + +/** Block tags omitted from extracted method prose (see `custom-theme.mjs` `comment` partial for theme output). */ +const BLOCK_TAGS_OMITTED_FROM_EXTRACTED_METHOD_PROSE = new Set(['@param', '@typeParam', '@returns', '@experimental']); + +/** + * @param {import('typedoc').Comment | undefined} comment + */ +function commentSummaryAndBody(comment) { + if (!comment) { + return ''; + } + const c = applyTodoStrippingToComment(comment) ?? comment; + const summary = displayPartsToString(c.summary).trim(); + const block = c.blockTags + ?.filter(t => !BLOCK_TAGS_OMITTED_FROM_EXTRACTED_METHOD_PROSE.has(t.tag)) + .map(t => displayPartsToString(t.content).trim()) + .filter(Boolean) + .join('\n\n'); + const returnsLines = + c.blockTags + ?.filter(t => t.tag === '@returns') + .map(t => formatReturnsLineFromTag(t)) + .filter(Boolean) ?? []; + return [summary, block, ...returnsLines].filter(Boolean).join('\n\n'); +} + +/** + * When `@returns` exists only on the call signature (not on the declaration), append it to the prose. + * @param {import('typedoc').Comment | undefined} declComment + * @param {import('typedoc').Comment | undefined} sigComment + */ +function appendSignatureOnlyReturns(declComment, sigComment) { + if (declComment?.getTag('@returns')?.content?.length) { + return ''; + } + const tag = sigComment?.getTag('@returns'); + if (!tag?.content?.length) { + return ''; + } + return formatReturnsLineFromTag(tag); +} + +/** + * @param {import('typedoc').DeclarationReflection} prop + */ +function propertyReflectionTypeIsNever(prop) { + const ty = unwrapOptional(prop.type, { deep: true }); + return ty?.type === 'intrinsic' && ty.name === 'never'; +} + +/** + * Union discriminators often use `otherProp?: never`. Prefer the branch with a documentable type. + * + * @param {import('typedoc').DeclarationReflection} existing + * @param {import('typedoc').DeclarationReflection} candidate + */ +function pickBetterUnionPropertyCandidate(existing, candidate) { + const existingNever = propertyReflectionTypeIsNever(existing); + const candidateNever = propertyReflectionTypeIsNever(candidate); + if (existingNever && !candidateNever) { + return candidate; + } + if (!existingNever && candidateNever) { + return existing; + } + const existingDoc = existing.comment?.summary?.length ?? 0; + const candidateDoc = candidate.comment?.summary?.length ?? 0; + return candidateDoc > existingDoc ? candidate : existing; +} + +/** + * Filter each arm to `Property` reflections and dedupe by name, returning a single sorted list + * (or `undefined` if every arm was empty). Used for intersection / union / generic-instantiation + * arm merges in {@link resolveDeclarationWithObjectMembers}. + * + * Default behavior is "later arm wins" overwrite (right for intersections + generic instantiations + * where every arm's properties are part of the final shape). For unions, set + * `{ skipNever: true, pickBetter: true }`: union arms often use `prop?: never` as a discriminator, + * so we drop those and keep the documentable branch when names collide. + * + * @param {Array} arms + * @param {{ skipNever?: boolean, pickBetter?: boolean }} [options] + * @returns {import('typedoc').DeclarationReflection[] | undefined} + */ +function mergePropertyArms(arms, options) { + /** @type {Map} */ + const byName = new Map(); + for (const arm of arms) { + if (!arm?.length) { + continue; + } + for (const c of arm) { + if (!c.kindOf(ReflectionKind.Property)) { + continue; + } + if (options?.skipNever && propertyReflectionTypeIsNever(c)) { + continue; + } + const existing = byName.get(c.name); + if (!existing) { + byName.set(c.name, c); + continue; + } + byName.set(c.name, options?.pickBetter ? pickBetterUnionPropertyCandidate(existing, c) : c); + } + } + if (byName.size === 0) { + return undefined; + } + return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)); +} + +/** + * Resolve a parameter / property type to the list of `Property` reflections that should populate + * a nested rows table. TypeDoc applies `@param parent.prop` descriptions onto these reflections. + * + * Cases: + * - `reflection` (inline `{...}`): the declaration's own children. + * - `reference` to a named interface/alias: the target's children, or — for generic instantiations + * like `ClerkPaginationParams<{ status?: … }>` — the base properties merged with each typeArg's. + * - `intersection`: every `&` arm's properties combined (later arm wins on name collision). + * - `union`: every `|` arm's properties combined, dropping `prop?: never` discriminators and + * preferring the branch with more documentation on collisions. + * - `optional`: unwrap and recurse. + * + * Returns `undefined` when nothing resolves (so callers can `if (!children?.length)` cheaply). + * The children list may include non-`Property` kinds for direct `reflection` / `reference` cases — + * callers that need only `Property` should filter; merge cases (typeArgs / intersection / union) + * pre-filter via {@link mergePropertyArms}. + * + * @param {import('typedoc').SomeType | undefined} t + * @param {import('typedoc').ProjectReflection | undefined} [project] For resolving references when `ref.reflection` is missing (intersections like `Foo & WithOptionalOrgType<…>`). + * @returns {import('typedoc').DeclarationReflection[] | undefined} + */ +function resolveDeclarationWithObjectMembers(t, project) { + if (!t) { + return undefined; + } + if (t.type === 'optional') { + return resolveDeclarationWithObjectMembers(/** @type {import('typedoc').OptionalType} */ (t).elementType, project); + } + if (t.type === 'reflection') { + const children = t.declaration?.children; + return children?.length ? children : undefined; + } + if (t.type === 'reference') { + const ref = /** @type {import('typedoc').ReferenceType} */ (t); + let decl = + ref.reflection && 'kind' in ref.reflection + ? /** @type {import('typedoc').DeclarationReflection} */ (ref.reflection) + : undefined; + if (!decl && project && ref.name) { + decl = lookupInterfaceOrTypeAliasByName(project, ref.name); + } + if (!decl) { + return undefined; + } + /** + * Generic instantiation: TypeDoc often attaches pagination fields only to the target alias's + * own `children` and omits `decl.type`, so returning the base early drops the type argument + * object. Merge the base (`decl.type` if present, else `decl.children` as a fallback) with + * each type argument's properties. + */ + const typeArgs = ref.typeArguments ?? []; + if (typeArgs.length > 0) { + const baseFromType = decl.type ? resolveDeclarationWithObjectMembers(decl.type, project) : undefined; + const base = baseFromType ?? (decl.children?.length ? decl.children : undefined); + const argArms = typeArgs.map(ta => resolveDeclarationWithObjectMembers(ta, project)); + return mergePropertyArms([base, ...argArms]); + } + if (decl.children?.length) { + return decl.children; + } + if (decl.type) { + return resolveDeclarationWithObjectMembers(decl.type, project); + } + return undefined; + } + if (t.type === 'intersection') { + const inter = /** @type {import('typedoc').IntersectionType} */ (t); + return mergePropertyArms(inter.types.map(inner => resolveDeclarationWithObjectMembers(inner, project))); + } + if (t.type === 'union') { + const u = /** @type {import('typedoc').UnionType} */ (t); + return mergePropertyArms( + u.types.map(inner => resolveDeclarationWithObjectMembers(inner, project)), + { skipNever: true, pickBetter: true }, + ); + } + return undefined; +} + +/** + * Build the name cell for a nominal-nested row. Uses `?.` when the parent param is optional (so `options?.foo` mirrors how it would be accessed at runtime) and `.` when required — same rule as `clerkParametersTable.flattenParams` in `custom-theme.mjs`. + * + * @param {import('typedoc').ParameterReflection} parentParam + * @param {string} childName + */ +function formatNestedParamNameColumn(parentParam, childName) { + const sep = parentParam.flags?.isOptional ? '?.' : '.'; + return `\`${parentParam.name}${sep}${childName}\``; +} + +/** + * When TypeDoc renders a parameter type as a markdown link to another generated `.mdx` file, that type has a dedicated page — omit nested `param?.prop` rows so readers follow the type link instead. + * `@inline` aliases are expanded by the theme and do not link to a standalone page unless `@standalonePage` is set (`standalone-page-tag.mjs`). + * + * @param {import('typedoc').SomeType | undefined} t + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + */ +function parameterTypeLinksToStandaloneMdxPage(t, ctx) { + const bare = unwrapOptional(t); + if (!bare) { + return false; + } + if (bare.type === 'reference') { + const ref = /** @type {import('typedoc').ReferenceType} */ (bare); + if (isInlineModifierWithoutStandalonePage(ref.reflection)) { + return false; + } + } + const md = removeLineBreaksForTableCell(ctx.partials.someType(bare) ?? '') ?? ''; + return /\.mdx(?:#[^)]*)?\)/.test(md); +} + +/** + * Rows for object properties on a nominal param type (e.g. `HandleOAuthCallbackParams`), including from `@param parent.prop` on the method. + * Lists every property on the resolved shape; uses the property comment when present, otherwise `—` (intersection aliases often omit comments on some arms in the model). + * + * @param {import('typedoc').ParameterReflection} param + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + */ +function nestedParameterRowsFromDocumentedProperties(param, ctx) { + // `parametersTable` already flattens inline `{ ... }` params (see typedoc-plugin-markdown `parseParams`). + // Adding rows here would duplicate those (e.g. `options.skipInitialEmit` twice on `addListener`). + if (param.type?.type === 'reflection') { + const d = /** @type {import('typedoc').DeclarationReflection} */ (param.type.declaration); + if (d?.kind === ReflectionKind.TypeLiteral && d.children?.length) { + return []; + } + } + + if (parameterTypeLinksToStandaloneMdxPage(param.type, ctx)) { + return []; + } + + const project = /** @type {import('typedoc').ProjectReflection | undefined} */ (param.project ?? ctx.page?.project); + const children = resolveDeclarationWithObjectMembers(param.type, project); + if (!children?.length) { + return []; + } + const props = children.filter(c => c.kindOf(ReflectionKind.Property)); + props.sort((a, b) => a.name.localeCompare(b.name)); + /** @type {string[]} */ + const rows = []; + for (const child of props) { + const summary = child.comment?.summary; + const typeCell = child.type ? removeLineBreaksForTableCell(ctx.partials.someType(child.type)) : '`unknown`'; + const nestedNameCol = formatNestedParamNameColumn(param, child.name); + const nestedDesc = summary?.length ? displayPartsToString(summary).trim() || '—' : '—'; + rows.push(`| ${nestedNameCol} | ${typeCell} | ${nestedDesc} |`); + } + return rows; +} + +/** + * Merged / external references sometimes leave {@link ReferenceType.reflection} unset; resolve by name. + * + * @param {import('typedoc').ProjectReflection} project + * @param {string} name + * @returns {import('typedoc').DeclarationReflection | undefined} + */ +function lookupInterfaceOrTypeAliasByName(project, name) { + /** @type {import('typedoc').DeclarationReflection[]} */ + const cands = []; + for (const r of Object.values(project.reflections)) { + if (r.name !== name) { + continue; + } + if (!r.kindOf(ReflectionKind.Interface) && !r.kindOf(ReflectionKind.TypeAlias)) { + continue; + } + cands.push(/** @type {import('typedoc').DeclarationReflection} */ (r)); + } + if (cands.length === 0) { + return undefined; + } + if (cands.length === 1) { + return cands[0]; + } + const withChildren = cands.find(c => c.children?.length); + return withChildren ?? cands[0]; +} + +/** + * Unwrap optional wrappers. When the parameter is a single named interface or type alias for an + * object shape, returns the section title (the type's name), the resolved property list, and the + * source `typeDecl` for `@experimental` / `@deprecated` checks. + * + * @param {import('typedoc').SomeType | undefined} t + * @param {import('typedoc').ProjectReflection} project + * @returns {{ sectionTitle: string, children: import('typedoc').DeclarationReflection[], typeDecl: import('typedoc').DeclarationReflection } | undefined} + */ +function resolveNominalObjectTypeForSingleParam(t, project) { + if (!t) { + return undefined; + } + if (t.type === 'optional') { + return resolveNominalObjectTypeForSingleParam( + /** @type {import('typedoc').OptionalType} */ (t).elementType, + project, + ); + } + if (t.type !== 'reference') { + return undefined; + } + const ref = /** @type {import('typedoc').ReferenceType} */ (t); + const typeDecl = + ref.reflection && 'kind' in ref.reflection + ? /** @type {import('typedoc').DeclarationReflection} */ (ref.reflection) + : lookupInterfaceOrTypeAliasByName(project, ref.name); + if (!typeDecl) { + return undefined; + } + if (typeDecl.kindOf(ReflectionKind.Interface)) { + if (!typeDecl.children?.length) { + return undefined; + } + return { sectionTitle: typeDecl.name, children: typeDecl.children, typeDecl }; + } + if (typeDecl.kindOf(ReflectionKind.TypeAlias)) { + // Prefer resolving `typeAlias.type` so intersections and generic instantiations (e.g. `ClerkPaginationParams<{ status?: … }>`) merge every `&` arm into one property list. + // Some aliases only attach members on `typeDecl.children` with no object shape on `.type`; keep that fallback (e.g. `SignOutOptions`, `JoinWaitlistParams`). + const fromResolvedType = typeDecl.type ? resolveDeclarationWithObjectMembers(typeDecl.type, project) : undefined; + const children = fromResolvedType?.length ? fromResolvedType : typeDecl.children; + if (!children?.length) { + return undefined; + } + return { sectionTitle: typeDecl.name, children, typeDecl }; + } + return undefined; +} + +/** + * Nominal param sections are skipped when there is no prose anywhere — avoids huge undocumented tables. + * Type-only aliases often use `@experimental` / `@deprecated` on the type with an empty summary; intersection params like `GetPaymentAttemptParams` still have documented arms (`id`, pagination) and must inline. + * + * @param {import('typedoc').DeclarationReflection} typeDecl + * @param {import('typedoc').DeclarationReflection[]} props + */ +function isNominalParamTypeDocumented(typeDecl, props) { + if (typeDecl.comment?.summary?.length) { + return true; + } + const blockTags = typeDecl.comment?.blockTags ?? []; + if (blockTags.some(t => t.tag !== '@inline')) { + return true; + } + return props.some(p => p.comment?.summary?.length); +} + +/** + * Single parameter that is a named object type (interface / type alias): one section titled after the type, table lists every property (not the outer `params` row). Uses the same `propertiesTable` partial as TypeDoc. + * + * @param {import('typedoc').SignatureReflection} sig + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @returns {string | undefined} + */ +function trySingleNominalParameterTypeSection(sig, ctx) { + const params = sig.parameters ?? []; + if (params.length !== 1) { + return undefined; + } + const p = params[0]; + const project = sig.project ?? ctx.page?.project; + const nominal = resolveNominalObjectTypeForSingleParam(p.type, project); + if (!nominal) { + return undefined; + } + const props = nominal.children.filter(c => c.kindOf(ReflectionKind.Property)); + if (props.length === 0) { + return undefined; + } + if (!isNominalParamTypeDocumented(nominal.typeDecl, props)) { + return undefined; + } + const tableMd = renderMemberTableOmittingExampleBlocks(props, ctx, () => + ctx.partials.propertiesTable( + props, + /** @type {Parameters[1]} */ + ({ + kind: nominal.typeDecl.kind, + isEventProps: false, + applyAllowlistedPropertyTableRowFilters: false, + }), + ), + ); + if (!tableMd?.trim()) { + return undefined; + } + return [markdownHeadingInlineCode(4, nominal.sectionTitle), '', tableMd, ''].join('\n'); +} + +/** + * @param {import('typedoc').SignatureReflection} sig + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {Map | undefined} instantiationMap + */ +function parametersMarkdownTable(sig, ctx, instantiationMap) { + const sigForDisplay = signatureWithInstantiation(sig, instantiationMap); + const params = sigForDisplay.parameters ?? []; + if (params.length === 0) { + return ''; + } + + const singleNominal = trySingleNominalParameterTypeSection(sigForDisplay, ctx); + if (singleNominal) { + return singleNominal; + } + + let tableMd = renderMemberTableOmittingExampleBlocks(params, ctx, () => ctx.partials.parametersTable(params)); + /** @type {string[]} */ + const nested = []; + for (const p of params) { + nested.push(...nestedParameterRowsFromDocumentedProperties(p, ctx)); + } + if (nested.length) { + tableMd = `${tableMd.trimEnd()}\n${nested.join('\n')}\n`; + } + + return [markdownHeading(4, ReflectionKind.pluralString(ReflectionKind.Parameter)), '', tableMd, ''].join('\n'); +} + +/** + * @param {import('typedoc').DeclarationReflection} decl + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {{ qualifiedName?: string }} [options] Nested namespace methods use `parent.child` for headings / signatures. + */ +function buildMethodMdx(decl, ctx, options = {}) { + const name = options.qualifiedName ?? decl.name; + const sig = getPrimaryCallSignature(decl); + if (!sig) { + return ''; + } + const title = `### \`${name}()\``; + /** Prefer the declaration comment (property-style methods document `addListener` on the property, not the signature). */ + const comment = decl.comment ?? sig.comment; + let description = commentSummaryAndBody(comment); + const sigReturns = comment === sig.comment ? '' : appendSignatureOnlyReturns(decl.comment, sig.comment); + if (sigReturns) { + description = [description, sigReturns].filter(Boolean).join('\n\n'); + } + const instantiationMap = getGenericInstantiationMapFromCallableProperty(decl); + const ts = ['```typescript', formatTypeScriptSignature(sig, name, instantiationMap), '```'].join('\n'); + const skipParametersSection = + Boolean(decl.comment?.hasModifier('@skipParametersSection')) || + Boolean(sig.comment?.hasModifier('@skipParametersSection')); + const paramsMd = skipParametersSection ? '' : parametersMarkdownTable(sig, ctx, instantiationMap); + + // Same post-process as `custom-plugin.mjs` `MarkdownPageEvent.END`: relative `.mdx` links, then catch-alls. + // Skip the ```typescript``` fence so signatures stay plain code. + const head = applyCatchAllMdReplacements(applyRelativeLinkReplacements([title, '', description].join('\n'))); + const paramsProcessed = paramsMd ? applyCatchAllMdReplacements(applyRelativeLinkReplacements(paramsMd)) : ''; + const chunks = [head, ts]; + if (paramsProcessed) { + chunks.push(paramsProcessed); + } + return chunks.join('\n\n').trim() + '\n'; +} + +/** + * @param {import('typedoc').DeclarationReflection} decl + */ +function hasExtractMethodsModifier(decl) { + return Boolean(decl.comment?.hasModifier('@extractMethods')); +} + +/** + * @typedef {{ filePath: string, content: string }} ExtractedFile + */ + +/** + * Collect `methods/-.mdx` content for each direct member of an `@extractMethods` object-like type: callables via {@link buildMethodMdx}, non-callables with a resolvable object shape via {@link buildPropertyTableDocMdx}. Plus a `.mdx` index for non-callable members. + * + * Supports inline object literals and named references (`interface` / object-like `type` aliases) via {@link resolveDeclarationWithObjectMembers}. + * + * @param {import('typedoc').DeclarationReflection} parentDecl + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {string} outDir + * @returns {ExtractedFile[]} + */ +function processExtractMethodsNamespace(parentDecl, ctx, outDir) { + const project = ctx.page?.project; + const members = resolveDeclarationWithObjectMembers(parentDecl.type, project) ?? []; + if (members.length === 0) { + console.warn( + `[extract-methods] @extractMethods on "${parentDecl.name}" requires an object-like type with members; skipping nested extraction`, + ); + return []; + } + const parentName = parentDecl.name; + /** @type {ExtractedFile[]} */ + const collected = []; + /** @type {import('typedoc').DeclarationReflection[]} */ + const nonCallableMembers = []; + for (const nested of members) { + if (nested.name.startsWith('__')) { + continue; + } + const nd = /** @type {import('typedoc').DeclarationReflection} */ (nested); + const fileSlug = `${toFileSlug(parentName)}-${toFileSlug(nd.name)}`; + const filePath = path.join(outDir, `${fileSlug}.mdx`); + if (shouldExtractCallableMember(nd, ctx)) { + const mdx = buildMethodMdx(nd, ctx, { qualifiedName: `${parentName}.${nd.name}` }); + if (!mdx) { + continue; + } + collected.push({ filePath, content: mdx }); + continue; + } + nonCallableMembers.push(nd); + const propTableMdx = buildPropertyTableDocMdx(parentName, nd, ctx); + if (!propTableMdx) { + continue; + } + collected.push({ filePath, content: propTableMdx }); + } + if (nonCallableMembers.length) { + const namespaceMdx = buildExtractMethodsNamespacePropertyTableMdx(parentDecl, nonCallableMembers, ctx); + if (namespaceMdx) { + const namespacePath = path.join(outDir, `${toFileSlug(parentName)}.mdx`); + collected.push({ filePath: namespacePath, content: namespaceMdx }); + } + } + return collected; +} + +/** + * Collect (path, content) pairs for each callable/`@extractMethods` child on `decl`. Callers are responsible for writing — see {@link load} which prettifies then writes. + * + * @param {import('typedoc').DeclarationReflection} decl + * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx + * @param {string} outDir + * @returns {ExtractedFile[]} + */ +function extractCallableMembersFromDeclaration(decl, ctx, outDir) { + if (!decl.children) { + return []; + } + /** @type {ExtractedFile[]} */ + const collected = []; + for (const child of decl.children) { + if (child.name.startsWith('__')) { + continue; + } + const childDecl = /** @type {import('typedoc').DeclarationReflection} */ (child); + + if (hasExtractMethodsModifier(childDecl)) { + collected.push(...processExtractMethodsNamespace(childDecl, ctx, outDir)); + continue; + } + + if (shouldExtractCallableMember(childDecl, ctx)) { + const mdx = buildMethodMdx(childDecl, ctx); + if (mdx) { + const fileName = `${toFileSlug(child.name)}.mdx`; + const filePath = path.join(outDir, fileName); + collected.push({ filePath, content: mdx }); + } + } + } + return collected; +} + +/** + * @param {import('typedoc-plugin-markdown').MarkdownPageEvent} output + * @returns {keyof typeof REFERENCE_OBJECT_CONFIG | undefined} + */ +function matchReferenceObjectPageUrl(output) { + if (!output.url) { + return undefined; + } + const normalized = output.url.replace(/\\/g, '/'); + return normalized in REFERENCE_OBJECT_CONFIG + ? /** @type {keyof typeof REFERENCE_OBJECT_CONFIG} */ (normalized) + : undefined; +} + +/** + * Plugin entry: registers a `MarkdownPageEvent.END` listener that, for each page in {@link REFERENCE_OBJECT_CONFIG}, queues a `preWriteAsyncJob` to extract Properties + methods. + * + * The job runs **after** typedoc-plugin-markdown's own prettier job (also a `preWriteAsyncJob`, queued during `renderDocument`) — so by the time we read `output.contents`, the Properties table is already prettier-formatted, and our `properties.mdx` inherits that formatting. Method files are written raw (matching the pre-refactor behavior, where extract-methods.mjs also bypassed prettier for `methods/*.mdx`). + * + * Must be loaded **after** `custom-plugin.mjs` so its END listener (link replacements + heading filtering) runs first. + * + * @param {import('typedoc-plugin-markdown').MarkdownApplication} app + */ +export function load(app) { + app.renderer.on(MarkdownPageEvent.END, output => { + const pageUrl = matchReferenceObjectPageUrl(output); + if (!pageUrl) { + return; + } + const entry = REFERENCE_OBJECT_CONFIG[pageUrl]; + const decl = /** @type {import('typedoc').DeclarationReflection | undefined} */ (output.model); + if (!decl?.children) { + console.warn(`[extract-methods] No children on reflection for ${pageUrl}, skipping`); + return; + } + const project = output.project; + if (!project) { + console.warn(`[extract-methods] No project on page event for ${pageUrl}, skipping`); + return; + } + const theme = /** @type {InstanceType | undefined} */ ( + app.renderer.theme + ); + if (!theme || typeof theme.getRenderContext !== 'function') { + console.warn(`[extract-methods] Renderer theme not ready for ${pageUrl}, skipping`); + return; + } + const ctx = /** @type {import('typedoc-plugin-markdown').MarkdownThemeContext} */ (theme.getRenderContext(output)); + + const objectDir = path.dirname(output.filename); + const outDir = path.join(objectDir, 'methods'); + + /** @type {ExtractedFile[]} */ + const methodFiles = extractCallableMembersFromDeclaration(decl, ctx, outDir); + const extraMethodInterfaces = 'extraMethodInterfaces' in entry ? entry.extraMethodInterfaces : undefined; + if (Array.isArray(extraMethodInterfaces)) { + for (const extra of extraMethodInterfaces) { + const extraDecl = findInterfaceOrClass(project, extra.symbol, extra.declarationHint); + if (!extraDecl?.children) { + console.warn(`[extract-methods] extraMethodInterfaces: could not find "${extra.symbol}" for ${pageUrl}`); + continue; + } + methodFiles.push(...extractCallableMembersFromDeclaration(extraDecl, ctx, outDir)); + } + } + + output.preWriteAsyncJobs.push(() => { + fs.mkdirSync(objectDir, { recursive: true }); + + // `output.contents` is already prettier-formatted by typedoc-plugin-markdown's earlier + // pre-write job. Extract the Properties body from it (also formatted), write it out, + // then strip the section so the main page no longer ships it. + const { propertiesBody, stripped } = splitPropertiesFromContents(output.contents ?? ''); + if (propertiesBody) { + const propertiesPath = path.join(objectDir, 'properties.mdx'); + fs.writeFileSync(propertiesPath, `${propertiesBody.trimEnd()}\n`, 'utf-8'); + console.log(`[extract-methods] Wrote ${path.relative(path.join(__dirname, '..'), propertiesPath)}`); + } + if (stripped && stripped !== output.contents) { + output.contents = stripped; + } + + if (methodFiles.length === 0) { + return; + } + fs.mkdirSync(outDir, { recursive: true }); + for (const { filePath, content } of methodFiles) { + fs.writeFileSync(filePath, content, 'utf-8'); + console.log(`[extract-methods] Wrote ${path.relative(path.join(__dirname, '..'), filePath)}`); + } + console.log(`[extract-methods] ${pageUrl}: wrote ${methodFiles.length} method file(s)`); + }); + }); +} diff --git a/.typedoc/markdown-helpers.mjs b/.typedoc/markdown-helpers.mjs new file mode 100644 index 00000000000..9924671bf4b --- /dev/null +++ b/.typedoc/markdown-helpers.mjs @@ -0,0 +1,117 @@ +// @ts-check — JSDoc-typed plugin helpers. +/** + * Small markdown utilities. These are inlined from `typedoc-plugin-markdown`'s + * internal `dist/libs/markdown/` and `dist/libs/utils/` modules — the plugin's + * public API doesn't re-export them, and reaching into `dist/` directly breaks + * when the dependency updates. + * + * Keep these byte-equivalent to the upstream behavior so generated markdown + * stays consistent with what typedoc-plugin-markdown produces. + * + * @see https://github.com/typedoc2md/typedoc-plugin-markdown/blob/main/packages/typedoc-plugin-markdown/src/libs/markdown/ + * @see https://github.com/typedoc2md/typedoc-plugin-markdown/blob/main/packages/typedoc-plugin-markdown/src/libs/utils/ + */ + +/** + * Escape characters with special meaning in MDX so they render literally. + * + * @param {string} str + */ +export function escapeChars(str) { + return str + .replace(/>/g, '\\>') + .replace(/ 6 ? 6 : level; + return `${'#'.repeat(l)} ${text}`; +} + +/** + * Collapse newlines and excess whitespace so a string is safe to use as a + * single markdown table cell. + * + * @param {string} str + */ +export function removeLineBreaks(str) { + return str?.replace(/\r?\n/g, ' ').replace(/ {2,}/g, ' '); +} + +/** + * Sanitize a markdown table cell: flatten newlines, unwrap any fenced code + * block into inline backticks, and collapse runs of spaces. + * + * @param {string} str + */ +function formatTableCell(str) { + return str + .replace(/\r?\n/g, ' ') + .replace(/```(\w+\s)?([\s\S]*?)```/gs, (_match, _lang, body) => `\`${body.trim()}\``) + .replace(/ +/g, ' ') + .trim(); +} + +/** + * Render a markdown pipe-table. + * + * @param {string[]} headers + * @param {string[][]} rows + * @param {boolean} [headerLeftAlign] + */ +export function table(headers, rows, headerLeftAlign = false) { + const sep = headers.map(() => `${headerLeftAlign ? ':' : ''}------`).join(' | '); + const body = rows.map(row => `| ${row.map(cell => formatTableCell(cell)).join(' | ')} |\n`).join(''); + return `\n| ${headers.join(' | ')} |\n| ${sep} |\n${body}`; +} + +/** + * Render an HTML `` (used when MDX needs richer cell content than the + * pipe-table syntax can express). + * + * @param {string[]} headers + * @param {string[][]} rows + * @param {boolean} [leftAlignHeadings] + */ +export function htmlTable(headers, rows, leftAlignHeadings = false) { + const align = leftAlignHeadings ? ' align="left"' : ''; + const head = headers.map(h => `\n${h}`).join(''); + const body = rows + .map(row => { + const cells = row.map(cell => `\n`).join(''); + return `\n${cells}\n`; + }) + .join(''); + return `
\n\n${cell === '-' ? '‐' : cell}\n\n
\n\n${head}\n\n\n${body}\n\n
`; +} diff --git a/.typedoc/reference-objects.mjs b/.typedoc/reference-objects.mjs new file mode 100644 index 00000000000..424ca40172f --- /dev/null +++ b/.typedoc/reference-objects.mjs @@ -0,0 +1,68 @@ +// @ts-check +/** + * Shared between the markdown theme and extract-methods.mjs. + * `page.url` values are relative to TypeDoc `out` (e.g. `.typedoc/temp-docs`). + */ + +/** + * Reference object page: MDX path → TypeDoc symbol + optional source hint. + * + * Keys **must** match `custom-router.mjs` (`ClerkRouter`): for each symbol, `shared//.mdx` + * (e.g. `SessionResource` → `shared/session-resource/session-resource.mdx`). If the path drifts, TypeDoc writes one folder while `extract-methods.mjs` strips/writes under another. + * + * `declarationHint` is a substring of `packages/shared/src/**` file paths (used by `findInterfaceOrClass()` in `extract-methods.mjs` when multiple reflections share the same interface/class name). + * + * `extract-methods.mjs` reads each file, writes `properties.mdx` with the same Properties table as TypeDoc (no `## Properties` heading), strips Properties from `.mdx`, and writes methods under `methods/`. + * + * Optional **`extraMethodInterfaces`**: extra `interface` / `class` declarations whose callable members (and `@extractMethods` namespaces) are emitted into the same `methods/` folder. Use when the documented resource type and the API surface live on different types (e.g. `APIKeyResource` vs `APIKeysNamespace` on `Clerk.apiKeys`). + */ +export const REFERENCE_OBJECT_CONFIG = { + 'shared/clerk/clerk.mdx': { + symbol: 'Clerk', + declarationHint: 'types/clerk', + }, + 'shared/client-resource/client-resource.mdx': { + symbol: 'ClientResource', + declarationHint: 'types/client', + }, + 'shared/session-resource/session-resource.mdx': { + symbol: 'SessionResource', + declarationHint: 'types/session', + }, + 'shared/user-resource/user-resource.mdx': { + symbol: 'UserResource', + declarationHint: 'types/user', + }, + 'shared/sign-in-future-resource/sign-in-future-resource.mdx': { + symbol: 'SignInFutureResource', + declarationHint: 'types/signInFuture', + }, + 'shared/sign-up-future-resource/sign-up-future-resource.mdx': { + symbol: 'SignUpFutureResource', + declarationHint: 'types/signUpFuture', + }, + 'shared/organization-resource/organization-resource.mdx': { + symbol: 'OrganizationResource', + declarationHint: 'types/organization', + }, + 'shared/api-key-resource/api-key-resource.mdx': { + symbol: 'APIKeyResource', + declarationHint: 'types/apiKeys', + extraMethodInterfaces: [{ symbol: 'APIKeysNamespace', declarationHint: 'types/apiKeys' }], + }, + 'shared/billing-namespace/billing-namespace.mdx': { + symbol: 'BillingNamespace', + declarationHint: 'types/billing', + }, +}; + +/** Stable iteration order matches key order in {@link REFERENCE_OBJECT_CONFIG}. */ +export const REFERENCE_OBJECTS_LIST = Object.keys(REFERENCE_OBJECT_CONFIG); + +/** + * Primary interface/class documented on each reference object page (used to resolve TypeDoc reflections). + * Derived from {@link REFERENCE_OBJECT_CONFIG}; kept for callers that only need `pageUrl → symbol`. + */ +export const REFERENCE_OBJECT_PAGE_SYMBOLS = Object.fromEntries( + Object.entries(REFERENCE_OBJECT_CONFIG).map(([url, { symbol }]) => [url, symbol]), +); diff --git a/.typedoc/slug.mjs b/.typedoc/slug.mjs new file mode 100644 index 00000000000..f4cebb54e64 --- /dev/null +++ b/.typedoc/slug.mjs @@ -0,0 +1,35 @@ +// @ts-check — JSDoc-typed plugin helpers. +/** + * Two kebab-case flavors. They produce different output for acronym-heavy names (`mountOAuthConsent`, `authenticateWithOKXWallet`, …) and the published docs depend on both styles existing — do not consolidate them without changing the output. + * + * | input | toFileSlug | toUrlSlug | + * | --------------------------- | ----------------------- | ------------------------- | + * | `mountOAuthConsent` | `mount-oauth-consent` | `mount-o-auth-consent` | + * | `authenticateWithOKXWallet` | `authenticate-with-okxwallet` | `authenticate-with-okx-wallet` | + * | `OAuthCallback` | `oauth-callback` | `o-auth-callback` | + * + * `toFileSlug` is what `extract-methods.mjs` uses for `methods/.mdx` filenames — the existing clerk.com docs link to `oauth-…` slugs (see `mount-oauth-consent.mdx`). + * + * `toUrlSlug` is what `custom-router.mjs` uses for page URLs and what cross-page link replacements (`o-auth-strategy`, `o-auth-consent-info` in `custom-plugin.mjs`) match — the published docs link to those `o-auth-…` slugs. + */ + +/** + * Inserts a dash before every uppercase that immediately follows a lowercase or digit, then lowercases. Treats runs of uppercase letters (acronyms) as a single token: `OKXWallet` → `okxwallet`. Used for `methods/.mdx` filenames. + * + * @param {string} name + */ +export function toFileSlug(name) { + return name + .replace(/([a-z\d])([A-Z])/g, '$1-$2') + .replace(/[\s_]+/g, '-') + .toLowerCase(); +} + +/** + * Splits acronyms by also inserting a dash between adjacent uppercase letters when the second one is followed by a lowercase: `OKXWallet` → `okx-wallet`. Used for page URLs. + * + * @param {string} str + */ +export function toUrlSlug(str) { + return str.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase(); +} diff --git a/.typedoc/standalone-page-tag.mjs b/.typedoc/standalone-page-tag.mjs new file mode 100644 index 00000000000..20cf25c55e4 --- /dev/null +++ b/.typedoc/standalone-page-tag.mjs @@ -0,0 +1,24 @@ +// @ts-check + +/** + * Modifier tag: keep a dedicated `.mdx` page even when `@inline` is present (TypeDoc + our router otherwise drop inline-marked declarations; the theme also expands references instead of linking). + */ +export const STANDALONE_PAGE_MODIFIER_TAG = '@standalonePage'; + +/** + * @param {import('typedoc').Reflection | undefined} reflection + * @returns {boolean} True when `@inline` should suppress a standalone page / force in-place expansion. + */ +export function isInlineModifierWithoutStandalonePage(reflection) { + const comment = + reflection && 'comment' in reflection + ? /** @type {{ comment?: import('typedoc').Comment | undefined }} */ (reflection).comment + : undefined; + if (!comment?.hasModifier('@inline')) { + return false; + } + if (comment.hasModifier(STANDALONE_PAGE_MODIFIER_TAG)) { + return false; + } + return true; +} diff --git a/.typedoc/type-utils.mjs b/.typedoc/type-utils.mjs new file mode 100644 index 00000000000..38ba45c4e5f --- /dev/null +++ b/.typedoc/type-utils.mjs @@ -0,0 +1,27 @@ +// @ts-check — JSDoc-typed plugin helpers shared between custom-theme.mjs and extract-methods.mjs. + +/** + * Strip one (or, with `{ deep: true }`, all) `OptionalType` layers and return the inner type. Returns `t` unchanged when it isn't an `OptionalType`, or when `t` is nullish. + * + * Typed loosely (`Type` ⊕ `SomeType`) so callers in either type domain can use the same helper; the runtime check is structural (`type === 'optional' && 'elementType' in t`). + * + * @template {import('typedoc').Type | import('typedoc').SomeType | undefined} T + * @param {T} t + * @param {{ deep?: boolean }} [options] + * @returns {T} + */ +export function unwrapOptional(t, options) { + let cur = t; + while ( + cur && + typeof cur === 'object' && + /** @type {{ type?: string }} */ (cur).type === 'optional' && + 'elementType' in cur + ) { + cur = /** @type {T} */ (/** @type {{ elementType: import('typedoc').Type }} */ (cur).elementType); + if (!options?.deep) { + break; + } + } + return cur; +} diff --git a/packages/backend/src/api/endpoints/ActorTokenApi.ts b/packages/backend/src/api/endpoints/ActorTokenApi.ts index c3dca6a9706..2c4e3e114ba 100644 --- a/packages/backend/src/api/endpoints/ActorTokenApi.ts +++ b/packages/backend/src/api/endpoints/ActorTokenApi.ts @@ -28,7 +28,7 @@ type ActorTokenCreateParams = { */ actor: ActorTokenActorCreateParams; /** - * Optional parameter to specify the life duration of the actor token in seconds. + * The lifetime of the actor token in seconds. * * @remarks * By default, the duration is 1 hour. diff --git a/packages/backend/src/api/endpoints/SessionApi.ts b/packages/backend/src/api/endpoints/SessionApi.ts index a4fc70ddf55..170408ea5ac 100644 --- a/packages/backend/src/api/endpoints/SessionApi.ts +++ b/packages/backend/src/api/endpoints/SessionApi.ts @@ -72,11 +72,11 @@ export class SessionAPI extends AbstractAPI { } /** - * Retrieves a session token or generates a JWT using a specified template. + * Gets a session token or generates a JWT using a specified template. * * @param sessionId - The ID of the session for which to generate the token - * @param template - Optional name of the JWT template configured in the Clerk Dashboard. - * @param expiresInSeconds - Optional expiration time for the token in seconds. + * @param template - The name of the JWT template configured in the Clerk Dashboard. + * @param expiresInSeconds - The expiration time for the token in seconds. * If not provided, uses the default expiration. * * @returns A promise that resolves to the generated token diff --git a/packages/backend/src/api/resources/APIKey.ts b/packages/backend/src/api/resources/APIKey.ts index 6e3c3fbf044..5add117abc6 100644 --- a/packages/backend/src/api/resources/APIKey.ts +++ b/packages/backend/src/api/resources/APIKey.ts @@ -50,7 +50,7 @@ export class APIKey { */ readonly createdBy: string | null, /** - * An optional description for the API key. + * A description for the API key. */ readonly description: string | null, /** diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index 205d7d1fd3a..8353fa1286d 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -390,7 +390,7 @@ export const makeAuthObjectSerializable = >(ob * * @param sessionId - The ID of the session * @param template - The JWT template name to use for token generation - * @param expiresInSeconds - Optional expiration time in seconds for the token + * @param expiresInSeconds - The expiration time in seconds for the token * @returns A promise that resolves to the token string */ type TokenFetcher = (sessionId: string, template?: string, expiresInSeconds?: number) => Promise; @@ -406,8 +406,7 @@ type CreateGetToken = (params: { sessionId: string; sessionToken: string; fetche /** * Creates a token retrieval function for authenticated sessions. * - * This factory function returns a getToken function that can either return the raw session token - * or generate a JWT using a specified template with optional custom expiration. + * This factory function returns a getToken function that can either return the raw session token or generate a JWT using a specified template with custom expiration. * * @param params - Configuration object * @param params.sessionId - The session ID for token generation diff --git a/packages/backend/src/tokens/authenticateContext.ts b/packages/backend/src/tokens/authenticateContext.ts index 794c9268874..e8d1d682330 100644 --- a/packages/backend/src/tokens/authenticateContext.ts +++ b/packages/backend/src/tokens/authenticateContext.ts @@ -58,7 +58,7 @@ class AuthenticateContext implements AuthenticateContext { private originalFrontendApi: string = ''; /** - * Retrieves the session token from either the cookie or the header. + * Gets the session token from either the cookie or the header. * * @returns {string | undefined} The session token if available, otherwise undefined. */ diff --git a/packages/clerk-js/src/core/modules/apiKeys/index.ts b/packages/clerk-js/src/core/modules/apiKeys/index.ts index 77949b70ae0..58e589c1a2d 100644 --- a/packages/clerk-js/src/core/modules/apiKeys/index.ts +++ b/packages/clerk-js/src/core/modules/apiKeys/index.ts @@ -40,7 +40,7 @@ export class APIKeys implements APIKeysNamespace { } /** - * Retrieves a paginated list of API keys. + * Gets a paginated list of API keys. * * The subject (owner) is resolved in the following order: * 1. Explicit `subject` param (user or organization ID) diff --git a/packages/clerk-js/src/core/modules/debug/index.ts b/packages/clerk-js/src/core/modules/debug/index.ts index cb7ec30695e..30e37e51a13 100644 --- a/packages/clerk-js/src/core/modules/debug/index.ts +++ b/packages/clerk-js/src/core/modules/debug/index.ts @@ -22,11 +22,11 @@ function validateLoggerOptions(options: T): vo * Options for configuring the debug logger. */ export interface LoggerOptions { - /** Optional URL to which telemetry logs will be sent. */ + /** The URL to which telemetry logs will be sent. */ endpoint?: string; /** Minimum log level to capture. */ logLevel?: DebugLogLevel; - /** Optional collector instance for custom telemetry handling. */ + /** A collector instance for custom telemetry handling. */ telemetryCollector?: TelemetryCollector; } @@ -42,11 +42,11 @@ export interface ConsoleLoggerOptions { * Configuration options for a telemetry-based debug logger. */ export interface TelemetryLoggerOptions { - /** Optional URL to which telemetry logs will be sent. */ + /** The URL to which telemetry logs will be sent. */ endpoint?: string; /** Minimum log level to capture. */ logLevel?: DebugLogLevel; - /** Optional collector instance for custom telemetry handling. */ + /** A collector instance for custom telemetry handling. */ telemetryCollector?: TelemetryCollector; } diff --git a/packages/clerk-js/src/core/resources/Client.ts b/packages/clerk-js/src/core/resources/Client.ts index 986252b20dd..6b690c7261c 100644 --- a/packages/clerk-js/src/core/resources/Client.ts +++ b/packages/clerk-js/src/core/resources/Client.ts @@ -33,7 +33,6 @@ export class Client extends BaseResource implements ClientResource { lastActiveSessionId: string | null = null; captchaBypass = false; cookieExpiresAt: Date | null = null; - /** Last authentication strategy used by this client; `null` when unknown/disabled. */ lastAuthenticationStrategy: LastAuthenticationStrategy | null = null; createdAt: Date | null = null; updatedAt: Date | null = null; diff --git a/packages/expo/src/google-one-tap/types.ts b/packages/expo/src/google-one-tap/types.ts index fdc8e95df74..7133fc1be46 100644 --- a/packages/expo/src/google-one-tap/types.ts +++ b/packages/expo/src/google-one-tap/types.ts @@ -18,7 +18,7 @@ export type ConfigureParams = { iosClientId?: string; /** - * Optional hosted domain to restrict sign-in to a specific domain. + * The hosted domain to restrict sign-in to a specific domain. */ hostedDomain?: string; diff --git a/packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts b/packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts index 771bea0e700..1705353f808 100644 --- a/packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts +++ b/packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts @@ -191,11 +191,11 @@ export const useLocalCredentials = (): LocalCredentialsReturn => { */ setCredentials, /** - * A Boolean that indicates if there are any credentials stored on the device. + * Indicates whether there are any credentials stored on the device. */ hasCredentials: hasLocalAuthCredentials, /** - * A Boolean that indicates if the stored credentials belong to the signed in uer. When there is no signed-in user the value will always be `false`. + * Indicates whether the stored credentials belong to the signed in user. When there is no signed-in user the value will always be `false`. */ userOwnsCredentials, /** diff --git a/packages/express/src/getAuth.ts b/packages/express/src/getAuth.ts index 0119cbeec7f..31b12cdff04 100644 --- a/packages/express/src/getAuth.ts +++ b/packages/express/src/getAuth.ts @@ -8,7 +8,7 @@ import { requestHasAuthObject } from './utils'; /** * Retrieves the Clerk AuthObject using the current request object. * - * @param {GetAuthOptions} options - Optional configuration for retriving auth object. + * @param {GetAuthOptions} options - Optional configuration for retrieving auth object. * @returns {AuthObject} Object with information about the request state and claims. * @throws {Error} `clerkMiddleware` or `requireAuth` is required to be set in the middleware chain before this util is used. */ diff --git a/packages/nextjs/src/app-router/server/currentUser.ts b/packages/nextjs/src/app-router/server/currentUser.ts index 9ab96f78f4f..327a730071a 100644 --- a/packages/nextjs/src/app-router/server/currentUser.ts +++ b/packages/nextjs/src/app-router/server/currentUser.ts @@ -15,6 +15,8 @@ type CurrentUserOptions = PendingSessionOptions; * - uses the [`GET /v1/users/{user_id}`](https://clerk.com/docs/reference/backend-api/tag/users/GET/users/%7Buser_id%7D) endpoint. * - counts towards the [Backend API request rate limit](https://clerk.com/docs/guides/how-clerk-works/system-limits). * + * @param opts - Options to configure the behavior of the helper. + * * @example * ```tsx {{ filename: 'app/page.tsx' }} * import { currentUser } from '@clerk/nextjs/server' diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 0b29d105b27..dfd60fa861b 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -94,7 +94,7 @@ export const createSyncGetAuth = ({ * > If you are using App Router, use the [`auth()` helper](https://clerk.com/docs/reference/nextjs/app-router/auth) instead. * * @param req - The Next.js request object. - * @param [options] - An optional object that can be used to configure the behavior of the `getAuth()` function. + * @param [options] - An object that can be used to configure the behavior of the `getAuth()` function. * @param [options.secretKey] - A string that represents the Secret Key used to sign the session token. If not provided, the Secret Key is retrieved from the environment variable `CLERK_SECRET_KEY`. * @returns The `Auth` object. See the [Auth reference](https://clerk.com/docs/reference/backend/types/auth-object) for more information. * diff --git a/packages/react/src/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx index da0ab7f8fbb..48fb42f8cf5 100644 --- a/packages/react/src/components/uiComponents.tsx +++ b/packages/react/src/components/uiComponents.tsx @@ -55,7 +55,7 @@ import { withClerk } from './withClerk'; type FallbackProp = { /** - * An optional element to render while the component is mounting. + * The element to render while the component is mounting. */ fallback?: ReactNode; }; diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index c8896134628..4957f7b6796 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -35,7 +35,7 @@ type UseAuthOptions = PendingSessionOptions | undefined | null; * @unionReturnHeadings * ["Loading", "Signed out", "Signed in (no active organization)", "Signed in (with active organization)"] * - * @param [options] - An object containing options for the `useAuth()` hook. `treatPendingAsSignedOut` is a boolean that indicates whether pending sessions are considered as signed out or not. Defaults to `true`. + * @param [options] - An object containing options for the `useAuth()` hook. `treatPendingAsSignedOut` indicates whether pending sessions are considered as signed out or not. Defaults to `true`. * * @function * diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index 9c38a97c989..bf773d029c9 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -53,11 +53,11 @@ export type ClerkProviderProps = Omit< */ __internal_bypassMissingPublishableKey?: boolean; /** - * Optional object to style your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. + * An object to style your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. */ appearance?: ExtractAppearanceType; /** - * Optional object to use the bundled Clerk UI instead of loading from CDN. + * An object to use the bundled Clerk UI instead of loading from CDN. * Import `ui` from `@clerk/ui` and pass it here to bundle the UI with your application. * When omitted, UI is loaded from Clerk's CDN. * Note: When `ui` is used, appearance is automatically typed based on the specific UI version. diff --git a/packages/shared/src/eventBus.ts b/packages/shared/src/eventBus.ts index ad6766b4d7c..d89fd2e4bb3 100644 --- a/packages/shared/src/eventBus.ts +++ b/packages/shared/src/eventBus.ts @@ -47,7 +47,7 @@ type EventBus> = { * Unsubscribe from an event * * @param event - The event name to unsubscribe from - * @param handler - Optional specific handler to remove. If omitted, all handlers for the event are removed + * @param handler - A specific handler to remove. If omitted, all handlers for the event are removed * @returns void */ off: (event: Event, handler?: EventHandler) => void; @@ -56,7 +56,7 @@ type EventBus> = { * Unsubscribe from a pre-dispatch event * * @param event - The event name to unsubscribe from - * @param handler - Optional specific handler to remove. If omitted, all pre-dispatch handlers for the event are removed + * @param handler - A specific handler to remove. If omitted, all pre-dispatch handlers for the event are removed * @returns void */ prioritizedOff: (event: Event, handler?: EventHandler) => void; diff --git a/packages/shared/src/react/billing/payment-element.tsx b/packages/shared/src/react/billing/payment-element.tsx index f293399fac2..0a988347583 100644 --- a/packages/shared/src/react/billing/payment-element.tsx +++ b/packages/shared/src/react/billing/payment-element.tsx @@ -98,11 +98,11 @@ type internalStripeAppearance = { */ export type PaymentElementProviderProps = { /** - * An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session. + * A checkout resource object. When provided, the payment element is scoped to the specific checkout session. */ checkout?: CheckoutFlowResource | BillingCheckoutResource | ReturnType['checkout']; /** - * An optional object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme. + * An object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme. */ stripeAppearance?: internalStripeAppearance; /** @@ -112,7 +112,7 @@ export type PaymentElementProviderProps = { */ for?: ForPayerType; /** - * An optional description to display to the user within the payment element UI. + * A description to display to the user within the payment element UI. */ paymentDescription?: string; }; @@ -294,7 +294,7 @@ export type UsePaymentElementReturn = { */ reset: () => Promise; /** - * A boolean that indicates if the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive. + * Indicates whether the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive. */ isFormReady: boolean; } & ( @@ -306,7 +306,7 @@ export type UsePaymentElementReturn = { name: 'stripe'; }; /** - * A boolean that indicates if the underlying payment provider (e.g. Stripe) has been fully initialized. + * Indicates whether the underlying payment provider (e.g. Stripe) has been fully initialized. */ isProviderReady: true; } diff --git a/packages/shared/src/react/hooks/createBillingPaginatedHook.tsx b/packages/shared/src/react/hooks/createBillingPaginatedHook.tsx index 8b057f0309a..e6ecc3137e6 100644 --- a/packages/shared/src/react/hooks/createBillingPaginatedHook.tsx +++ b/packages/shared/src/react/hooks/createBillingPaginatedHook.tsx @@ -25,6 +25,7 @@ type BillingHookConfig = | { /** - * A boolean that indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** diff --git a/packages/shared/src/react/hooks/useOrganizationCreationDefaults.types.ts b/packages/shared/src/react/hooks/useOrganizationCreationDefaults.types.ts index 63575b3e1d0..f968b333741 100644 --- a/packages/shared/src/react/hooks/useOrganizationCreationDefaults.types.ts +++ b/packages/shared/src/react/hooks/useOrganizationCreationDefaults.types.ts @@ -32,11 +32,11 @@ export type UseOrganizationCreationDefaultsReturn = { */ error: ClerkAPIResponseError | null; /** - * A boolean that indicates whether the initial data is still being fetched. + * Indicates whether the initial data is still being fetched. */ isLoading: boolean; /** - * A boolean that indicates whether any request is still in flight, including background updates. + * Indicates whether any request is still in flight, including background updates. */ isFetching: boolean; }; diff --git a/packages/shared/src/react/hooks/useOrganizationList.tsx b/packages/shared/src/react/hooks/useOrganizationList.tsx index a5b37b06c24..38eb4176b86 100644 --- a/packages/shared/src/react/hooks/useOrganizationList.tsx +++ b/packages/shared/src/react/hooks/useOrganizationList.tsx @@ -77,7 +77,7 @@ const undefinedPaginatedResource = { export type UseOrganizationListReturn = | { /** - * A boolean that indicates whether Clerk has loaded the current authentication state and there is an authenticated user. Initially `false`, becomes `true` once Clerk loads with a user, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). + * Indicates whether Clerk has loaded the current authentication state and there is an authenticated user. Initially `false`, becomes `true` once Clerk loads with a user, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** diff --git a/packages/shared/src/react/hooks/usePaymentAttemptQuery.types.ts b/packages/shared/src/react/hooks/usePaymentAttemptQuery.types.ts index 9c1dd976333..e35e4964319 100644 --- a/packages/shared/src/react/hooks/usePaymentAttemptQuery.types.ts +++ b/packages/shared/src/react/hooks/usePaymentAttemptQuery.types.ts @@ -42,11 +42,11 @@ export type PaymentAttemptQueryResult = { */ error: ClerkAPIResponseError | null; /** - * A boolean that indicates whether the initial data is still being fetched. + * Indicates whether the initial data is still being fetched. */ isLoading: boolean; /** - * A boolean that indicates whether any request is still in flight, including background updates. + * Indicates whether any request is still in flight, including background updates. */ isFetching: boolean; }; diff --git a/packages/shared/src/react/hooks/usePlanDetailsQuery.types.ts b/packages/shared/src/react/hooks/usePlanDetailsQuery.types.ts index 653e4229a42..46113540c73 100644 --- a/packages/shared/src/react/hooks/usePlanDetailsQuery.types.ts +++ b/packages/shared/src/react/hooks/usePlanDetailsQuery.types.ts @@ -40,11 +40,11 @@ export type PlanDetailsQueryResult = { */ error: ClerkAPIResponseError | null; /** - * A boolean that indicates whether the initial data is still being fetched. + * Indicates whether the initial data is still being fetched. */ isLoading: boolean; /** - * A boolean that indicates whether any request is still in flight, including background updates. + * Indicates whether any request is still in flight, including background updates. */ isFetching: boolean; }; diff --git a/packages/shared/src/react/hooks/useStatementQuery.types.ts b/packages/shared/src/react/hooks/useStatementQuery.types.ts index f6302024101..0ee92ab87d1 100644 --- a/packages/shared/src/react/hooks/useStatementQuery.types.ts +++ b/packages/shared/src/react/hooks/useStatementQuery.types.ts @@ -41,11 +41,11 @@ export type StatementQueryResult = { */ error: ClerkAPIResponseError | null; /** - * A boolean that indicates whether the initial data is still being fetched. + * Indicates whether the initial data is still being fetched. */ isLoading: boolean; /** - * A boolean that indicates whether any request is still in flight, including background updates. + * Indicates whether any request is still in flight, including background updates. */ isFetching: boolean; }; diff --git a/packages/shared/src/react/hooks/useSubscription.types.ts b/packages/shared/src/react/hooks/useSubscription.types.ts index 462509b1632..11637dd4c11 100644 --- a/packages/shared/src/react/hooks/useSubscription.types.ts +++ b/packages/shared/src/react/hooks/useSubscription.types.ts @@ -37,11 +37,11 @@ export type SubscriptionResult = { */ error: Error | undefined; /** - * A boolean that indicates whether the initial data is still being fetched. + * Indicates whether the initial data is still being fetched. */ isLoading: boolean; /** - * A boolean that indicates whether any request is still in flight, including background updates. + * Indicates whether any request is still in flight, including background updates. */ isFetching: boolean; /** diff --git a/packages/shared/src/react/types.ts b/packages/shared/src/react/types.ts index aea1557422e..a5d3a3adb09 100644 --- a/packages/shared/src/react/types.ts +++ b/packages/shared/src/react/types.ts @@ -24,15 +24,15 @@ export type PaginatedResources = { */ error: ClerkAPIResponseError | null; /** - * A boolean that is `true` if there is an ongoing request and there is no fetched data. + * Indicates whether there is an ongoing request and there is no fetched data. */ isLoading: boolean; /** - * A boolean that is `true` if there is an ongoing request or a revalidation. + * Indicates whether there is an ongoing request or a revalidation. */ isFetching: boolean; /** - * A boolean that indicates the request failed. + * Indicates whether the request failed. */ isError: boolean; /** @@ -57,11 +57,11 @@ export type PaginatedResources = { */ fetchNext: () => void; /** - * A boolean that indicates if there are available pages to be fetched. + * Indicates whether there are available pages to be fetched. */ hasNextPage: boolean; /** - * A boolean that indicates if there are available pages to be fetched. + * Indicates whether there are available pages to be fetched. */ hasPreviousPage: boolean; /** @@ -85,6 +85,7 @@ export type PaginatedResourcesWithDefault = { /** * @inline + * @standalonePage */ export type PaginatedHookConfig = T & { /** diff --git a/packages/shared/src/types/apiKeys.ts b/packages/shared/src/types/apiKeys.ts index 09679504ecf..652cf83a9f2 100644 --- a/packages/shared/src/types/apiKeys.ts +++ b/packages/shared/src/types/apiKeys.ts @@ -2,36 +2,93 @@ import type { CreateAPIKeyParams, GetAPIKeysParams, RevokeAPIKeyParams } from '. import type { ClerkPaginatedResponse } from './pagination'; import type { ClerkResource } from './resource'; +/** + * The `APIKeys` object provides methods for managing API keys that allow your application's users to grant third-party services programmatic access to your application's API endpoints on their behalf. API keys are long-lived, opaque tokens that can be instantly revoked. + */ export interface APIKeyResource extends ClerkResource { + /** + * A unique identifier for the API key. + */ id: string; + /** + * The type of the API key. + */ type: string; + /** + * The name of the API key. + */ name: string; + /** + * The user or organization ID that the API key is associated with. + */ subject: string; + /** + * An array of scopes that define what the API key can access. + */ scopes: string[]; + /** + * Custom claims associated with the API key, or `null` if none. + */ claims: Record | null; + /** + * Indicates whether the API key has been revoked. + */ revoked: boolean; + /** + * The reason the API key was revoked, or `null` if not revoked. + */ revocationReason: string | null; + /** + * Indicates whether the API key has expired. + */ expired: boolean; + /** + * The expiration date and time for the API key, or `null` if the key never expires. + */ expiration: Date | null; + /** + * The ID of the user that created the API key. + */ createdBy: string | null; + /** + * A description for the API key. + */ description: string | null; + /** + * The API key secret. **This property is only present in the response from [`create()`](https://clerk.com/docs/reference/objects/api-keys#create) and cannot be retrieved later.** + */ secret?: string; + /** + * The date and time when the API key was last used to authenticate a request, or `null` if it has never been used. + */ lastUsedAt: Date | null; + /** + * The date and time when the API key was created. + */ createdAt: Date; + /** + * The date and time when the API key was last updated. + */ updatedAt: Date; } +/** @generateWithEmptyComment */ export interface APIKeysNamespace { /** - * Retrieves a paginated list of API keys for the current user or organization. + * Gets a paginated list of API keys for the current user or organization. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`APIKeyResource`](https://clerk.com/docs/reference/types/api-key-resource) objects. */ getAll(params?: GetAPIKeysParams): Promise>; /** * Creates a new API key. + * @returns An [`APIKeyResource`](https://clerk.com/docs/reference/types/api-key-resource) object that includes the `secret` property. + * > [!WARNING] + * > Make sure to store the API key secret immediately after creation, as it will not be available again. */ create(params: CreateAPIKeyParams): Promise; /** * Revokes a given API key by ID. + * @returns An [`APIKeyResource`](https://clerk.com/docs/reference/types/api-key-resource) object. */ revoke(params: RevokeAPIKeyParams): Promise; } diff --git a/packages/shared/src/types/attributes.ts b/packages/shared/src/types/attributes.ts index 7cc23cbcc46..0b2ca92c6fc 100644 --- a/packages/shared/src/types/attributes.ts +++ b/packages/shared/src/types/attributes.ts @@ -1,4 +1,8 @@ +/** @inline */ export type FirstNameAttribute = 'first_name'; +/** @inline */ export type LastNameAttribute = 'last_name'; +/** @inline */ export type PasswordAttribute = 'password'; +/** @inline */ export type LegalAcceptedAttribute = 'legal_accepted'; diff --git a/packages/shared/src/types/billing.ts b/packages/shared/src/types/billing.ts index 786887fd2b6..a33212af489 100644 --- a/packages/shared/src/types/billing.ts +++ b/packages/shared/src/types/billing.ts @@ -6,7 +6,10 @@ import type { ClerkPaginatedResponse, ClerkPaginationParams } from './pagination import type { ClerkResource } from './resource'; import type { ForceNull, RemoveFunctions, Simplify } from './utils'; -type WithOptionalOrgType = T & { +/** + * Intersects `T` with an optional organization scope (`orgId`) for billing and related requests. + */ +export type WithOptionalOrgType = T & { /** * The Organization ID to perform the request on. */ @@ -18,56 +21,64 @@ type WithOptionalOrgType = T & { */ export interface BillingNamespace { /** - * Returns a list of payment attempts for the current user or supplied organization. + * Gets a list of payment attempts for the current user or supplied Organization. + * @returns A [`ClerkPaginatedResponse`](/docs/reference/types/clerk-paginated-response) of [`BillingPaymentResource`](/docs/reference/types/billing-payment-resource) objects. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getPaymentAttempts: (params: GetPaymentAttemptsParams) => Promise>; /** - * Returns details of a specific payment attempt for the current user or supplied Organization. + * Gets details of a specific payment attempt for the current user or supplied Organization. + * @returns A [`BillingPaymentResource`](https://clerk.com/docs/reference/types/billing-payment-resource) object. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getPaymentAttempt: (params: GetPaymentAttemptParams) => Promise; /** - * Returns a list of all publically visible Billing Plans. + * Gets a list of all publically visible Billing Plans. + * @returns A [`ClerkPaginatedResponse`](/docs/reference/types/clerk-paginated-response) of [`BillingPlanResource`](/docs/reference/types/billing-plan-resource) objects. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getPlans: (params?: GetPlansParams) => Promise>; /** - * Returns a Billing Plan by ID. + * Gets a given Billing Plan. + * @returns A [`BillingPlanResource`](/docs/reference/types/billing-plan-resource) object. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getPlan: (params: GetPlanParams) => Promise; /** - * Returns the main Billing Subscription for the current user or supplied Organization. + * Gets the main Billing Subscription for the current user or supplied Organization. + * @returns A [`BillingSubscriptionResource`](/docs/reference/types/billing-subscription-resource) object. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getSubscription: (params: GetSubscriptionParams) => Promise; /** - * Returns a list of billing statements for the current user or supplied Organization. + * Gets a list of Billing Statements for the current user or supplied Organization. + * @returns A [`ClerkPaginatedResponse`](/docs/reference/types/clerk-paginated-response) of [`BillingStatementResource`](/docs/reference/types/billing-statement-resource) objects. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getStatements: (params: GetStatementsParams) => Promise>; /** - * Returns a billing statement by ID. + * Gets a given Billing Statement. + * @returns A [`BillingStatementResource`](/docs/reference/types/billing-statement-resource) object. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getStatement: (params: GetStatementParams) => Promise; /** - * Creates a new billing checkout for the current user or supplied Organization. + * Creates a new Billing checkout for the current user or supplied Organization. + * @returns A [`BillingCheckoutResource`](/docs/reference/types/billing-checkout-resource) object. * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ @@ -107,14 +118,20 @@ export type BillingSubscriptionPlanPeriod = 'month' | 'annual'; */ export interface BillingPayerMethods { /** + * Initializes a payment method. + * @returns A [`BillingInitializedPaymentMethodResource`](https://clerk.com/docs/reference/types/billing-initialized-payment-method-resource) object. * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ initializePaymentMethod: (params: InitializePaymentMethodParams) => Promise; /** + * Adds a payment method. + * @returns A [`BillingPaymentMethodResource`](https://clerk.com/docs/reference/types/billing-payment-method-resource) object. * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ addPaymentMethod: (params: AddPaymentMethodParams) => Promise; /** + * Gets a list of payment methods that have been stored. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`BillingPaymentMethodResource`](https://clerk.com/docs/reference/types/billing-payment-method-resource) objects. * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ getPaymentMethods: ( @@ -127,7 +144,7 @@ export interface BillingPayerMethods { */ export type GetPlanParams = { /** - * The ID of the Billing Plan to fetch. + * The ID of the Billing Plan to get. */ id: string; }; @@ -474,6 +491,8 @@ export interface BillingPaymentMethodResource extends ClerkResource { } /** + * The `BillingInitializedPaymentMethodResource` type represents a payment method that has been initialized for checkout session. + * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ export interface BillingInitializedPaymentMethodResource extends ClerkResource { @@ -482,11 +501,11 @@ export interface BillingInitializedPaymentMethodResource extends ClerkResource { */ externalClientSecret: string; /** - * The identifier for the external payment gateway used for this checkout session. + * The unique identifier for the external payment gateway used for this checkout session. */ externalGatewayId: string; /** - * The order the payment methods will be displayed in when `` renders. + * The order the payment methods will be displayed in when [``](/docs/nextjs/reference/hooks/use-payment-element#payment-element) renders. */ paymentMethodOrder: string[]; } @@ -557,14 +576,19 @@ export type GetPaymentAttemptsParams = WithOptionalOrgType; +export type GetPaymentAttemptParams = { + /** + * The unique identifier for the payment attempt to get. + */ + id: string; +} & WithOptionalOrgType; /** * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ export type GetStatementParams = { /** - * The ID of the statement to fetch. + * The ID of the statement to get. */ id: string; } & WithOptionalOrgType; @@ -630,6 +654,9 @@ export interface BillingStatementGroup { * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ export type GetSubscriptionParams = { + /** + * The unique identifier for the Organization to get the subscription for. + */ orgId?: string; }; diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index c7e87bcd2d2..9a2c4a015d6 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -135,7 +135,16 @@ export type SDKMetadata = { environment?: string; }; +/** + * A callback function that is called when Clerk resources change. + * @inline + */ export type ListenerCallback = (emission: Resources) => void; +/** + * Optional configuration for the `addListener()` method. + * @param skipInitialEmit - If `true`, the callback will not be called immediately after registration. Defaults to `false`. + * @inline + */ export type ListenerOptions = { skipInitialEmit?: boolean }; export type UnsubscribeCallback = () => void; @@ -175,16 +184,21 @@ export type SetActiveNavigate = (params: { decorateUrl: DecorateUrl; }) => void | Promise; +/** + * A callback that runs after sign out completes. + * @inline */ export type SignOutCallback = () => void | Promise; +/** + * Configuration options. + */ export type SignOutOptions = { /** - * Specify a specific session to sign out. Useful for - * multi-session applications. + * Specify a specific session to sign out. Useful for multi-session applications. */ sessionId?: string; /** - * Specify a redirect URL to navigate to after sign out is complete. + * Specify a redirect URL to navigate to after sign-out is complete. */ redirectUrl?: string; }; @@ -203,8 +217,28 @@ type EventHandler = (payload: ClerkEventPayload[E]) => voi export type ClerkEventPayload = { status: ClerkStatus; }; -type OnEventListener = (event: E, handler: EventHandler, opt?: { notify: boolean }) => void; -type OffEventListener = (event: E, handler: EventHandler) => void; + +/** + * Registers an event listener for a specific Clerk event. + * + * @param event - The event name to subscribe to. + * @param handler - The callback function to execute when the event is dispatched. + * @param opt - Optional configuration. + * @param opt.notify - If true and the event was previously dispatched, handler will be called immediately with the latest payload. + */ +export type OnEventListener = ( + event: E, + handler: EventHandler, + opt?: { notify: boolean }, +) => void; + +/** + * Unregisters an event listener for a specific Clerk event. + * + * @param event - The event name to unsubscribe from. + * @param handler - The callback function to remove. + */ +export type OffEventListener = (event: E, handler: EventHandler) => void; /** * @inline @@ -212,31 +246,33 @@ type OffEventListener = (event: E, handler: EventHandler + *
  • `"error"`: Set when hotloading `clerk-js` or `Clerk.load()` failed.
  • + *
  • `"loading"`: Set during initialization.
  • + *
  • `"ready"`: Set when Clerk is fully operational.
  • + *
  • `"degraded"`: Set when Clerk is partially operational.
  • + * */ status: ClerkStatus; @@ -247,39 +283,42 @@ export interface Clerk { frontendApi: string; - /** Clerk Publishable Key string. */ + /** Your Clerk [Publishable Key](!publishable-key). */ publishableKey: string; - /** Clerk Proxy url string. */ + /** **Required for applications that run behind a reverse proxy**. Your Clerk app's proxy URL. Can be either a relative path (`/__clerk`) or a full URL (`https:///__clerk`). */ proxyUrl: string | undefined; - /** Clerk Satellite Frontend API string. */ + /** The current Clerk app's domain. Prefixed with `clerk.` on production if not already prefixed. Returns `""` when ran on the server. */ domain: string; - /** Clerk Flag for satellite apps. */ + /** Indicates whether the instance is a satellite app. */ isSatellite: boolean; - /** Clerk Instance type is defined from the Publishable key */ + /** Indicates whether the Clerk instance is running in a production or development environment. */ instanceType: InstanceType | undefined; - /** Clerk flag for loading Clerk in a standard browser setup */ + /** + * Indicates whether the instance is being loaded in a standard browser environment. Set to `false` on native platforms where cookies cannot be set. When `undefined`, Clerk assumes a standard browser. + * @inline + */ isStandardBrowser: boolean | undefined; /** - * Indicates whether the current user has a valid signed-in client session + * Indicates whether the current user has a valid signed-in client session. */ isSignedIn: boolean; - /** Client handling most Clerk operations. */ + /** The `Client` object for the current window. */ client: ClientResource | undefined; - /** Current Session. */ + /** The currently active `Session`, which is guaranteed to be one of the sessions in `Client.sessions`. If there is no active session, this field will be `null`. If the session is loading, this field will be `undefined`. */ session: SignedInSessionResource | null | undefined; - /** Active Organization */ + /** A shortcut to the last active `Session.user.organizationMemberships` which holds an instance of a `Organization` object. If the session is `null` or `undefined`, the user field will match. */ organization: OrganizationResource | null | undefined; - /** Current User. */ + /** A shortcut to `Session.user` which holds the currently active `User` object. If the session is `null` or `undefined`, the user field will match. */ user: UserResource | null | undefined; /** @@ -293,25 +332,30 @@ export interface Clerk { * Entrypoint for Clerk's Signal API containing resource signals along with accessible versions of `computed()` and * `effect()` that can be used to subscribe to changes from Signals. * + * @hidden * @experimental This experimental API is subject to change. */ __internal_state: State; /** + * The `Billing` object used for managing billing. + * * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ billing: BillingNamespace; + /** + * [Telemetry](https://clerk.com/docs/guides/how-clerk-works/security/clerk-telemetry) configuration. + */ telemetry: TelemetryCollector | undefined; + /** + * @hidden + */ __internal_country?: string | null; /** - * Signs out the current user on single-session instances, or all users on multi-session instances - * - * @param signOutCallback - Optional A callback that runs after sign out completes. - * @param options - Optional Configuration options, see {@link SignOutOptions} - * @returns A promise that resolves when the sign out process completes. + * Signs out the current user on single-session instances, or all users on multi-session instances. */ signOut: SignOut; @@ -331,11 +375,13 @@ export interface Clerk { * Opens the Clerk Checkout component in a drawer. * * @param props - Optional checkout configuration parameters. + * @hidden */ __internal_openCheckout: (props?: __internal_CheckoutProps) => void; /** * Closes the Clerk Checkout drawer. + * @hidden */ __internal_closeCheckout: () => void; @@ -343,11 +389,13 @@ export interface Clerk { * Opens the Clerk PlanDetails drawer component in a drawer. * * @param props - `plan` or `planId` parameters are required. + * @hidden */ __internal_openPlanDetails: (props: __internal_PlanDetailsProps) => void; /** * Closes the Clerk PlanDetails drawer. + * @hidden */ __internal_closePlanDetails: () => void; @@ -355,11 +403,13 @@ export interface Clerk { * Opens the Clerk SubscriptionDetails drawer component in a drawer. * * @param props - Optional configuration parameters. + * @hidden */ __internal_openSubscriptionDetails: (props?: __internal_SubscriptionDetailsProps) => void; /** * Closes the Clerk SubscriptionDetails drawer. + * @hidden */ __internal_closeSubscriptionDetails: () => void; @@ -367,16 +417,19 @@ export interface Clerk { * Opens the Clerk UserVerification component in a modal. * * @param props - Optional user verification configuration parameters. + * @hidden */ __internal_openReverification: (props?: __internal_UserVerificationModalProps) => void; /** * Closes the Clerk user verification modal. + * @hidden */ __internal_closeReverification: () => void; /** * Attempts to enable a environment setting from a development instance, prompting if disabled. + * @hidden */ __internal_attemptToEnableEnvironmentSetting: ( options: __internal_AttemptToEnableEnvironmentSettingParams, @@ -384,11 +437,13 @@ export interface Clerk { /** * Opens the Clerk Enable Organizations prompt for development instance + * @hidden */ __internal_openEnableOrganizationsPrompt: (props: __internal_EnableOrganizationsPromptProps) => void; /** * Closes the Clerk Enable Organizations modal. + * @hidden */ __internal_closeEnableOrganizationsPrompt: () => void; @@ -692,6 +747,7 @@ export interface Clerk { * * @param targetNode - Target node to mount the OAuth consent component. * @param oauthConsentProps - OAuth consent configuration parameters. + * @hidden */ __internal_mountOAuthConsent: (targetNode: HTMLDivElement, oauthConsentProps?: __internal_OAuthConsentProps) => void; @@ -699,6 +755,7 @@ export interface Clerk { * Unmounts a OAuth consent component from the target element. * * @param targetNode - Target node to unmount the OAuth consent component from. + * @hidden */ __internal_unmountOAuthConsent: (targetNode: HTMLDivElement) => void; @@ -773,27 +830,29 @@ export interface Clerk { __internal_loadStripeJs: () => Promise; /** - * Register a listener that triggers a callback each time important Clerk resources are changed. - * Allows to hook up at different steps in the sign up, sign in processes. + * Register a listener that triggers a callback whenever a change in the [`Client`](https://clerk.com/docs/reference/objects/client), [`Session`](https://clerk.com/docs/reference/objects/session), [`User`](https://clerk.com/docs/reference/objects/user), or [`Organization`](https://clerk.com/docs/reference/objects/organization) resources occurs. This method is primarily used to build frontend SDKs like [`@clerk/react`](https://www.npmjs.com/package/@clerk/react). + * + * Allows hooking up at different steps in the sign up, sign in processes. * * Some important checkpoints: - * When there is an active session, user === session.user. - * When there is no active session, user and session will both be null. - * When a session is loading, user and session will be undefined. + * - When there is an active session, `user === session.user`. + * - When there is no active session, user and session will both be `null`. + * - When a session is loading, user and session will be `undefined`. * - * @param callback - Callback function receiving the most updated Clerk resources after a change. - * @param options.skipInitialEmit - If true, the callback will not be called immediately after registration. - * @returns - Unsubscribe callback + * @param callback - The function to call when Clerk resources change. + * @param options - Optional configuration. + * @param options.skipInitialEmit - If `true`, the callback will not be called immediately after registration. Defaults to `false`. + * @returns - An `UnsubscribeCallback` function that can be used to remove the listener from the `Clerk` object. */ addListener: (callback: ListenerCallback, options?: ListenerOptions) => UnsubscribeCallback; /** * Registers an event handler for a specific Clerk event. * - * @param event - The event name to subscribe to - * @param handler - The callback function to execute when the event is dispatched - * @param opt - Optional configuration object - * @param opt.notify - If true and the event was previously dispatched, handler will be called immediately with the latest payload + * @param event - The event name to subscribe to. + * @param handler - The callback function to execute when the event is triggered. + * @param opt - An object to control the behavior of the event handler. If true, and the event was previously dispatched, handler will be called immediately with the latest payload. + * @param opt.notify - If `true` and the event was previously dispatched, the handler will be called immediately with the latest payload. */ on: OnEventListener; @@ -801,7 +860,7 @@ export interface Clerk { * Removes an event handler for a specific Clerk event. * * @param event - The event name to unsubscribe from - * @param handler - The callback function to remove + * @param handler - The callback function to remove. */ off: OffEventListener; @@ -814,7 +873,7 @@ export interface Clerk { __internal_addNavigationListener: (callback: () => void) => UnsubscribeCallback; /** - * Set the active session and Organization explicitly. + * A method used to set the current session and/or Organization for the client. Accepts a [`SetActiveParams`](https://clerk.com/docs/reference/types/set-active-params) object. * * If the session param is `null`, the active session is deleted. * In a similar fashion, if the organization param is `null`, the current organization is removed as active. @@ -822,148 +881,170 @@ export interface Clerk { setActive: SetActive; /** - * Function used to commit a navigation after certain steps in the Clerk processes. + * Helper method which will use the custom push navigation function of your application to navigate to the provided URL or relative path. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. */ navigate: CustomNavigation; /** - * Decorates the provided url with the auth token for development instances. + * Decorates the provided URL with the auth token for development instances. * - * @param to + * @param to - The route to create a URL towards. */ buildUrlWithAuth(to: string): string; /** - * Returns the configured url where `` is mounted or a custom sign-in page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/authentication/sign-in) is mounted or a custom sign-in page is rendered. * - * @param opts - A {@link RedirectOptions} object + * @param opts - Options used to control the redirect in the constructed URL. */ buildSignInUrl(opts?: RedirectOptions): string; /** - * Returns the configured url where `` is mounted or a custom sign-up page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/authentication/sign-up) is mounted or a custom sign-up page is rendered. * - * @param opts - A {@link RedirectOptions} object + * @param opts - Options used to control the redirect in the constructed URL. */ buildSignUpUrl(opts?: RedirectOptions): string; /** - * Returns the url where `` is mounted or a custom user-profile page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/user/user-profile) is mounted or a custom user-profile page is rendered. */ buildUserProfileUrl(): string; /** - * Returns the configured url where `` is mounted or a custom create-organization page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/organization/create-organization) is mounted or a custom create-organization page is rendered. */ buildCreateOrganizationUrl(): string; /** - * Returns the configured url where `` is mounted or a custom organization-profile page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/organization/organization-profile) is mounted or a custom organization-profile page is rendered. */ buildOrganizationProfileUrl(): string; /** - * Returns the configured url where tasks are mounted. + * Returns the configured URL where [session tasks](https://clerk.com/docs/guides/configure/session-tasks) are mounted. */ buildTasksUrl(): string; /** - * Returns the configured afterSignInUrl of the instance. + * Returns the configured `afterSignInUrl` of the instance. + * @param params - Optional query parameters to append to the URL. */ buildAfterSignInUrl({ params }?: { params?: URLSearchParams }): string; /** - * Returns the configured afterSignInUrl of the instance. + * Returns the configured `afterSignUpUrl` of the instance. + * @param params - Optional query parameters to append to the URL. */ buildAfterSignUpUrl({ params }?: { params?: URLSearchParams }): string; /** - * Returns the configured afterSignOutUrl of the instance. + * Returns the configured `afterSignOutUrl` of the instance. */ buildAfterSignOutUrl(): string; /** - * Returns the configured newSubscriptionRedirectUrl of the instance. + * Returns the configured `newSubscriptionRedirectUrl` of the instance. */ buildNewSubscriptionRedirectUrl(): string; /** - * Returns the configured afterMultiSessionSingleSignOutUrl of the instance. + * Returns the configured `afterMultiSessionSingleSignOutUrl` of the instance. */ buildAfterMultiSessionSingleSignOutUrl(): string; /** - * Returns the configured url where `` is mounted or a custom waitlist page is rendered. + * Returns the configured URL where [``](https://clerk.com/docs/reference/components/authentication/waitlist) is mounted or a custom waitlist page is rendered. + * + * @param opts - Options to control the waitlist URL. + * @param opts.initialValues - Initial values to prefill the waitlist form. */ buildWaitlistUrl(opts?: { initialValues?: Record }): string; /** * - * Redirects to the provided url after decorating it with the auth token for development instances. + * Redirects to the provided URL after appending authentication credentials. For development instances, this method decorates the URL with an auth token to maintain authentication state. For production instances, the standard session cookie is used. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. * - * @param to + * @param to - The URL to redirect to. */ redirectWithAuth(to: string): Promise; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the sign-in URL, as configured in your application's instance settings. This method uses the [`navigate()`](https://clerk.com/docs/reference/objects/clerk#navigate) method under the hood. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. * - * @param opts - A {@link RedirectOptions} object + * @param opts - Options to control the redirect. */ redirectToSignIn(opts?: SignInRedirectOptions): Promise; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the sign-up URL, as configured in your application's instance settings. This method uses the [`navigate()`](https://clerk.com/docs/reference/objects/clerk#navigate) method under the hood. * - * @param opts - A {@link RedirectOptions} object + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. + * + * @param opts - Options to control the redirect. */ redirectToSignUp(opts?: SignUpRedirectOptions): Promise; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the configured URL where [``](https://clerk.com/docs/reference/components/user/user-profile) is mounted. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. */ redirectToUserProfile: () => Promise; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the configured URL where [``](https://clerk.com/docs/reference/components/organization/organization-profile) is mounted. This method uses the [`navigate()`](https://clerk.com/docs/reference/objects/clerk#navigate) method under the hood. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. */ redirectToOrganizationProfile: () => Promise; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the configured URL where [``](https://clerk.com/docs/reference/components/organization/create-organization) is mounted. This method uses the [`navigate()`](https://clerk.com/docs/reference/objects/clerk#navigate) method under the hood. + * + * Returns a promise that can be `await`ed in order to listen for the navigation to finish. The inner value should not be relied on, as it can change based on the framework it's used within. */ redirectToCreateOrganization: () => Promise; /** - * Redirects to the configured afterSignIn URL. + * Redirects to the configured `afterSignIn` URL. */ redirectToAfterSignIn: () => void; /** - * Redirects to the configured afterSignUp URL. + * Redirects to the configured `afterSignUp` URL. */ redirectToAfterSignUp: () => void; /** - * Redirects to the configured afterSignOut URL. + * Redirects to the configured `afterSignOut` URL. */ redirectToAfterSignOut: () => void; /** - * Redirects to the configured URL where `` is mounted. + * Redirects to the configured URL where [``](https://clerk.com/docs/reference/components/authentication/waitlist) is mounted. */ redirectToWaitlist: () => void; /** - * Redirects to the configured URL where tasks are mounted. + * Redirects to the configured URL where [session tasks](https://clerk.com/docs/reference/objects/session) are mounted. * - * @param opts - A {@link RedirectOptions} object + * @param opts - Options to control the redirect (e.g. redirect URL after tasks are complete). */ redirectToTasks(opts?: TasksRedirectOptions): Promise; /** - * Completes a Google One Tap redirection flow started by - * {@link Clerk.authenticateWithGoogleOneTap} + * Completes a Google One Tap redirection flow started by [`authenticateWithGoogleOneTap()`](https://clerk.com/docs/reference/objects/clerk#authenticate-with-google-one-tap). This method should be called after the user is redirected back from visiting the Google One Tap prompt. + * + * @param signInOrUp - The resource returned from the initial `authenticateWithGoogleOneTap()` call (before redirect). + * @param params - Additional props that define where the user will be redirected to at the end of a successful Google One Tap flow. + * @param customNavigate - A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. */ handleGoogleOneTapCallback: ( signInOrUp: SignInResource | SignUpResource, @@ -972,8 +1053,10 @@ export interface Clerk { ) => Promise; /** - * Completes an OAuth or SAML redirection flow started by - * {@link Clerk.client.signIn.authenticateWithRedirect} or {@link Clerk.client.signUp.authenticateWithRedirect} + * Completes a custom OAuth or SAML redirect flow that was started by calling [`SignIn.authenticateWithRedirect(params)`](https://clerk.com/docs/reference/objects/sign-in) or [`SignUp.authenticateWithRedirect(params)`](https://clerk.com/docs/reference/objects/sign-up). + * + * @param params - Additional props that define where the user will be redirected to at the end of a successful OAuth or SAML flow. + * @param customNavigate - A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. */ handleRedirectCallback: ( params: HandleOAuthCallbackParams | HandleSamlCallbackParams, @@ -981,7 +1064,9 @@ export interface Clerk { ) => Promise; /** - * Completes a Email Link flow started by {@link Clerk.client.signIn.createEmailLinkFlow} or {@link Clerk.client.signUp.createEmailLinkFlow} + * Completes an email link verification flow started by `Clerk.client.signIn.createEmailLinkFlow` or `Clerk.client.signUp.createEmailLinkFlow`, by processing the verification results from the redirect URL query parameters. This method should be called after the user is redirected back from visiting the verification link in their email. + * @param params - Allows you to define the URLs where the user should be redirected to on successful verification or pending/completed sign-up or sign-in attempts. If the email link is successfully verified on another device, there's a callback function parameter that allows custom code execution. + * @param customNavigate - A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. */ handleEmailLinkVerification: ( params: HandleEmailLinkVerificationParams, @@ -989,32 +1074,32 @@ export interface Clerk { ) => Promise; /** - * Authenticates user using their Metamask browser extension + * Starts a sign-in flow that uses MetaMask to authenticate the user using their Metamask wallet address. */ authenticateWithMetamask: (params?: AuthenticateWithMetamaskParams) => Promise; /** - * Authenticates user using their Coinbase Smart Wallet and browser extension + * Starts a sign-in flow that uses Coinbase Smart Wallet to authenticate the user using their Coinbase wallet address. */ authenticateWithCoinbaseWallet: (params?: AuthenticateWithCoinbaseWalletParams) => Promise; /** - * Authenticates user using their OKX Wallet browser extension + * Starts a sign-in flow that uses OKX Wallet to authenticate the user using their OKX wallet address. */ authenticateWithOKXWallet: (params?: AuthenticateWithOKXWalletParams) => Promise; /** - * Authenticates user using Base Account SDK + * Starts a sign-in flow that uses Base to authenticate the user using their Web3 wallet address. */ authenticateWithBase: (params?: AuthenticateWithBaseParams) => Promise; /** - * Authenticates user using their Solana supported Web3 wallet browser extension + * Starts a sign-in flow that uses Solana to authenticate the user using their Solana wallet address. */ authenticateWithSolana: (params: AuthenticateWithSolanaParams) => Promise; /** - * Authenticates user using their Web3 Wallet browser extension + * Starts a sign-in flow that uses a Web3 Wallet browser extension to authenticate the user using their Ethereum wallet address. */ authenticateWithWeb3: (params: ClerkAuthenticateWithWeb3Params) => Promise; @@ -1026,20 +1111,28 @@ export interface Clerk { ) => Promise; /** - * Creates an Organization, adding the current user as admin. + * Creates an Organization programmatically, adding the current user as admin. Returns an [`Organization`](https://clerk.com/docs/reference/objects/organization) object. + * + * > [!NOTE] + * > For React-based apps, consider using the [``](https://clerk.com/docs/reference/components/organization/create-organization) component. */ createOrganization: (params: CreateOrganizationParams) => Promise; /** - * Retrieves a single Organization by ID. + * Gets a single [Organization](https://clerk.com/docs/reference/objects/organization) by ID. + * + * @param organizationId - The ID of the Organization to get. */ getOrganization: (organizationId: string) => Promise; /** - * Handles a 401 response from Frontend API by refreshing the client and session object accordingly + * Handles a 401 response from the Frontend API by refreshing the [`Client`](https://clerk.com/docs/reference/objects/client) and [`Session`](https://clerk.com/docs/reference/objects/session) object accordingly. */ handleUnauthenticated: () => Promise; + /** + * Create a new waitlist entry programmatically. Requires that you set your app's sign-up mode to [**Waitlist**](https://clerk.com/docs/guides/secure/restricting-access#waitlist) in the Clerk Dashboard. + */ joinWaitlist: (params: JoinWaitlistParams) => Promise; /** @@ -1062,11 +1155,13 @@ export interface Clerk { /** * Internal flag indicating whether a `setActive` call is in progress. Used to prevent navigations from being * initiated outside of the Clerk class. + * + * @hidden */ __internal_setActiveInProgress: boolean; /** - * API Keys Object + * The `APIKeys` object used for managing API keys. */ apiKeys: APIKeysNamespace; @@ -1084,44 +1179,42 @@ export interface Clerk { __experimental_checkout: __experimental_CheckoutFunction; } +/** @generateWithEmptyComment */ export type HandleOAuthCallbackParams = TransferableOption & SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & { /** - * Full URL or path where the SignIn component is mounted. + * The full URL or path where the [``](https://clerk.com/docs/reference/components/authentication/sign-in) component is mounted. */ signInUrl?: string; /** - * Full URL or path where the SignUp component is mounted. + * The full URL or path where the [``](https://clerk.com/docs/reference/components/authentication/sign-up) component is mounted. */ signUpUrl?: string; /** - * Full URL or path to navigate to during sign in, - * if identifier verification is required. + * The full URL or path to navigate to during sign in, if [first factor verification](!first-factor-verification) is required. */ firstFactorUrl?: string; /** - * Full URL or path to navigate to during sign in, - * if 2FA is enabled. + * The full URL or path to navigate to during sign in, if [multi-factor authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#multi-factor-authentication) is enabled. */ secondFactorUrl?: string; /** - * Full URL or path to navigate to during sign in, - * if the user is required to reset their password. + * The full URL or path to navigate to during sign in, if the user is required to reset their password. */ resetPasswordUrl?: string; /** - * Full URL or path to navigate to after an incomplete sign up. + * The full URL or path to navigate to if the sign up requires additional information. */ continueSignUpUrl?: string | null; /** - * Full URL or path to navigate to after requesting email verification. + * The full URL or path to navigate to after requesting email verification. */ verifyEmailAddressUrl?: string | null; /** - * Full URL or path to navigate to after requesting phone verification. + * The full URL or path to navigate to after requesting phone verification. */ verifyPhoneNumberUrl?: string | null; /** @@ -1129,13 +1222,21 @@ export type HandleOAuthCallbackParams = TransferableOption & */ reloadResource?: 'signIn' | 'signUp'; /** - * Additional arbitrary metadata to be stored alongside the User object when a sign-up transfer occurs. + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. */ unsafeMetadata?: SignUpUnsafeMetadata; }; export type HandleSamlCallbackParams = HandleOAuthCallbackParams; +/** + * A function used to navigate to a given URL after certain steps in the Clerk processes. + * + * @param to - The URL or relative path to navigate to. + * @param options - Optional configuration. + * @param options.replace? - If `true`, replace the current history entry instead of pushing a new one. + * @param options.metadata? - Optional router metadata. + */ export type CustomNavigation = (to: string, options?: NavigateOptions) => Promise | void; export type ClerkThemeOptions = DeepSnakeToCamel>; @@ -1144,7 +1245,7 @@ export type ClerkThemeOptions = DeepSnakeToCamel>; * Navigation options used to replace or push history changes. * Both `routerPush` & `routerReplace` OR none options should be passed. */ -type ClerkOptionsNavigation = +export type ClerkOptionsNavigation = | { /** * A function which takes the destination path as an argument and performs a "push" navigation. @@ -1154,14 +1255,27 @@ type ClerkOptionsNavigation = * A function which takes the destination path as an argument and performs a "replace" navigation. */ routerReplace?: never; + /** + * If `true`, the router will log debug information to the console. + */ routerDebug?: boolean; } | { + /** + * A function which takes the destination path as an argument and performs a "push" navigation. + */ routerPush: RouterFn; + /** + * A function which takes the destination path as an argument and performs a "replace" navigation. + */ routerReplace: RouterFn; + /** + * If `true`, the router will log debug information to the console. + */ routerDebug?: boolean; }; +/** @generateWithEmptyComment */ type ClerkUnsafeOptions = { /** * Disables the `Clerk has been loaded with development keys` console warning that is logged when Clerk is @@ -1184,6 +1298,7 @@ type ClerkUnsafeOptions = { unsafe_disableDevelopmentModeConsoleWarning?: boolean; }; +/** @generateWithEmptyComment */ export type ClerkOptions = ClerkOptionsNavigation & SignInForceRedirectUrl & SignInFallbackRedirectUrl & @@ -1194,34 +1309,42 @@ export type ClerkOptions = ClerkOptionsNavigation & AfterMultiSessionSingleSignOutUrl & ClerkUnsafeOptions & { /** - * Clerk UI module. Pass the `ui` export from `@clerk/ui` to bundle the UI - * with your application instead of loading it from the CDN. + * **Only required if you're bundling Clerk's UI (`@clerk/ui`) instead of loading it from the Clerk CDN**. Provide the UI module to embed Clerk's prebuilt authentication components directly in your application. */ - ui?: { ClerkUI?: ClerkUIConstructor | Promise }; + ui?: { + /** + * Pass the `ui` export from `@clerk/ui`. + */ + ClerkUI?: ClerkUIConstructor | Promise; + }; /** - * Optional object to style your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. + * An object to style your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ // TODO @nikos appearance?: any; /** - * Optional object to localize your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. + * An object to localize your components. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. */ localization?: LocalizationResource; + /** + * Indicates whether Clerk should poll against Clerk's backend every 5 minutes. + * @default true + */ polling?: boolean; /** * By default, the last signed-in session is used during client initialization. This option allows you to override that behavior, e.g. by selecting a specific session. */ selectInitialSession?: (client: ClientResource) => SignedInSessionResource | null; /** - * By default, ClerkJS is loaded with the assumption that cookies can be set (browser setup). On native platforms this value must be set to `false`. + * Indicates whether ClerkJS is loaded with the assumption that cookies can be set (browser setup). On native platforms this value must be set to `false`. */ standardBrowser?: boolean; /** - * Optional support email for display in authentication screens. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. + * The support email address for display in authentication screens. Will only affect [Clerk Components](https://clerk.com/docs/reference/components/overview) and not [Account Portal](https://clerk.com/docs/guides/account-portal/overview) pages. */ supportEmail?: string; /** - * By default, the [Clerk Frontend API `touch` endpoint](https://clerk.com/docs/reference/frontend-api/tag/Sessions#operation/touchSession) is called during page focus to keep the last active session alive. This option allows you to disable this behavior. + * By default, the [Clerk Frontend API `touch` endpoint](https://clerk.com/docs/reference/frontend-api/tag/Sessions#operation/touchSession){{ target: '_blank' }} is called during page focus to keep the last active session alive. This option allows you to disable this behavior. */ touchSession?: boolean; /** @@ -1229,19 +1352,19 @@ export type ClerkOptions = ClerkOptionsNavigation & */ signInUrl?: string; /** - * This URL will be used for any redirects that might happen and needs to point to your primary application on the client-side. This option is optional for production instances but **must be set for a satellite application in a development instance**. It's recommended to use [the environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. + * This URL will be used for any redirects that might happen and needs to point to your primary application on the client-side. This option is optional for production instances. **It is required to be set for a satellite application in a development instance**. It's recommended to use [the environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. */ signUpUrl?: string; /** - * An optional array of domains to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. + * An array of domains to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. */ allowedRedirectOrigins?: Array; /** - * An optional array of protocols to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. + * An array of protocols to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. */ allowedRedirectProtocols?: Array; /** - * This option defines that the application is a satellite application. + * Indicates whether the application is a satellite application. */ isSatellite?: boolean | ((url: URL) => boolean); /** @@ -1264,9 +1387,12 @@ export type ClerkOptions = ClerkOptionsNavigation & telemetry?: | false | { + /** + * If `true`, telemetry will not be collected. + */ disabled?: boolean; /** - * Telemetry events are only logged to the console and not sent to Clerk + * If `true`, telemetry events are only logged to the console and not sent to Clerk */ debug?: boolean; /** @@ -1343,11 +1469,21 @@ export type ClerkOptions = ClerkOptionsNavigation & taskUrls?: Partial>; }; +/** @inline */ export interface NavigateOptions { + /** + * If `true`, replace the current history entry instead of pushing a new one. + */ replace?: boolean; + /** + * Router metadata. + */ metadata?: RouterMetadata; } +/** + * @inline + */ export interface Resources { client: ClientResource; session?: SignedInSessionResource | null; @@ -1393,7 +1529,7 @@ type RouterFn = ( */ to: string, /** - * Optional metadata + * Metadata */ metadata?: { /** @@ -1463,13 +1599,9 @@ export type SetActiveParams = { redirectUrl?: string; /** - * A custom navigation function to be called just before the session and/or Organization is set. - * - * When provided, it takes precedence over the `redirectUrl` parameter for navigation. + * A custom navigation function to be called just before the session and/or Organization is set. When provided, it takes precedence over the `redirectUrl` parameter for navigation. * - * The callback receives a `decorateUrl` function that should be used to wrap destination URLs. - * This enables Safari ITP cookie refresh when needed. The decorated URL may be an external URL - * (starting with `https://`) that requires `window.location.href` instead of client-side navigation. + * The callback receives a `decorateUrl` function that should be used to wrap destination URLs. This enables Safari ITP cookie refresh when needed. The decorated URL may be an external URL (starting with `https://`) that requires `window.location.href` instead of client-side navigation. See the [section on using the `navigate()` parameter](https://clerk.com/docs/reference/objects/clerk#using-the-navigate-parameter) for more details. * * @example * ```typescript @@ -1504,6 +1636,7 @@ export type RoutingOptions = | { path: string | undefined; routing?: Extract } | { path?: never; routing?: Extract }; +/** @generateWithEmptyComment */ export type SignInProps = RoutingOptions & { /** * Full URL or path to navigate to after successful sign in. @@ -1531,9 +1664,7 @@ export type SignInProps = RoutingOptions & { */ signUpUrl?: string; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /** @@ -1570,10 +1701,12 @@ export type SignInProps = RoutingOptions & { SignUpFallbackRedirectUrl & AfterSignOutUrl; +/** + * @interface + */ export interface TransferableOption { /** - * Indicates whether or not sign in attempts are transferable to the sign up flow. - * When set to false, prevents opaque sign ups when a user attempts to sign in via OAuth with an email that doesn't exist. + * Indicates whether or not sign-in attempts are transferable to the sign-up flow. Defaults to `true`. When set to `false`, prevents [opaque sign-ups](!opaque-sign-up) when a user attempts to sign in via OAuth with an email that doesn't exist. * * @default true */ @@ -1615,9 +1748,7 @@ export type __internal_UserVerificationProps = RoutingOptions & { level?: SessionVerificationLevel; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; }; @@ -1656,6 +1787,7 @@ export type __internal_AttemptToEnableEnvironmentSettingResult = { type GoogleOneTapRedirectUrlProps = SignInForceRedirectUrl & SignUpForceRedirectUrl; +/** @generateWithEmptyComment */ export type GoogleOneTapProps = GoogleOneTapRedirectUrlProps & { /** * Whether to cancel the Google One Tap request if a user clicks outside the prompt. @@ -1678,9 +1810,13 @@ export type GoogleOneTapProps = GoogleOneTapRedirectUrlProps & { * @default true */ fedCmSupport?: boolean; + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; }; +/** @generateWithEmptyComment */ export type SignUpProps = RoutingOptions & { /** * Full URL or path to navigate to after successful sign up. @@ -1703,9 +1839,7 @@ export type SignUpProps = RoutingOptions & { */ signInUrl?: string; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; @@ -1747,11 +1881,10 @@ export type SignUpModalProps = WithoutRouting & { getContainer?: () => HTMLElement | null; }; +/** @generateWithEmptyComment */ export type UserProfileProps = RoutingOptions & { /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /* @@ -1796,6 +1929,7 @@ export type UserProfileModalProps = WithoutRouting & { getContainer?: () => HTMLElement | null; }; +/** @generateWithEmptyComment */ export type OrganizationProfileProps = RoutingOptions & { /** * Full URL or path to navigate to after the user leaves the currently Active Organization. @@ -1804,9 +1938,7 @@ export type OrganizationProfileProps = RoutingOptions & { */ afterLeaveOrganizationUrl?: string; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /* @@ -1846,6 +1978,7 @@ export type OrganizationProfileModalProps = WithoutRouting HTMLElement | null; }; +/** @generateWithEmptyComment */ export type CreateOrganizationProps = RoutingOptions & { /** * Full URL or path to navigate to after creating a new Organization. @@ -1863,13 +1996,12 @@ export type CreateOrganizationProps = RoutingOptions & { */ skipInvitationScreen?: boolean; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; }; +/** @generateWithEmptyComment */ export type CreateOrganizationModalProps = WithoutRouting & { /** * Function that returns the container element where portals should be rendered. @@ -1879,7 +2011,10 @@ export type CreateOrganizationModalProps = WithoutRouting HTMLElement | null; }; +/** @inline */ type UserProfileMode = 'modal' | 'navigation'; + +/** @generateWithEmptyComment */ type UserButtonProfileMode = | { userProfileUrl?: never; @@ -1921,9 +2056,7 @@ export type UserButtonProps = UserButtonProfileMode & { */ afterSwitchSessionUrl?: string; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; @@ -1940,6 +2073,9 @@ export type UserButtonProps = UserButtonProfileMode & { }; export type UserAvatarProps = { + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; rounded?: boolean; }; @@ -1958,6 +2094,7 @@ type CreateOrganizationMode = | { createOrganizationUrl: string; createOrganizationMode?: 'navigation' } | { createOrganizationUrl?: never; createOrganizationMode?: 'modal' }; +/** @generateWithEmptyComment */ export type OrganizationSwitcherProps = CreateOrganizationMode & OrganizationProfileMode & { /** @@ -2022,9 +2159,7 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & */ skipInvitationScreen?: boolean; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider(if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /* @@ -2034,6 +2169,7 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & organizationProfileProps?: Pick; }; +/** @generateWithEmptyComment */ export type OrganizationListProps = { /** * Full URL or path to navigate to after creating a new Organization. @@ -2053,9 +2189,7 @@ export type OrganizationListProps = { | ((organization: OrganizationResource) => string) | LooseExtractedParams>; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /** @@ -2083,15 +2217,14 @@ export type OrganizationListProps = { afterSelectPersonalUrl?: ((user: UserResource) => string) | LooseExtractedParams>; }; +/** @generateWithEmptyComment */ export type WaitlistProps = { /** * Full URL or path to navigate to after join waitlist. */ afterJoinWaitlistUrl?: string; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvided (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /** @@ -2100,6 +2233,7 @@ export type WaitlistProps = { signInUrl?: string; }; +/** @generateWithEmptyComment */ export type WaitlistModalProps = WaitlistProps & { /** * Function that returns the container element where portals should be rendered. @@ -2109,6 +2243,7 @@ export type WaitlistModalProps = WaitlistProps & { getContainer?: () => HTMLElement | null; }; +/** @generateWithEmptyComment */ type PricingTableDefaultProps = { /** * The position of the CTA button. @@ -2130,6 +2265,7 @@ type PricingTableDefaultProps = { newSubscriptionRedirectUrl?: string; }; +/** @generateWithEmptyComment */ type PricingTableBaseProps = { /** * The plan slug to highlight with a "Popular" badge. @@ -2143,9 +2279,7 @@ type PricingTableBaseProps = { */ for?: ForPayerType; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /* @@ -2157,8 +2291,10 @@ type PricingTableBaseProps = { type PortalRoot = HTMLElement | null | undefined; +/** @generateWithEmptyComment */ export type PricingTableProps = PricingTableBaseProps & PricingTableDefaultProps; +/** @generateWithEmptyComment */ export type APIKeysProps = { /** * The number of API keys to show per page. @@ -2167,9 +2303,7 @@ export type APIKeysProps = { */ perPage?: number; /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /** @@ -2182,9 +2316,7 @@ export type APIKeysProps = { export type ConfigureSSOProps = { /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; }; @@ -2192,20 +2324,47 @@ export type ConfigureSSOProps = { /** @deprecated Use `ConfigureSSOProps` instead. */ export type __experimental_ConfigureSSOProps = ConfigureSSOProps; +/** @generateWithEmptyComment */ export type GetAPIKeysParams = ClerkPaginationParams<{ + /** + * The user or organization ID to query API keys by. If not provided, defaults to the [Active Organization](!active-organization), then the current User. + */ subject?: string; + /** + * A search query to filter API keys by name. + */ query?: string; }>; +/** @generateWithEmptyComment */ export type CreateAPIKeyParams = { + /** + * The name of the API key. + */ name: string; + /** + * The user or organization ID to associate the API key with. If not provided, defaults to the [Active Organization](!active-organization), then the current User. + */ subject?: string; + /** + * The number of seconds until the API key expires. Set to `null` or omit to create a key that never expires. + */ secondsUntilExpiration?: number; + /** + * The description of the API key. + */ description?: string; }; +/** @generateWithEmptyComment */ export type RevokeAPIKeyParams = { + /** + * The ID of the API key to revoke. + */ apiKeyID: string; + /** + * The reason for revoking the API key. + */ revocationReason?: string; }; @@ -2213,6 +2372,9 @@ export type RevokeAPIKeyParams = { * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. */ export type __internal_CheckoutProps = { + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; planId?: string; planPeriod?: BillingSubscriptionPlanPeriod; @@ -2335,7 +2497,7 @@ export type __experimental_SubscriptionDetailsButtonProps = { export type OAuthConsentProps = { /** - * Customize the appearance of the component. + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. */ appearance?: ClerkAppearanceTheme; /** @@ -2399,20 +2561,19 @@ export type OAuthConsentProps = { /** @deprecated Use OAuthConsentProps instead. */ export type __internal_OAuthConsentProps = OAuthConsentProps; +/** @inline */ + export interface HandleEmailLinkVerificationParams { /** - * Full URL or path to navigate to after successful magic link verification - * on completed sign up or sign in on the same device. + * The full URL to navigate to after successful email link verification on completed sign-up or sign-in on the same device. */ redirectUrlComplete?: string; /** - * Full URL or path to navigate to after successful magic link verification - * on the same device, but not completed sign in or sign up. + * The full URL to navigate to after successful email link verification on the same device, but without completing sign-in or sign-up. */ redirectUrl?: string; /** - * Callback function to be executed after successful magic link - * verification on another device. + * Callback function to be executed after successful email link verification on another device. */ onVerifiedOnOtherDevice?: () => void; } @@ -2455,37 +2616,63 @@ export type SignUpButtonProps = (SignUpButtonPropsModal | ButtonPropsRedirect) & | 'oauthFlow' >; +/** @generateWithEmptyComment */ export type TaskChooseOrganizationProps = { /** * Full URL or path to navigate to after successfully resolving all tasks */ redirectUrlComplete: string; + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; }; +/** @generateWithEmptyComment */ export type TaskResetPasswordProps = { /** * Full URL or path to navigate to after successfully resolving all tasks */ redirectUrlComplete: string; + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; }; +/** @generateWithEmptyComment */ export type TaskSetupMFAProps = { /** * Full URL or path to navigate to after successfully resolving all tasks */ redirectUrlComplete: string; + /** + * Customization options to fully match the Clerk components to your own brand. These options serve as overrides and will be merged with the global `appearance` configuration (if one is provided). See the [`Appearance`](https://clerk.com/docs/guides/customizing-clerk/appearance-prop/overview) docs for more information. + */ appearance?: ClerkAppearanceTheme; }; +/** @generateWithEmptyComment */ export type CreateOrganizationInvitationParams = { + /** + * The email address of the user to invite. + */ emailAddress: string; + /** + * The role of the user to invite. + */ role: OrganizationCustomRoleKey; }; +/** @generateWithEmptyComment */ export type CreateBulkOrganizationInvitationParams = { + /** + * The email addresses of the users to invite. + */ emailAddresses: string[]; + /** + * The role of the users to invite. + */ role: OrganizationCustomRoleKey; }; @@ -2503,60 +2690,175 @@ export interface CreateOrganizationParams { slug?: string; } +/** @generateWithEmptyComment */ export interface ClerkAuthenticateWithWeb3Params { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * The strategy to use for the sign-in flow. + */ strategy: Web3Strategy; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; + /** + * The URL to navigate to if [second factor](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#multi-factor-authentication) is required. + */ secondFactorUrl?: string; + /** + * The name of the wallet to use for authentication. + */ walletName?: string; } +/** @generateWithEmptyComment */ export interface AuthenticateWithMetamaskParams { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; } +/** @generateWithEmptyComment */ export interface AuthenticateWithCoinbaseWalletParams { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; } +/** @generateWithEmptyComment */ export interface AuthenticateWithOKXWalletParams { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; } +/** @generateWithEmptyComment */ export interface AuthenticateWithGoogleOneTapParams { + /** + * The Google credential token from the Google Identity Services response. + */ token: string; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; } +/** @generateWithEmptyComment */ export interface AuthenticateWithBaseParams { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; } +/** @generateWithEmptyComment */ export interface AuthenticateWithSolanaParams { + /** + * A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + */ customNavigate?: (to: string) => Promise; + /** + * The full URL or path to navigate to after a successful sign-in or sign-up. + */ redirectUrl?: string; + /** + * The URL to navigate to if the sign-up process is missing user information. + */ signUpContinueUrl?: string; + /** + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + */ unsafeMetadata?: SignUpUnsafeMetadata; + /** + * A boolean indicating whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + */ legalAccepted?: boolean; + /** + * The name of the Solana wallet to use for authentication. + */ walletName: string; } @@ -2568,7 +2870,15 @@ export interface BrowserClerkConstructor { new (publishableKey: string, options?: DomainOrProxyUrl): BrowserClerk; } +/** + * Browser `Clerk` instance after `@clerk/clerk-js` loads. Extends [`Clerk`](https://clerk.com/docs/reference/objects/clerk) with `load()` and related browser-only APIs. + */ export interface HeadlessBrowserClerk extends Clerk { + /** + * Initializes the `Clerk` object and loads all necessary environment configuration and instance settings from the [Frontend API](https://clerk.com/docs/reference/frontend-api){{ target: '_blank' }}. + * + * When using the JavaScript SDK, you must call the `load()` method before using the `Clerk` object in your code. Refer to the [quickstart guide](https://clerk.com/docs/js-frontend/getting-started/quickstart) for more information. + */ load: (opts?: Without) => Promise; updateClient: (client: ClientResource) => void; } diff --git a/packages/shared/src/types/client.ts b/packages/shared/src/types/client.ts index 1c89ed554aa..aeae7ce8142 100644 --- a/packages/shared/src/types/client.ts +++ b/packages/shared/src/types/client.ts @@ -5,27 +5,102 @@ import type { SignInResource } from './signIn'; import type { SignUpResource } from './signUp'; import type { ClientJSONSnapshot } from './snapshots'; +/** + * The `Client` object keeps track of the authenticated sessions in the current device. The device can be a browser, a native application, or any other medium that is usually the requesting part in a request/response architecture. + * + * The `Client` object also holds information about any sign-in or sign-up attempts that might be in progress, tracking the sign-in or sign-up progress. + */ export interface ClientResource extends ClerkResource { + /** + * A list of sessions that have been created on this client. + */ sessions: SessionResource[]; + /** + * A list of sessions on this client where the user has completed the full sign-in flow. Sessions can be in one of the following states: + *
      + *
    • `"active"`: The user has completed the full sign-in flow and all pending tasks.
    • + *
    • `"pending"`: The user has completed the sign-in flow but still needs to complete one or more required steps (**pending tasks**).
    • + *
    + */ signedInSessions: SignedInSessionResource[]; + /** + * The current sign-up attempt. + */ signUp: SignUpResource; + /** + * The current sign-in attempt. + */ signIn: SignInResource; + /** + * Indicates whether this client hasn't been saved (created) yet in the Frontend API. + */ isNew: () => boolean; + /** + * Creates a new client for the current instance along with its cookie. + */ create: () => Promise; + /** + * Deletes the client. All sessions will be reset. + */ destroy: () => Promise; + /** + * Removes all sessions created on the client. + */ removeSessions: () => Promise; + /** + * Clears any locally cached session data for the current client. + */ clearCache: () => void; + /** + * Resets the current sign-in attempt. Clears the in-progress sign-in state on the client. + */ resetSignIn: () => void; + /** + * Resets the current sign-up attempt. Clears the in-progress sign-up state on the client. + */ resetSignUp: () => void; + /** + * Indicates whether the client cookie is due to expire in 8 days or less. + */ isEligibleForTouch: () => boolean; + /** + * Builds a URL that refreshes the current client's authentication state and then redirects the user to the specified URL. + * + * @param params - The URL to redirect the user to. + */ buildTouchUrl: (params: { redirectUrl: URL }) => string; + /** + * The ID of the last active [`Session`](https://clerk.com/docs/reference/objects/session) on this client. + */ lastActiveSessionId: string | null; - /** Last authentication strategy used by this client; `null` when unknown or feature disabled. */ + /** + * The last authentication strategy used by this client; `null` when unknown or feature disabled. + */ lastAuthenticationStrategy: LastAuthenticationStrategy | null; + /** + * Indicates whether CAPTCHA checks are skipped for this client. + */ captchaBypass: boolean; + /** + * The date and time when the client's authentication cookie will expire. + */ cookieExpiresAt: Date | null; + /** + * The date and time when the client was created. + */ createdAt: Date | null; + /** + * The date and time when the client was last updated. + */ updatedAt: Date | null; + /** + * Sends a CAPTCHA token to the client. + * @hidden + */ __internal_sendCaptchaToken: (params: unknown) => Promise; + /** + * Converts the client to a snapshot. + * @hidden + */ __internal_toSnapshot: () => ClientJSONSnapshot; } diff --git a/packages/shared/src/types/factors.ts b/packages/shared/src/types/factors.ts index 04aa639e87b..71088a89629 100644 --- a/packages/shared/src/types/factors.ts +++ b/packages/shared/src/types/factors.ts @@ -15,169 +15,378 @@ import type { Web3Strategy, } from './strategies'; +/** @generateWithEmptyComment */ export type EmailCodeFactor = { + /** + * The strategy type. + */ strategy: EmailCodeStrategy; + /** + * The ID of the email address used for the email code factor. + */ emailAddressId: string; + /** + * The identifier provided by the user, but masked for security reasons. + */ safeIdentifier: string; + /** + * Indicates whether the email address is set as the primary email address, as multiple can be added to a user's profile. + */ primary?: boolean; }; +/** @generateWithEmptyComment */ export type EmailLinkFactor = { + /** + * The strategy type. + */ strategy: EmailLinkStrategy; + /** + * The ID of the email address used for the email link factor. + */ emailAddressId: string; + /** + * The identifier provided by the user, but masked for security reasons. + */ safeIdentifier: string; + /** + * Indicates whether the email address is set as the primary email address, as multiple can be added to a user's profile. + */ primary?: boolean; }; +/** @generateWithEmptyComment */ export type PhoneCodeFactor = { + /** + * The strategy type. + */ strategy: PhoneCodeStrategy; + /** + * The ID of the phone number used for the phone code factor. + */ phoneNumberId: string; + /** + * The identifier provided by the user, but masked for security reasons. + */ safeIdentifier: string; + /** + * Indicates whether the phone number is set as the primary phone number, as multiple can be added to a user's profile. + */ primary?: boolean; + /** + * Indicates whether the phone number is set as the default identifier. + */ default?: boolean; + /** + * The channel used for the phone code factor. + */ channel?: PhoneCodeChannel; }; +/** @generateWithEmptyComment */ export type Web3SignatureFactor = { + /** + * The strategy type. + */ strategy: Web3Strategy; + /** + * The ID of the Web3 Wallet. + */ web3WalletId: string; + /** + * Indicates whether the Web3 Wallet is set as the primary Web3 Wallet, as multiple can be added to a user's profile. + */ primary?: boolean; + /** + * The name of the Web3 Wallet. + */ walletName?: string; }; +/** @inline */ export type PasswordFactor = { strategy: PasswordStrategy; }; +/** @inline */ export type PasskeyFactor = { strategy: PasskeyStrategy; }; +/** @inline */ export type OauthFactor = { strategy: OAuthStrategy; }; +/** @generateWithEmptyComment */ export type EnterpriseSSOFactor = { + /** + * The strategy type. + */ strategy: EnterpriseSSOStrategy; /** + * The ID of the enterprise connection. * @experimental */ enterpriseConnectionId?: string; /** + * The name of the enterprise connection. * @experimental */ enterpriseConnectionName?: string; }; +/** @inline */ export type TOTPFactor = { strategy: TOTPStrategy; }; +/** @inline */ export type BackupCodeFactor = { strategy: BackupCodeStrategy; }; +/** @generateWithEmptyComment */ export type ResetPasswordPhoneCodeFactor = { + /** + * The strategy type. + */ strategy: ResetPasswordPhoneCodeStrategy; + /** + * The ID of the phone number used for the reset password phone code factor. + */ phoneNumberId: string; + /** + * The identifier provided by the user, but masked for security reasons. + */ safeIdentifier: string; + /** + * Indicates whether the phone number is set as the primary phone number, as multiple can be added to a user's profile. + */ primary?: boolean; }; +/** @generateWithEmptyComment */ export type ResetPasswordEmailCodeFactor = { + /** + * The strategy type. + */ strategy: ResetPasswordEmailCodeStrategy; + /** + * The ID of the email address used for the reset password email code factor. + */ emailAddressId: string; + /** + * The identifier provided by the user, but masked for security reasons. + */ safeIdentifier: string; + /** + * Indicates whether the email address is set as the primary email address, as multiple can be added to a user's profile. + */ primary?: boolean; }; +/** @generateWithEmptyComment */ export type ResetPasswordCodeFactor = ResetPasswordEmailCodeFactor | ResetPasswordPhoneCodeFactor; +/** @generateWithEmptyComment */ export type ResetPasswordPhoneCodeFactorConfig = Omit; +/** @generateWithEmptyComment */ export type ResetPasswordEmailCodeFactorConfig = Omit; +/** @generateWithEmptyComment */ export type EmailCodeConfig = Omit; +/** @generateWithEmptyComment */ export type EmailLinkConfig = Omit & { + /** + * The URL to redirect to after the email link is clicked. + */ redirectUrl: string; }; +/** @generateWithEmptyComment */ export type PhoneCodeConfig = Omit; +/** @generateWithEmptyComment */ export type Web3SignatureConfig = Web3SignatureFactor; +/** @inline */ export type PassKeyConfig = PasskeyFactor; + +/** @generateWithEmptyComment */ export type OAuthConfig = OauthFactor & { + /** + * The URL to redirect to after the OAuth flow is completed. + */ redirectUrl: string; + /** @generateWithEmptyComment */ actionCompleteRedirectUrl: string; + /** + * The OIDC prompt parameter to use for the OAuth flow. + */ oidcPrompt?: string; + /** + * The OIDC login hint parameter to use for the OAuth flow. + */ oidcLoginHint?: string; }; +/** @generateWithEmptyComment */ export type EnterpriseSSOConfig = EnterpriseSSOFactor & { + /** + * The URL to redirect to after the OAuth flow is completed. + */ redirectUrl: string; + /** @generateWithEmptyComment */ actionCompleteRedirectUrl: string; + /** + * The OIDC prompt parameter to use for the OAuth flow. + */ oidcPrompt?: string; /** + * The ID of the email address used for the enterprise SSO factor. * @experimental */ emailAddressId?: string; /** + * The ID of the enterprise connection used for the enterprise SSO factor. * @experimental */ enterpriseConnectionId?: string; }; export type PhoneCodeSecondFactorConfig = { + /** + * The strategy type. + */ strategy: PhoneCodeStrategy; + /** + * The ID of the phone number used for the phone code second factor. + */ phoneNumberId?: string; }; export type EmailCodeSecondFactorConfig = { + /** + * The strategy type. + */ strategy: EmailCodeStrategy; + /** + * The ID of the email address used for the email code second factor. + */ emailAddressId?: string; }; +/** @generateWithEmptyComment */ export type EmailCodeAttempt = { + /** + * The strategy type. + */ strategy: EmailCodeStrategy; + /** + * The one-time code sent to the user's email. + */ code: string; }; +/** @generateWithEmptyComment */ export type PhoneCodeAttempt = { + /** + * The strategy type. + */ strategy: PhoneCodeStrategy; + /** + * The one-time code sent via SMS. + */ code: string; }; +/** @generateWithEmptyComment */ export type PasswordAttempt = { + /** + * The strategy type. + */ strategy: PasswordStrategy; + /** + * The user's password. + */ password: string; }; +/** @generateWithEmptyComment */ export type PasskeyAttempt = { + /** + * The strategy type. + */ strategy: PasskeyStrategy; + /** + * The Web Authentication assertion returned by the browser. + */ publicKeyCredential: PublicKeyCredentialWithAuthenticatorAssertionResponse; }; +/** @generateWithEmptyComment */ export type Web3Attempt = { + /** + * The strategy type. + */ strategy: Web3Strategy; + /** + * The signature of the Web3 transaction. + */ signature: string; }; +/** @generateWithEmptyComment */ export type TOTPAttempt = { + /** + * The strategy type. + */ strategy: TOTPStrategy; + /** + * The code generated by the authenticator app. + */ code: string; }; +/** @generateWithEmptyComment */ export type BackupCodeAttempt = { + /** + * The strategy type. + */ strategy: BackupCodeStrategy; + /** + * The backup code. + */ code: string; }; +/** @generateWithEmptyComment */ export type ResetPasswordPhoneCodeAttempt = { + /** + * The strategy type. + */ strategy: ResetPasswordPhoneCodeStrategy; + /** + * The one-time code sent via SMS. + */ code: string; + /** + * The password provided by the user. + */ password?: string; }; +/** @generateWithEmptyComment */ export type ResetPasswordEmailCodeAttempt = { + /** + * The strategy type. + */ strategy: ResetPasswordEmailCodeStrategy; + /** + * The one-time code sent to the user's email. + */ code: string; + /** + * The password provided by the user. + */ password?: string; }; diff --git a/packages/shared/src/types/hooks.ts b/packages/shared/src/types/hooks.ts index 3de88e8ef40..9e377663e44 100644 --- a/packages/shared/src/types/hooks.ts +++ b/packages/shared/src/types/hooks.ts @@ -26,11 +26,11 @@ type CheckAuthorizationSignedOut = CheckAuthorizationWithoutOrgOrUser; export type UseAuthReturn = | { /** - * A boolean that indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** - * A boolean that indicates whether a user is currently signed in. + * Indicates whether a user is currently signed in. */ isSignedIn: undefined; /** @@ -46,7 +46,7 @@ export type UseAuthReturn = */ sessionClaims: undefined; /** - * The JWT actor for the session. Holds identifier for the user that is impersonating the current user. Read more about [impersonation](https://clerk.com/docs/guides/users/impersonation). + * The JWT actor for the session. Read more about [impersonation](https://clerk.com/docs/guides/users/impersonation). */ actor: undefined; /** @@ -123,7 +123,7 @@ export type UseAuthReturn = export type UseSignInReturn = | { /** - * A boolean that indicates whether Clerk has completed initialization. Initially `false`, becomes `true` once Clerk loads. + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** @@ -147,7 +147,7 @@ export type UseSignInReturn = export type UseSignUpReturn = | { /** - * A boolean that indicates whether Clerk has completed initialization. Initially `false`, becomes `true` once Clerk loads. + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** @@ -171,11 +171,11 @@ export type UseSignUpReturn = export type UseSessionReturn = | { /** - * A boolean that indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** - * A boolean that indicates whether a user is currently signed in. + * Indicates whether a user is currently signed in. */ isSignedIn: undefined; /** @@ -200,7 +200,7 @@ export type UseSessionReturn = export type UseSessionListReturn = | { /** - * A boolean that indicates whether Clerk has completed initialization. Initially `false`, becomes `true` once Clerk loads. + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** @@ -224,11 +224,11 @@ export type UseSessionListReturn = export type UseUserReturn = | { /** - * A boolean that indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). + * Indicates whether Clerk has loaded the current authentication state. Initially `false`, becomes `true` once Clerk loads, and can revert to `false` while auth state is updating (for example, when switching organizations via [`setActive()`](https://clerk.com/docs/reference/objects/clerk#set-active)). */ isLoaded: false; /** - * A boolean that returns `true` if the user is signed in. + * Indicates whether the user is signed in. */ isSignedIn: undefined; /** diff --git a/packages/shared/src/types/identifiers.ts b/packages/shared/src/types/identifiers.ts index 0b1802f7130..9e967d7d43d 100644 --- a/packages/shared/src/types/identifiers.ts +++ b/packages/shared/src/types/identifiers.ts @@ -1,5 +1,10 @@ +/** @inline */ export type UsernameIdentifier = 'username'; +/** @inline */ export type EmailAddressIdentifier = 'email_address'; +/** @inline */ export type PhoneNumberIdentifier = 'phone_number'; +/** @inline */ export type Web3WalletIdentifier = 'web3_wallet'; +/** @inline */ export type EmailAddressOrPhoneNumberIdentifier = 'email_address_or_phone_number'; diff --git a/packages/shared/src/types/image.ts b/packages/shared/src/types/image.ts index 51b3c77fb61..b0ddd6e94be 100644 --- a/packages/shared/src/types/image.ts +++ b/packages/shared/src/types/image.ts @@ -1,7 +1,17 @@ import type { ClerkResource } from './resource'; +/** Represents information about an image. */ export interface ImageResource extends ClerkResource { + /** + * The unique identifier of the image. + */ id?: string; + /** + * The name of the image. + */ name: string | null; + /** + * The public URL of the image. + */ publicUrl: string | null; } diff --git a/packages/shared/src/types/instance.ts b/packages/shared/src/types/instance.ts index 617799635de..921926dd885 100644 --- a/packages/shared/src/types/instance.ts +++ b/packages/shared/src/types/instance.ts @@ -1 +1,4 @@ +/** + * @inline + */ export type InstanceType = 'production' | 'development'; diff --git a/packages/shared/src/types/jwtv2.ts b/packages/shared/src/types/jwtv2.ts index 1d8af24d979..7a93b63df01 100644 --- a/packages/shared/src/types/jwtv2.ts +++ b/packages/shared/src/types/jwtv2.ts @@ -197,7 +197,13 @@ export type ActClaimType = 'agent'; * @inline */ export interface ActClaim { + /** + * The identifier for the user that is impersonating the current user. + */ sub: string; + /** + * The type of the actor. + */ type?: ActClaimType; [x: string]: unknown; } diff --git a/packages/shared/src/types/multiDomain.ts b/packages/shared/src/types/multiDomain.ts index 3661e7132bf..83ef6b4487a 100644 --- a/packages/shared/src/types/multiDomain.ts +++ b/packages/shared/src/types/multiDomain.ts @@ -11,7 +11,7 @@ import type { ClerkOptions } from './clerk'; export type MultiDomainAndOrProxy = | { /** - * A boolean that indicates whether the application is a satellite application. + * Indicates whether the application is a satellite application. */ isSatellite?: never; /** @@ -37,7 +37,7 @@ export type MultiDomainAndOrProxy = export type MultiDomainAndOrProxyPrimitives = | { /** - * A boolean that indicates whether the application is a satellite application. + * Indicates whether the application is a satellite application. */ isSatellite?: never; /** @@ -60,13 +60,16 @@ export type MultiDomainAndOrProxyPrimitives = domain?: never; }; +/** + * If both `proxyUrl` and `domain` are set, the `proxyUrl` will be used. + */ export type DomainOrProxyUrl = { /** - * **Required for applications that run behind a reverse proxy**. The URL that Clerk will proxy requests to. Can be either a relative path (`/__clerk`) or a full URL (`https:///__clerk`). + * **Required for applications that run behind a reverse proxy**. The URL that Clerk will proxy requests to. Can be either a relative path (`/__clerk`) or a full URL (`https:///__clerk`), or a function that will be called with a `URL` made from `window.location.href`. */ proxyUrl?: string | ((url: URL) => string); /** - * **Required if your application is a satellite application**. Sets the domain of the satellite application. + * **Required if your application is a satellite application**. Sets the domain of the satellite application. Can be either a relative path (`/__clerk`) or a full URL (`https:///__clerk`), or a function that will be called with a `URL` made from `window.location.href`. */ domain?: string | ((url: URL) => string); }; diff --git a/packages/shared/src/types/oauth.ts b/packages/shared/src/types/oauth.ts index cf20b674495..83cd8c30e41 100644 --- a/packages/shared/src/types/oauth.ts +++ b/packages/shared/src/types/oauth.ts @@ -9,37 +9,68 @@ export interface OAuthProviderData { docsUrl: string; } +/** @inline */ export type FacebookOauthProvider = 'facebook'; +/** @inline */ export type GoogleOauthProvider = 'google'; +/** @inline */ export type HubspotOauthProvider = 'hubspot'; +/** @inline */ export type GithubOauthProvider = 'github'; +/** @inline */ export type TiktokOauthProvider = 'tiktok'; +/** @inline */ export type GitlabOauthProvider = 'gitlab'; +/** @inline */ export type DiscordOauthProvider = 'discord'; +/** @inline */ export type TwitterOauthProvider = 'twitter'; +/** @inline */ export type TwitchOauthProvider = 'twitch'; +/** @inline */ export type LinkedinOauthProvider = 'linkedin'; +/** @inline */ export type LinkedinOIDCOauthProvider = 'linkedin_oidc'; +/** @inline */ export type DropboxOauthProvider = 'dropbox'; +/** @inline */ export type AtlassianOauthProvider = 'atlassian'; +/** @inline */ export type BitbucketOauthProvider = 'bitbucket'; +/** @inline */ export type MicrosoftOauthProvider = 'microsoft'; +/** @inline */ export type NotionOauthProvider = 'notion'; +/** @inline */ export type AppleOauthProvider = 'apple'; +/** @inline */ export type LineOauthProvider = 'line'; +/** @inline */ export type InstagramOauthProvider = 'instagram'; +/** @inline */ export type CoinbaseOauthProvider = 'coinbase'; +/** @inline */ export type SpotifyOauthProvider = 'spotify'; +/** @inline */ export type XeroOauthProvider = 'xero'; +/** @inline */ export type BoxOauthProvider = 'box'; +/** @inline */ export type SlackOauthProvider = 'slack'; +/** @inline */ export type LinearOauthProvider = 'linear'; +/** @inline */ export type XOauthProvider = 'x'; +/** @inline */ export type EnstallOauthProvider = 'enstall'; +/** @inline */ export type HuggingfaceOAuthProvider = 'huggingface'; +/** @inline */ export type VercelOauthProvider = 'vercel'; +/** @inline */ export type CustomOauthProvider = `custom_${string}`; +/** Represents the available OAuth providers. */ export type OAuthProvider = | FacebookOauthProvider | GoogleOauthProvider diff --git a/packages/shared/src/types/organization.ts b/packages/shared/src/types/organization.ts index 81d123bcbaf..e3e78b512b0 100644 --- a/packages/shared/src/types/organization.ts +++ b/packages/shared/src/types/organization.ts @@ -48,33 +48,141 @@ declare global { * @interface */ export interface OrganizationResource extends ClerkResource, BillingPayerMethods { + /** + * The unique identifier for the Organization. + */ id: string; + /** + * The name of the Organization. + */ name: string; + /** + * The URL-friendly identifier of the Organization. If supplied, it must be unique for the instance. + */ slug: string | null; + /** + * Holds the Organization's logo. Compatible with Clerk's [Image Optimization](https://clerk.com/docs/guides/development/image-optimization). + */ imageUrl: string; + /** + * Whether the Organization has an image. + */ hasImage: boolean; + /** + * The number of members in the Organization. + */ membersCount: number; + /** + * The number of pending invitations in the Organization. + */ pendingInvitationsCount: number; + /** + * Metadata that can be read from both the [Frontend API](https://clerk.com/docs/reference/frontend-api){{ target: '_blank' }} and [Backend API](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }}, but can be set only from the Backend API. Once the user accepts the invitation and signs up, these metadata will end up in the user's public metadata. + */ publicMetadata: OrganizationPublicMetadata; + /** + * Whether the Organization allows admins to delete users. + */ adminDeleteEnabled: boolean; + /** + * The maximum number of memberships allowed in the Organization. + */ maxAllowedMemberships: number; + /** + * Whether the Organization allows self-serve SSO. + */ selfServeSSOEnabled: boolean; + /** + * The date when the Organization was first created. + */ createdAt: Date; + /** + * The date when the Organization was last updated. + */ updatedAt: Date; + /** + * Updates the current Organization. + */ update: (params: UpdateOrganizationParams) => Promise; + /** + * Gets the list of Organization Memberships. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationMembershipResource`](https://clerk.com/docs/reference/types/organization-membership) objects. + */ getMemberships: GetMemberships; + + /** + * Gets the list of invitations. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationInvitationResource`](https://clerk.com/docs/reference/types/organization-invitation) objects. + */ getInvitations: (params?: GetInvitationsParams) => Promise>; + /** + * Gets the list of [Roles](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) available. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`RoleResource`](https://clerk.com/docs/reference/types/role-resource) objects and a `has_role_set_migration` status. + * + * When `has_role_set_migration` is `true`, updating Organization membership Roles is not allowed. Learn how to [build a custom flow for managing member Roles in an Organization](/docs/guides/development/custom-flows/organizations/manage-roles). + */ getRoles: (params?: GetRolesParams) => Promise; + /** + * Gets the list of domains. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationDomainResource`](https://clerk.com/docs/reference/types/organization-domain-resource) objects. + * + * > [!WARNING] + * > You must have [**Verified domains**](https://clerk.com/docs/guides/organizations/add-members/verified-domains) enabled in your app's settings in the Clerk Dashboard. + */ getDomains: (params?: GetDomainsParams) => Promise>; + /** + * Gets the list of membership requests. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationMembershipRequestResource`](https://clerk.com/docs/reference/types/organization-membership-request) objects. + * + * > [!WARNING] + * > You must have [**Verified domains** and **Automatic suggestion**](https://clerk.com/docs/guides/organizations/add-members/verified-domains) enabled in your app's settings in the Clerk Dashboard. + */ getMembershipRequests: ( params?: GetMembershipRequestParams, ) => Promise>; + /** + * Adds a user as a member to an organization. A user can only be added to an organization if they are not already a member of it and if they already exist in the same instance as the organization. Only administrators can add members to an organization. + * @returns An [`OrganizationMembershipResource`](https://clerk.com/docs/reference/types/organization-membership) object. + */ addMember: (params: AddMemberParams) => Promise; + /** + * Creates and sends an invitation to the given email address. + * @returns An [`OrganizationInvitationResource`](https://clerk.com/docs/reference/types/organization-invitation) object. + */ inviteMember: (params: InviteMemberParams) => Promise; + /** + * Creates and sends invitations to the given email addresses. + * @returns An array of [`OrganizationInvitationResource`](https://clerk.com/docs/reference/types/organization-invitation) objects. + */ inviteMembers: (params: InviteMembersParams) => Promise; + /** + * Updates a given member. + * @returns An [`OrganizationMembershipResource`](https://clerk.com/docs/reference/types/organization-membership) object. + */ updateMember: (params: UpdateMembershipParams) => Promise; + /** + * Removes a member. + * @returns An [`OrganizationMembershipResource`](https://clerk.com/docs/reference/types/organization-membership) object. + * @param userId - The unique identifier of the user to remove. + */ removeMember: (userId: string) => Promise; + /** + * Creates a new domain. + * @returns An [`OrganizationDomainResource`](https://clerk.com/docs/reference/types/organization-domain-resource) object. + * + * > [!WARNING] + * > You must have [**Verified domains**](https://clerk.com/docs/guides/organizations/add-members/verified-domains) enabled in your app's settings in the Clerk Dashboard. + * @param domainName - The name of the domain to create. + */ createDomain: (domainName: string) => Promise; + /** + * Gets a domain for an Organization based on the given domain ID. + * @returns An [`OrganizationDomainResource`](https://clerk.com/docs/reference/types/organization-domain-resource) object. + * + * > [!WARNING] + * > You must have [**Verified domains**](https://clerk.com/docs/guides/organizations/add-members/verified-domains) enabled in your app's settings in the Clerk Dashboard. + * @param domainId - The unique identifier of the domain to get. + */ getDomain: ({ domainId }: { domainId: string }) => Promise; getEnterpriseConnections: (params?: GetEnterpriseConnectionsParams) => Promise; createEnterpriseConnection: ( @@ -92,63 +200,131 @@ export interface OrganizationResource extends ClerkResource, BillingPayerMethods enterpriseConnectionId: string, params?: GetEnterpriseConnectionTestRunsParams, ) => Promise>; + /** + * Deletes the Organization. Only administrators can delete an Organization. + * + * Deleting an Organization will also delete all memberships and invitations. **This is not reversible.** + */ destroy: () => Promise; + /** + * Sets or replaces an Organization's logo. + */ setLogo: (params: SetOrganizationLogoParams) => Promise; __internal_toSnapshot: () => OrganizationJSONSnapshot; } +/** @generateWithEmptyComment */ export type GetRolesParams = ClerkPaginationParams; export interface GetRolesResponse extends ClerkPaginatedResponse { has_role_set_migration?: boolean; } +/** @generateWithEmptyComment */ export type GetMembersParams = ClerkPaginationParams<{ + /** + * The [Role](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) to filter the users by. + */ role?: OrganizationCustomRoleKey[]; + /** + * The query to filter the users by. + */ query?: string; }>; +/** @generateWithEmptyComment */ export type GetDomainsParams = ClerkPaginationParams<{ + /** + * The [enrollment mode](https://clerk.com/docs/guides/organizations/add-members/verified-domains#enable-verified-domains) will decide how new users join an organization. + */ enrollmentMode?: OrganizationEnrollmentMode; }>; +/** @generateWithEmptyComment */ export type GetInvitationsParams = ClerkPaginationParams<{ + /** + * The status of the invitations to get. + */ status?: OrganizationInvitationStatus[]; }>; +/** @generateWithEmptyComment */ export type GetMembershipRequestParams = ClerkPaginationParams<{ + /** + * The status of the membership requests to get. + */ status?: OrganizationInvitationStatus; }>; +/** @generateWithEmptyComment */ export interface AddMemberParams { + /** + * The unique identifier of the user to add as a member. + */ userId: string; + /** + * The [Role](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) that will be assigned to the user. + */ role: OrganizationCustomRoleKey; } +/** @generateWithEmptyComment */ export interface InviteMemberParams { + /** + * The email address of the user to invite. + */ emailAddress: string; + /** + * The [Role](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) that will be assigned to the user. + */ role: OrganizationCustomRoleKey; } +/** @generateWithEmptyComment */ export interface InviteMembersParams { + /** + * The email addresses of the users to invite. + */ emailAddresses: string[]; + /** + * The [Role](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) that will be assigned to the users. + */ role: OrganizationCustomRoleKey; } +/** @generateWithEmptyComment */ export interface UpdateMembershipParams { + /** + * The unique identifier of the user to update. + */ userId: string; + /** + * The [Role](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions) that will be assigned to the user. + */ role: OrganizationCustomRoleKey; } +/** @generateWithEmptyComment */ export interface UpdateOrganizationParams { + /** + * The name of the Organization. + */ name: string; + /** + * The URL-friendly identifier of the Organization. If supplied, it must be unique for the instance. + */ slug?: string; } +/** @generateWithEmptyComment */ export interface SetOrganizationLogoParams { + /** + * The file to set as the Organization's logo. The file must be an image and its size cannot exceed 10MB. + */ file: Blob | File | string | null; } +/** @generateWithEmptyComment */ export type GetMemberships = ( params?: GetMembersParams, ) => Promise>; diff --git a/packages/shared/src/types/organizationDomain.ts b/packages/shared/src/types/organizationDomain.ts index 86b845a1aa7..c64f4e196ba 100644 --- a/packages/shared/src/types/organizationDomain.ts +++ b/packages/shared/src/types/organizationDomain.ts @@ -7,14 +7,10 @@ export interface OrganizationDomainVerification { expiresAt: Date; } -/** - * @inline - */ +/** @inline */ export type OrganizationDomainVerificationStatus = 'unverified' | 'verified'; -/** - * @inline - */ +/** @inline */ export type OrganizationEnrollmentMode = 'manual_invitation' | 'automatic_invitation' | 'automatic_suggestion'; /** diff --git a/packages/shared/src/types/organizationInvitation.ts b/packages/shared/src/types/organizationInvitation.ts index 61581a28e37..0027efc929b 100644 --- a/packages/shared/src/types/organizationInvitation.ts +++ b/packages/shared/src/types/organizationInvitation.ts @@ -34,7 +34,5 @@ export interface OrganizationInvitationResource extends ClerkResource { revoke: () => Promise; } -/** - * @inline - */ +/** @inline */ export type OrganizationInvitationStatus = 'pending' | 'accepted' | 'revoked' | 'expired'; diff --git a/packages/shared/src/types/phoneCodeChannel.ts b/packages/shared/src/types/phoneCodeChannel.ts index 516e9e57324..e75163d79c6 100644 --- a/packages/shared/src/types/phoneCodeChannel.ts +++ b/packages/shared/src/types/phoneCodeChannel.ts @@ -3,8 +3,13 @@ export interface PhoneCodeChannelData { name: string; } +/** @inline */ export type PhoneCodeSMSChannel = 'sms'; +/** @inline */ export type PhoneCodeWhatsAppChannel = 'whatsapp'; +/** @inline */ export type PhoneCodeChannel = PhoneCodeSMSChannel | PhoneCodeWhatsAppChannel; + +/** @inline */ export type PhoneCodeProvider = PhoneCodeChannel; diff --git a/packages/shared/src/types/redirects.ts b/packages/shared/src/types/redirects.ts index bafcdf1db63..83b1ba61327 100644 --- a/packages/shared/src/types/redirects.ts +++ b/packages/shared/src/types/redirects.ts @@ -1,12 +1,14 @@ import type { EnterpriseSSOStrategy, OAuthStrategy } from './strategies'; +/** @generateWithEmptyComment */ export type AfterSignOutUrl = { /** - * Full URL or path to navigate to after successful sign out. + * The full URL or path to navigate to after successful sign out. */ afterSignOutUrl?: string | null; }; +/** @generateWithEmptyComment */ export type AfterMultiSessionSingleSignOutUrl = { /** * The full URL or path to navigate to after signing out the current user is complete. @@ -17,7 +19,6 @@ export type AfterMultiSessionSingleSignOutUrl = { /** * Redirect URLs for different actions. - * Mainly used to be used to type internal Clerk functions. */ export type RedirectOptions = SignInForceRedirectUrl & SignInFallbackRedirectUrl & @@ -25,6 +26,7 @@ export type RedirectOptions = SignInForceRedirectUrl & SignUpFallbackRedirectUrl & RedirectUrlProp; +/** @generateWithEmptyComment */ export type AuthenticateWithRedirectParams = { /** * The full URL or path to the route that will complete the OAuth or SAML flow. @@ -82,6 +84,7 @@ export type AuthenticateWithRedirectParams = { export type AuthenticateWithPopupParams = AuthenticateWithRedirectParams & { popup: Window | null }; +/** @generateWithEmptyComment */ export type RedirectUrlProp = { /** * Full URL or path to navigate to after a successful action. @@ -89,13 +92,15 @@ export type RedirectUrlProp = { redirectUrl?: string | null; }; +/** @generateWithEmptyComment */ export type SignUpForceRedirectUrl = { /** - * This URL will always be redirected to after the user signs up. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. + * If provided, this URL will always be redirected to after the user signs up. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. */ signUpForceRedirectUrl?: string | null; }; +/** @generateWithEmptyComment */ export type SignUpFallbackRedirectUrl = { /** * The fallback URL to redirect to after the user signs up, if there's no `redirect_url` in the path already. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. @@ -105,6 +110,7 @@ export type SignUpFallbackRedirectUrl = { signUpFallbackRedirectUrl?: string | null; }; +/** @generateWithEmptyComment */ export type SignInFallbackRedirectUrl = { /** * The fallback URL to redirect to after the user signs in, if there's no `redirect_url` in the path already. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. @@ -114,16 +120,18 @@ export type SignInFallbackRedirectUrl = { signInFallbackRedirectUrl?: string | null; }; +/** @generateWithEmptyComment */ export type SignInForceRedirectUrl = { /** - * This URL will always be redirected to after the user signs in. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. + * If provided, this URL will always be redirected to after the user signs in. It's recommended to use the [environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. */ signInForceRedirectUrl?: string | null; }; +/** @generateWithEmptyComment */ export type NewSubscriptionRedirectUrl = { /** - * The URL to navigate to after the user completes the checkout and clicks the "Continue" button. + * The full URL or path to navigate to after the user completes the checkout and clicks the "Continue" button. */ newSubscriptionRedirectUrl?: string | null; }; diff --git a/packages/shared/src/types/resource.ts b/packages/shared/src/types/resource.ts index 140af2e7fe2..3a98d7c956a 100644 --- a/packages/shared/src/types/resource.ts +++ b/packages/shared/src/types/resource.ts @@ -1,4 +1,8 @@ +/** @generateWithEmptyComment */ export type ClerkResourceReloadParams = { + /** + * A nonce to use for rotating the user's token. Used in native application OAuth flows to allow the native client to update its JWT once despite changes in its rotating token. + */ rotatingTokenNonce?: string; }; @@ -10,12 +14,9 @@ export interface ClerkResource { * The unique identifier of the resource. */ readonly id?: string | undefined; - /** - * The root path of the resource. - */ pathRoot: string; /** - * Reload the resource and return the resource itself. + * Reloads the resource, which is useful when you want to access the latest user data after performing a mutation. To make the updated data immediately available, this method forces a session token refresh instead of waiting for the automatic refresh cycle that could temporarily retain stale information. Learn more about [forcing a token refresh](https://clerk.com/docs/guides/sessions/force-token-refresh). */ reload(p?: ClerkResourceReloadParams): Promise; } diff --git a/packages/shared/src/types/session.ts b/packages/shared/src/types/session.ts index a512fc2baf9..ce38f9f7e26 100644 --- a/packages/shared/src/types/session.ts +++ b/packages/shared/src/types/session.ts @@ -35,7 +35,7 @@ import type { Autocomplete } from './utils'; */ export type PendingSessionOptions = { /** - * A boolean that indicates whether pending sessions are considered as signed out or not. + * Indicates whether pending sessions are considered as signed out or not. * * @default true */ @@ -100,6 +100,7 @@ export type CheckAuthorizationParamsWithCustomPermissions = WithReverification< | { role?: never; permission?: never; feature?: never; plan?: never } >; +/** @generateWithEmptyComment */ export type CheckAuthorization = CheckAuthorizationFn; type CheckAuthorizationParams = WithReverification< @@ -217,49 +218,133 @@ export interface SessionResource extends ClerkResource { * The current state of the session. */ status: SessionStatus; + /** + * The date and time when the session will expire. + */ expireAt: Date; + /** + * The date and time when the session was abandoned by the user. + */ abandonAt: Date; /** * An array where each item represents the number of minutes since the last verification of a first or second factor: `[firstFactorAge, secondFactorAge]`. */ factorVerificationAge: [firstFactorAge: number, secondFactorAge: number] | null; + /** + * The token that was last used to authenticate the session. + */ lastActiveToken: TokenResource | null; + /** + * The ID of the last [Active Organization](!active-organization). + */ lastActiveOrganizationId: string | null; + /** + * The date and time when the session was last active on the [`Client`](https://clerk.com/docs/reference/objects/client). + */ lastActiveAt: Date; + /** + * The JWT actor for the session. Holds identifier for the user that is impersonating the current user. Read more about [impersonation](https://clerk.com/docs/guides/users/impersonation). + */ actor: ActClaim | null; + /** + * When the session's actor claim has `type: 'agent'`, this property exposes information about the agent and [Agent Task](https://clerk.com/docs/reference/objects/agent-task) that was used to create the session. + */ agent: AgentActClaim | null; + /** + * The user's pending [session tasks](https://clerk.com/docs/guides/configure/session-tasks). + */ tasks: Array | null; + /** + * The user's current pending [session task](https://clerk.com/docs/guides/configure/session-tasks). + */ currentTask?: SessionTask; /** - * The user associated with the session. + * The [`User`](https://clerk.com/docs/reference/objects/user) associated with the session. */ user: UserResource | null; + /** + * Publicly available information about the current [`User`](https://clerk.com/docs/reference/objects/user). + */ publicUserData: PublicUserData; + /** * Marks the session as ended. The session will no longer be active for this `Client` and its status will become **ended**. */ end: () => Promise; + /** + * Invalidates the current session by marking it as removed. Once removed, the session will be deactivated for the current Client instance and its `status` will be set to `removed`. This operation cannot be undone. + */ remove: () => Promise; + /** + * Updates the session's last active timestamp to the current time. This method should be called periodically to indicate ongoing user activity and prevent the session from becoming stale. The updated timestamp is used for session management and analytics purposes. + */ touch: (params?: SessionTouchParams) => Promise; + /** + * Gets the current user's [session token](https://clerk.com/docs/guides/sessions/session-tokens) or a [custom JWT template](https://clerk.com/docs/guides/sessions/jwt-templates). + * + * This method uses a cache so a network request will only be made if the token in memory has expired. The TTL for a Clerk token is one minute. It retries on transient failures (e.g. network errors); when the browser is offline and retries are exhausted, it throws `ClerkOfflineError`. + * + * Tokens can only be generated if the user is signed in. + */ getToken: GetToken; + /** + * Checks if the user is [authorized for the specified Role, Permission, Feature, or Plan](https://clerk.com/docs/guides/secure/authorization-checks) or requires the user to [reverify their credentials](https://clerk.com/docs/guides/secure/reverification) if their last verification is older than allowed. + * @skipParametersSection + */ checkAuthorization: CheckAuthorization; + /** + * Clears the cache for the current session. This is useful if the session has been updated and the cache is no longer valid. + */ clearCache: () => void; + /** + * The date and time when the session was first created. + */ createdAt: Date; + /** + * The date and time when the session was last updated. + */ updatedAt: Date; - + /** + * Initiates the reverification flow. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + */ startVerification: (params: SessionVerifyCreateParams) => Promise; + /** + * Initiates the [first factor verification](!first-factor-verification) process. This is a required step to complete a reverification flow when using a preparable factor. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + * @skipParametersSection + */ prepareFirstFactorVerification: ( factor: SessionVerifyPrepareFirstFactorParams, ) => Promise; + /** + * Attempts to complete the [first factor verification](!first-factor-verification) process. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + * @skipParametersSection + */ attemptFirstFactorVerification: ( attemptFactor: SessionVerifyAttemptFirstFactorParams, ) => Promise; + /** + * Initiates the [second factor verification](!second-factor-verification) process. This is a required step to complete a reverification flow when using a preparable factor. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + * @skipParametersSection + */ prepareSecondFactorVerification: ( params: SessionVerifyPrepareSecondFactorParams, ) => Promise; + /** + * Attempts to complete the [second factor verification](!second-factor-verification) process. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + * @skipParametersSection + */ attemptSecondFactorVerification: ( params: SessionVerifyAttemptSecondFactorParams, ) => Promise; + /** + * Initiates a verification flow using passkeys. + * @returns A [`SessionVerification`](https://clerk.com/docs/reference/types/session-verification) instance with its status and supported factors. + */ verifyWithPasskey: () => Promise; __internal_toSnapshot: () => SessionJSONSnapshot; __internal_touch: (params?: SessionTouchParams) => Promise; @@ -312,30 +397,89 @@ export interface SessionActivity { isMobile?: boolean; } +/** + * The current state of the session. + */ export type SessionStatus = + /** + * The session was abandoned client-side. + */ | 'abandoned' + /** + * The session is valid and all activity is allowed. + */ | 'active' + /** + * The user signed out of the session, but the [`Session`](https://clerk.com/docs/reference/objects/session) remains in the [`Client`](https://clerk.com/docs/reference/objects/client). + */ | 'ended' + /** + * The period of allowed activity for this session has passed. + */ | 'expired' + /** + * The user signed out of the session and the [`Session`](https://clerk.com/docs/reference/objects/session) was removed from the [`Client`](https://clerk.com/docs/reference/objects/client). + */ | 'removed' + /** + * The session has been replaced by another one, but the previous [`Session`](https://clerk.com/docs/reference/objects/session) remains in the [`Client`](https://clerk.com/docs/reference/objects/client). + */ | 'replaced' + /** + * The application ended the session and the [`Session`](https://clerk.com/docs/reference/objects/session) was removed from the [`Client`](https://clerk.com/docs/reference/objects/client). + */ | 'revoked' + /** + * The user has signed in but hasn't completed [session tasks](https://clerk.com/docs/guides/configure/session-tasks). + */ | 'pending'; +/** @inline */ export type SessionTouchIntent = 'focus' | 'select_session' | 'select_org'; +/** @generateWithEmptyComment */ export type SessionTouchParams = { + /** + * The intent of the touch operation. + */ intent?: SessionTouchIntent; }; +/** + * Information about the user that's publicly available. + */ export interface PublicUserData { + /** + * The user's first name. + */ firstName: string | null; + /** + * The user's last name. + */ lastName: string | null; + /** + * Holds the default avatar or user's uploaded profile image. Compatible with Clerk's [Image Optimization](https://clerk.com/docs/guides/development/image-optimization). + */ imageUrl: string; + /** + * Indicates whether the user has a profile picture. + */ hasImage: boolean; + /** + * The user's identifier, such as their email address or phone number. Can be used for user identification. + */ identifier: string; + /** + * The user's unique identifier. + */ userId?: string; + /** + * The user's username. + */ username?: string; + /** + * Indicates whether the user is banned. + */ banned?: boolean; } @@ -349,9 +493,19 @@ export interface SessionTask { key: 'choose-organization' | 'reset-password' | 'setup-mfa'; } +/** @generateWithEmptyComment */ export type GetTokenOptions = { + /** + * The Organization associated with the generated session token. _Does not modify the session's currently [Active Organization](!active-organization)._ + */ organizationId?: string; + /** + * Whether to skip the cache lookup and force a call to the server instead, even within the TTL. Useful if the token claims are time-sensitive or depend on data that can be updated (e.g. user fields). Defaults to `false`. + */ skipCache?: boolean; + /** + * The name of the JWT template from the [Clerk Dashboard](https://dashboard.clerk.com/~/jwt-templates) to generate a new token from. E.g. 'firebase', 'grafbase', or your custom template's name. + */ template?: string; }; /** @@ -359,7 +513,11 @@ export type GetTokenOptions = { */ export type GetToken = (options?: GetTokenOptions) => Promise; +/** @generateWithEmptyComment */ export type SessionVerifyCreateParams = { + /** + * The level of the verification to create. + */ level: SessionVerificationLevel; }; @@ -371,6 +529,7 @@ export type SessionVerifyPrepareFirstFactorParams = * @experimental */ | Omit; + export type SessionVerifyAttemptFirstFactorParams = | EmailCodeAttempt | PhoneCodeAttempt diff --git a/packages/shared/src/types/signInFuture.ts b/packages/shared/src/types/signInFuture.ts index b320d3afcf7..3bb6798c6c8 100644 --- a/packages/shared/src/types/signInFuture.ts +++ b/packages/shared/src/types/signInFuture.ts @@ -6,20 +6,18 @@ import type { OAuthStrategy, PasskeyStrategy, TicketStrategy, Web3Strategy } fro import type { VerificationResource } from './verification'; import type { Web3Provider } from './web3'; +/** @generateWithEmptyComment */ export interface SignInFutureCreateParams { /** - * The authentication identifier for the sign-in. This can be the value of the user's email address, phone number, - * username, or Web3 wallet address. + * The authentication identifier for the sign-in. This can be the value of the user's email address, phone number, username, or Web3 wallet address. */ identifier?: string; /** - * The user's password. Only supported if - * [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled. + * The user's password. Only supported if [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled. */ password?: string; /** - * The first factor verification strategy to use in the sign-in flow. Depends on the `identifier` value. Each - * authentication identifier supports different verification strategies. + * The first factor verification strategy to use in the sign-in flow. Depends on the `identifier` value. Each authentication identifier supports different verification strategies. */ strategy?: OAuthStrategy | 'enterprise_sso' | PasskeyStrategy | TicketStrategy; /** @@ -27,28 +25,24 @@ export interface SignInFutureCreateParams { */ redirectUrl?: string; /** - * The URL that the user will be redirected to, after successful authorization from the OAuth provider and - * Clerk sign-in. + * The URL that the user will be redirected to, after successful authorization from the OAuth provider and Clerk sign-in. */ actionCompleteRedirectUrl?: string; /** - * When set to `true`, the `SignIn` will attempt to retrieve information from the active `SignUp` instance and use it - * to complete the sign-in process. This is useful when you want to seamlessly transition a user from a sign-up - * attempt to a sign-in attempt. + * When set to `true`, the `SignIn` will attempt to retrieve information from the active `SignUp` instance and use it to complete the sign-in process. This is useful when you want to seamlessly transition a user from a sign-up attempt to a sign-in attempt. */ transfer?: boolean; /** - * The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) - * generated from the Backend API. **Required** if `strategy` is set to `'ticket'`. + * **Required** if `strategy` is set to `'ticket'`. The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) generated from the Backend API. */ ticket?: string; /** - * When set to `true`, if a user does not exist, the sign-up will prepare a transfer to sign up a new - * account. If bot sign-up protection is enabled, captcha will also be required on sign in. + * When set to `true`, if a user does not exist, the sign-up will prepare a transfer to sign up a new account. If bot sign-up protection is enabled, captcha will also be required on sign in. */ signUpIfMissing?: boolean; } +/** Parameters for submitting a password to sign-in. */ export type SignInFuturePasswordParams = { /** * The user's password. Only supported if @@ -58,8 +52,7 @@ export type SignInFuturePasswordParams = { } & ( | { /** - * The authentication identifier for the sign-in. This can be the value of the user's email address, phone number, - * username, or Web3 wallet address. + * The authentication identifier for the sign-in (email address, phone number, username, or Web3 wallet address). Provide exactly one of `identifier`, `emailAddress`, or `phoneNumber`. Omit all when a sign-in already exists to use the current identifier. */ identifier: string; emailAddress?: never; @@ -67,8 +60,7 @@ export type SignInFuturePasswordParams = { } | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled. Provide exactly one of `identifier`, `emailAddress`, or `phoneNumber`. */ emailAddress: string; identifier?: never; @@ -76,8 +68,7 @@ export type SignInFuturePasswordParams = { } | { /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. Provide exactly one of `identifier`, `emailAddress`, or `phoneNumber`. */ phoneNumber: string; identifier?: never; @@ -90,23 +81,25 @@ export type SignInFuturePasswordParams = { } ); +/** Parameters for sending a sign-in email verification code. */ export type SignInFutureEmailCodeSendParams = | { /** * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. + * is enabled. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. */ emailAddress?: string; emailAddressId?: never; } | { /** - * The ID for the user's email address that will receive an email with the one-time authentication code. + * The ID for the user's email address that will receive an email with the one-time authentication code. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. */ emailAddressId?: string; emailAddress?: never; }; +/** Parameters for sending a sign-in email link. */ export type SignInFutureEmailLinkSendParams = { /** * The full URL that the user will be redirected to when they visit the email link. @@ -115,21 +108,21 @@ export type SignInFutureEmailLinkSendParams = { } & ( | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. */ emailAddress?: string; emailAddressId?: never; } | { /** - * The ID for the user's email address that will receive an email with the email link. + * The ID for the user's email address that will receive an email with the email link. Provide either `emailAddress` or `emailAddressId`, not both. Omit both when a sign-in already exists. */ emailAddressId?: string; emailAddress?: never; } ); +/** @generateWithEmptyComment */ export interface SignInFutureEmailCodeVerifyParams { /** * The one-time code that was sent to the user. @@ -137,6 +130,7 @@ export interface SignInFutureEmailCodeVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureResetPasswordSubmitParams { /** * The new password for the user. @@ -148,6 +142,7 @@ export interface SignInFutureResetPasswordSubmitParams { signOutOfOtherSessions?: boolean; } +/** @generateWithEmptyComment */ export interface SignInFutureResetPasswordPhoneCodeSendParams { /** * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if @@ -156,6 +151,7 @@ export interface SignInFutureResetPasswordPhoneCodeSendParams { phoneNumber?: string; } +/** @generateWithEmptyComment */ export type SignInFuturePhoneCodeSendParams = { /** * The mechanism to use to send the code to the provided phone number. Defaults to `'sms'`. @@ -164,21 +160,21 @@ export type SignInFuturePhoneCodeSendParams = { } & ( | { /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. Provide either `phoneNumber` or `phoneNumberId`, not both. Omit both when a sign-in already exists. */ phoneNumber?: string; phoneNumberId?: never; } | { /** - * The ID for the user's phone number that will receive a message with the one-time authentication code. + * The ID for the user's phone number that will receive a message with the one-time authentication code. Provide either `phoneNumber` or `phoneNumberId`, not both. Omit both when a sign-in already exists. */ phoneNumberId: string; phoneNumber?: never; } ); +/** @generateWithEmptyComment */ export interface SignInFuturePhoneCodeVerifyParams { /** * The one-time code that was sent to the user. @@ -186,6 +182,7 @@ export interface SignInFuturePhoneCodeVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureResetPasswordPhoneCodeVerifyParams { /** * The one-time code that was sent to the user. @@ -193,6 +190,7 @@ export interface SignInFutureResetPasswordPhoneCodeVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureSSOParams { /** * The strategy to use for authentication. @@ -203,12 +201,12 @@ export interface SignInFutureSSOParams { */ redirectUrl: string; /** + * The URL to redirect to if a session was not created, and needs additional information. * TODO @revamp-hooks: This should be handled by FAPI instead. */ redirectCallbackUrl: string; /** - * If provided, a `Window` to use for the OAuth flow. Useful in instances where you cannot navigate to an - * OAuth provider. + * If provided, a `Window` to use for the OAuth flow. Useful in instances where you cannot navigate to an OAuth provider. * * @example * ```ts @@ -221,12 +219,11 @@ export interface SignInFutureSSOParams { */ popup?: Window; /** - * Optional for `oauth_` or `enterprise_sso` strategies. The value to pass to the - * [OIDC prompt parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=prompt,reauthentication%20and%20consent.) - * in the generated OAuth redirect URL. + * The value to pass to the [OIDC prompt parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=prompt,reauthentication%20and%20consent.) in the generated OAuth redirect URL. */ oidcPrompt?: string; /** + * The identifier of the enterprise connection to target when using the `enterprise_sso` strategy. * @experimental */ enterpriseConnectionId?: string; @@ -236,20 +233,23 @@ export interface SignInFutureSSOParams { identifier?: string; } +/** @generateWithEmptyComment */ export interface SignInFutureMFAPhoneCodeVerifyParams { /** - * The one-time code that was sent to the user as part of the `signIn.mfa.sendPhoneCode()` method. + * The one-time code that was sent to the user. */ code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureMFAEmailCodeVerifyParams { /** - * The one-time code that was sent to the user as part of the `signIn.mfa.sendEmailCode()` method. + * The one-time code that was sent to the user. */ code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureTOTPVerifyParams { /** * The TOTP generated by the user's authenticator app. @@ -257,21 +257,23 @@ export interface SignInFutureTOTPVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureBackupCodeVerifyParams { /** - * The backup code that was provided to the user when they set up two-step authentication. + * The backup code that was provided to the user when they set up backup codes. */ code: string; } +/** @generateWithEmptyComment */ export interface SignInFutureTicketParams { /** - * The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) - * generated from the Backend API. + * The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) generated from the Backend API. */ ticket: string; } +/** @generateWithEmptyComment */ export interface SignInFutureWeb3Params { /** * The verification strategy to validate the user's sign-in request. @@ -282,29 +284,34 @@ export interface SignInFutureWeb3Params { */ provider: Web3Provider; /** - * The name of the wallet to use for Solana sign-ins. Required when `provider` is set to `'solana'`. + * **Required** when `provider` is set to `'solana'`. The name of the wallet to use for Solana sign-ins. */ walletName?: string; } +/** @generateWithEmptyComment */ export interface SignInFuturePasskeyParams { /** * The flow to use for the passkey sign-in. * - * - `'autofill'`: The client prompts your users to select a passkey before they interact with your app. - * - `'discoverable'`: The client requires the user to interact with the client. + *
      + *
    • `'autofill'`: The client prompts your users to select a passkey before they interact with your app.
    • + *
    • `'discoverable'`: The client requires the user to interact with the client.
    • + *
    */ flow?: 'autofill' | 'discoverable'; } +/** @generateWithEmptyComment */ export interface SignInFutureFinalizeParams { + /** + * A custom navigation function to be called just before the session and/or Organization is set. When provided, it takes precedence over the `redirectUrl` parameter for navigation. The callback receives a `decorateUrl` function that should be used to wrap destination URLs. This enables Safari ITP cookie refresh when needed. The decorated URL may be an external URL (starting with `https://`) that requires `window.location.href` instead of client-side navigation. See the [section on using the `navigate()` parameter](https://clerk.com/docs/reference/objects/clerk#using-the-navigate-parameter) for more details. + */ navigate?: SetActiveNavigate; } /** - * The `SignInFuture` class holds the state of the current sign-in and provides helper methods to navigate and complete - * the sign-in process. It is used to manage the sign-in lifecycle, including the first and second factor verification, - * and the creation of a new session. + * The `SignInFuture` class holds the state of the current sign-in and provides helper methods to navigate and complete the sign-in process. It is used to manage the sign-in lifecycle, including the first and second factor verification, and the creation of a new session. */ export interface SignInFutureResource { /** @@ -313,58 +320,71 @@ export interface SignInFutureResource { readonly id?: string; /** - * Array of the first factors that are supported in the current sign-in. Each factor contains information about the - * verification strategy that can be used. + * Array of the first factors that are supported in the current sign-in. Each factor contains information about the verification strategy that can be used. */ readonly supportedFirstFactors: SignInFirstFactor[]; /** - * Array of the second factors that are supported in the current sign-in. Each factor contains information about the - * verification strategy that can be used. This property is populated only when the first factor is verified. + * Array of the second factors that are supported in the current sign-in. Each factor contains information about the verification strategy that can be used. This property is populated only when the first factor is verified. */ readonly supportedSecondFactors: SignInSecondFactor[]; /** * The current status of the sign-in. + *
      + *
    • `'complete'` - The sign-in process has been completed successfully.
    • + *
    • `'needs_client_trust'` - The user is signing in from a new device and must complete a [second factor verification](!second-factor-verification) to establish [Client Trust](https://clerk.com/docs/guides/secure/client-trust). See the [Client Trust custom flow guide](https://clerk.com/docs/guides/development/custom-flows/authentication/client-trust) for more information.
    • + *
    • `'needs_identifier'` - The user's identifier (e.g., email address, phone number, username) hasn't been provided.
    • + *
    • `'needs_first_factor'` - One of the following [first factor verification](!first-factor-verification) strategies is missing: `'email_link'`, `'email_code'`, `passkey`, `password`, `'phone_code'`, `'web3_base_signature'`, `'web3_metamask_signature'`, `'web3_coinbase_wallet_signature'`, `'web3_okx_wallet_signature'`, `'web3_solana_signature'`, [`OAuthStrategy`](https://clerk.com/docs/reference/types/sso#o-auth-strategy), or `'enterprise_sso'`.
    • + *
    • `'needs_second_factor'` - One of the following [second factor verification](!second-factor-verification) strategies is missing: `'phone_code'`, `'totp'`, `'backup_code'`, `'email_code'`, or `'email_link'`.
    • + *
    • `'needs_new_password'` - The user needs to set a new password. See the [dedicated custom flow](/docs/guides/development/custom-flows/authentication/forgot-password) guide for more information.
    • + *
    */ readonly status: SignInStatus; /** - * Indicates that there is not a matching user for the first-factor verification used, and that the sign-in can be - * transferred to a sign-up. + * Indicates that there is not a matching user for the first-factor verification used, and that the sign-in can be transferred to a sign-up. */ readonly isTransferable: boolean; - readonly existingSession?: { sessionId: string }; + /** + * Indicates that the sign-in was not able to create a new session because the identifier already exists in an existing session. + */ + readonly existingSession?: { + /** + * The ID of the existing session. + */ + sessionId: string; + }; /** - * The state of the verification process for the selected first factor. Initially, this property contains an empty - * verification object, since there is no first factor selected. + * The state of the verification process for the selected first factor. Initially, this property contains an empty verification object, since there is no first factor selected. */ readonly firstFactorVerification: VerificationResource; /** - * The state of the verification process for the selected second factor. Initially, this property contains an empty - * verification object, since there is no second factor selected. + * The state of the verification process for the selected second factor. Initially, this property contains an empty verification object, since there is no second factor selected. */ readonly secondFactorVerification: VerificationResource; /** - * The authentication identifier value for the current sign-in. `null` if the `strategy` is `'oauth_'` - * or `'enterprise_sso'`. + * The authentication identifier value for the current sign-in. `null` if the `strategy` is `'oauth_'` or `'enterprise_sso'`. */ readonly identifier: string | null; /** - * The identifier of the session that was created upon completion of the current sign-in. The value of this property - * is `null` if the sign-in status is not `'complete'`. + * The ID of the session that was created upon completion of the current sign-in. The value of this property is `null` if the sign-in status is not `'complete'`. */ readonly createdSessionId: string | null; /** - * An object containing information about the user of the current sign-in. This property is populated only once an - * identifier is given to the `SignIn` object through `signIn.create()` or another method that populates the - * `identifier` property. + * An object containing information about the user of the current sign-in. This property is populated only once an identifier is given to the `SignIn` object through `signIn.create()` or another method that populates the `identifier` property. + *
      + *
    • `'firstName'`: The user's first name.
    • + *
    • `'lastName'`: The user's last name.
    • + *
    • `'imageUrl'`: The user's profile image URL.
    • + *
    • `'hasImage'`: Whether the user has a profile image.
    • + *
    */ readonly userData: UserData; @@ -376,202 +396,179 @@ export interface SignInFutureResource { readonly canBeDiscarded: boolean; /** - * Creates a new `SignIn` instance initialized with the provided parameters. The instance maintains the sign-in - * lifecycle state through its `status` property, which updates as the authentication flow progresses. + * Creates a new `SignIn` instance initialized with the provided parameters. The instance maintains the sign-in lifecycle state through its `status` property, which updates as the authentication flow progresses. Once the sign-in process is complete, call the `signIn.finalize()` method to set the newly created session as the active session. * - * What you must pass to `params` depends on which [sign-in options](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options) - * you have enabled in your app's settings in the Clerk Dashboard. + * What you must pass to `params` depends on which [sign-in options](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options) you have enabled in your app's settings in the Clerk Dashboard. * - * You can complete the sign-in process in one step if you supply the required fields to `create()`. Otherwise, - * Clerk's sign-in process provides great flexibility and allows users to easily create multi-step sign-in flows. + * You can complete the sign-in process in one step if you supply the required fields to `create()`. Otherwise, Clerk's sign-in process provides great flexibility and allows users to easily create multi-step sign-in flows. * - * > [!WARNING] - * > Once the sign-in process is complete, call the `signIn.finalize()` method to set the newly created session as - * > the active session. + * > [!IMPORTANT] + * > The `signIn.create()` method is intended for advanced use cases. For most use cases, prefer the use of the factor-specific methods such as `signIn.password()`, `signIn.emailCode.sendCode()`, etc. */ create: (params: SignInFutureCreateParams) => Promise<{ error: ClerkError | null }>; /** - * Used to submit a password to sign-in. + * Submits a password to sign-in. */ password: (params: SignInFuturePasswordParams) => Promise<{ error: ClerkError | null }>; - /** - * - */ + /** @extractMethods */ emailCode: { /** - * Used to send an email code to sign-in + * Sends an email code to sign-in. */ sendCode: (params?: SignInFutureEmailCodeSendParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a code sent via email to sign-in + * Verifies a code sent with the [`emailCode.sendCode()`](https://clerk.com/docs/reference/objects/sign-in-future#email-code-send-code) method. */ verifyCode: (params: SignInFutureEmailCodeVerifyParams) => Promise<{ error: ClerkError | null }>; }; - /** - * - */ + /** @extractMethods */ emailLink: { /** - * Used to send an email link to sign-in + * Sends an email link to sign in with. */ sendLink: (params: SignInFutureEmailLinkSendParams) => Promise<{ error: ClerkError | null }>; /** - * Will wait for verification to complete or expire + * Waits for email link verification to complete or expire. */ waitForVerification: () => Promise<{ error: ClerkError | null }>; /** - * The verification status + * The verification status of the email link. This property is populated by reading query parameters from the URL after the user visits the email link. Returns `null` if no verification status is available. */ verification: { /** - * The verification status + * The verification status. */ status: 'verified' | 'expired' | 'failed' | 'client_mismatch'; /** - * The created session ID + * The ID of the session that was created upon completion of the current sign-in. */ createdSessionId: string; /** - * Whether the verification was from the same client + * Whether the verification was from the same client. */ verifiedFromTheSameClient: boolean; } | null; }; - /** - * - */ + /** @extractMethods */ phoneCode: { /** - * Used to send a phone code to sign-in + * Sends a phone code to sign in with. */ sendCode: (params?: SignInFuturePhoneCodeSendParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a code sent via phone to sign-in + * Verifies a code sent with the [`phoneCode.sendCode()`](https://clerk.com/docs/reference/objects/sign-in-future#phone-code-send-code) method. */ verifyCode: (params: SignInFuturePhoneCodeVerifyParams) => Promise<{ error: ClerkError | null }>; }; - /** - * - */ + /** @extractMethods */ resetPasswordEmailCode: { /** - * Used to send a password reset code to the first email address on the account + * Sends a password reset code to the first email address on the account. */ sendCode: () => Promise<{ error: ClerkError | null }>; /** - * Used to verify a password reset code sent via email. Will cause `signIn.status` to become `'needs_new_password'`. + * Verifies a password reset code sent with the [`resetPasswordEmailCode.sendCode()`](https://clerk.com/docs/reference/objects/sign-in-future#reset-password-email-code-send-code) method. Will cause `signIn.status` to become `'needs_new_password'`. This is when you will call the [`resetPasswordEmailCode.submitPassword()`](https://clerk.com/docs/reference/objects/sign-in-future#reset-password-email-code-submit-password) method to complete the password reset flow. */ verifyCode: (params: SignInFutureEmailCodeVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to submit a new password, and move the `signIn.status` to `'complete'`. + * Submits a new password and moves the sign-in status to `'complete'`. */ submitPassword: (params: SignInFutureResetPasswordSubmitParams) => Promise<{ error: ClerkError | null }>; }; - /** - * - */ + /** @extractMethods */ resetPasswordPhoneCode: { /** - * Used to send a password reset code to the first phone number on the account + * Sends a password reset code to the first phone number on the account. */ sendCode: (params?: SignInFutureResetPasswordPhoneCodeSendParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a password reset code sent via phone. Will cause `signIn.status` to become `'needs_new_password'`. + * Verifies a password reset code sent with the [`resetPasswordPhoneCode.sendCode()`](https://clerk.com/docs/reference/objects/sign-in-future#reset-password-phone-code-send-code) method. Will cause `signIn.status` to become `'needs_new_password'`. This is when you will call the [`resetPasswordPhoneCode.submitPassword()`](https://clerk.com/docs/reference/objects/sign-in-future#reset-password-phone-code-submit-password) method to complete the password reset flow. */ verifyCode: (params: SignInFutureResetPasswordPhoneCodeVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to submit a new password, and move the `signIn.status` to `'complete'`. + * Submits a new password and moves the sign-in status to `'complete'`. */ submitPassword: (params: SignInFutureResetPasswordSubmitParams) => Promise<{ error: ClerkError | null }>; }; /** - * Used to perform OAuth authentication. + * Performs an SSO-based sign-in (Social/OAuth or Enterprise). */ sso: (params: SignInFutureSSOParams) => Promise<{ error: ClerkError | null }>; - /** - * - */ + /** @extractMethods */ mfa: { /** - * Used to send a phone code as a second factor to sign-in + * Sends a phone code to sign in with as a second factor. */ sendPhoneCode: () => Promise<{ error: ClerkError | null }>; /** - * Used to verify a phone code sent as a second factor to sign-in + * Verifies a phone code sent with the [`mfa.sendPhoneCode()`](https://clerk.com/docs/reference/objects/sign-in-future#mfa-send-phone-code) method. */ verifyPhoneCode: (params: SignInFutureMFAPhoneCodeVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to send an email code as a second factor to sign-in + * Sends an email code to sign in with as a second factor. */ sendEmailCode: () => Promise<{ error: ClerkError | null }>; /** - * Used to verify an email code sent as a second factor to sign-in + * Verifies an email code sent with the [`mfa.sendEmailCode()`](https://clerk.com/docs/reference/objects/sign-in-future#mfa-send-email-code) method. */ verifyEmailCode: (params: SignInFutureMFAEmailCodeVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a TOTP code as a second factor to sign-in + * Verifies an authenticator app (TOTP) code to sign in with as a second factor. */ verifyTOTP: (params: SignInFutureTOTPVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a backup code as a second factor to sign-in + * Verifies a backup code to sign in with as a second factor. */ verifyBackupCode: (params: SignInFutureBackupCodeVerifyParams) => Promise<{ error: ClerkError | null }>; }; /** - * Used to perform a ticket-based sign-in. + * Performs a ticket-based sign-in. */ ticket: (params?: SignInFutureTicketParams) => Promise<{ error: ClerkError | null }>; /** - * Used to perform a Web3-based sign-in. + * Performs a Web3-based sign-in. */ web3: (params: SignInFutureWeb3Params) => Promise<{ error: ClerkError | null }>; /** - * Initiates a passkey-based authentication flow, enabling users to authenticate using a previously - * registered passkey. When called without parameters, this method requires a prior call to - * `SignIn.create({ strategy: 'passkey' })` to initialize the sign-in context. This pattern is particularly useful in - * scenarios where the authentication strategy needs to be determined dynamically at runtime. + * Initiates a passkey-based authentication flow, enabling users to authenticate using a previously registered passkey. When called without parameters, this method requires a prior call to `SignIn.create({ strategy: 'passkey' })` to initialize the sign-in context. This pattern is particularly useful in scenarios where the authentication strategy needs to be determined dynamically at runtime. */ passkey: (params?: SignInFuturePasskeyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to convert a sign-in with `status === 'complete'` into an active session. Will cause anything observing the - * session state (such as the `useUser()` hook) to update automatically. + * Converts a sign-in with `status === 'complete'` into an active session. Will cause anything observing the session state (such as the [`useUser()`](https://clerk.com/docs/reference/hooks/use-user) hook) to update automatically. */ finalize: (params?: SignInFutureFinalizeParams) => Promise<{ error: ClerkError | null }>; /** - * Resets the current sign-in attempt by clearing all local state back to null. - * This is useful when you want to allow users to go back to the beginning of - * the sign-in flow (e.g., to change their identifier during verification). + * Resets the current sign-in attempt by clearing all local state back to null. This is useful when you want to allow users to go back to the beginning of the sign-in flow (e.g., to change their identifier during verification). * - * Unlike other methods, `reset()` does not trigger the `fetchStatus` to change - * to `'fetching'` and does not make any API calls - it only clears local state. + * Unlike other methods, `reset()` does not trigger the `fetchStatus` to change to `'fetching'` and does not make any API calls - it only clears local state. */ reset: () => Promise<{ error: ClerkError | null }>; } diff --git a/packages/shared/src/types/signUpCommon.ts b/packages/shared/src/types/signUpCommon.ts index 41c15035b46..db5ca815f03 100644 --- a/packages/shared/src/types/signUpCommon.ts +++ b/packages/shared/src/types/signUpCommon.ts @@ -22,8 +22,10 @@ import type { import type { SnakeToCamel } from './utils'; import type { VerificationResource } from './verification'; +/** @inline */ export type SignUpStatus = 'missing_requirements' | 'complete' | 'abandoned'; +/** @inline */ export type SignUpField = SignUpAttributeField | SignUpIdentificationField; export type PrepareVerificationParams = @@ -64,9 +66,11 @@ export type AttemptVerificationParams = signature: string; }; +/** @inline */ export type SignUpAttributeField = FirstNameAttribute | LastNameAttribute | PasswordAttribute | LegalAcceptedAttribute; // TODO: SignUpVerifiableField or SignUpIdentifier? +/** @inline */ export type SignUpVerifiableField = | UsernameIdentifier | EmailAddressIdentifier @@ -75,6 +79,7 @@ export type SignUpVerifiableField = | Web3WalletIdentifier; // TODO: Does it make sense that the identification *field* holds a *strategy*? +/** @inline */ export type SignUpIdentificationField = SignUpVerifiableField | OAuthStrategy | EnterpriseSSOStrategy; // TODO: Replace with discriminated union type diff --git a/packages/shared/src/types/signUpFuture.ts b/packages/shared/src/types/signUpFuture.ts index 1daf1239ece..22629e6f5ac 100644 --- a/packages/shared/src/types/signUpFuture.ts +++ b/packages/shared/src/types/signUpFuture.ts @@ -13,42 +13,42 @@ import type { } from './strategies'; import type { VerificationResource } from './verification'; +/** @generateWithEmptyComment */ export interface SignUpFutureAdditionalParams { /** - * The user's first name. Only supported if - * [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) - * is enabled in the instance settings. + * The user's first name. Only supported if [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) is enabled in the instance settings. */ firstName?: string; /** - * The user's last name. Only supported if - * [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) - * is enabled in the instance settings. + * The user's last name. Only supported if [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) is enabled in the instance settings. */ lastName?: string; /** - * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be - * automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use - * it to implement custom fields that can be collected during sign-up and will automatically be attached to the - * created User object. + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created User object. */ unsafeMetadata?: SignUpUnsafeMetadata; /** - * A boolean indicating whether the user has agreed to the - * [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + * Indicates whether the user has agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. */ legalAccepted?: boolean; /** - * The locale to assign to the user in [BCP 47](https://developer.mozilla.org/en-US/docs/Glossary/BCP_47_language_tag) - * format (e.g., "en-US", "fr-FR"). If omitted, defaults to the browser's locale. + * The locale to assign to the user in [BCP 47](https://developer.mozilla.org/en-US/docs/Glossary/BCP_47_language_tag) format (e.g., "en-US", "fr-FR"). If omitted, defaults to the browser's locale. */ locale?: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureCreateParams extends SignUpFutureAdditionalParams { /** - * The first factor verification strategy to use in the sign-in flow. Depends on the `identifier` value. Each - * authentication identifier supports different verification strategies. + * The strategy to use for the sign-up. The following strategies are supported: + *
      + *
    • `'oauth_'`: The user will be authenticated with their [social connection account](https://clerk.com/docs/guides/configure/auth-strategies/social-connections/overview). See a list of [supported values for ``](https://clerk.com/docs/reference/types/sso).
    • + *
    • `'enterprise_sso'`: The user will be authenticated either through SAML or OIDC depending on the configuration of their [enterprise SSO account](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/overview).
    • + *
    • `'ticket'`: The user will be authenticated via the ticket _or token_ generated from the Backend API.
    • + *
    • `'google_one_tap'`: The user will be authenticated with the Google One Tap UI. It's recommended to use [`authenticateWithGoogleOneTap()`](https://clerk.com/docs/reference/components/authentication/google-one-tap#authenticate-with-google-one-tap) instead, as it will also set the user's current session as active for you.
    • + *
    • `'oauth_token_apple'`: The user will be authenticated using a native [Sign in with Apple](https://clerk.com/docs/guides/configure/auth-strategies/sign-in-with-apple) identity token.
    • + *
    • `'phone_code'`: The user will receive a one-time code via SMS to verify their phone number.
    • + *
    */ strategy?: | OAuthStrategy @@ -58,66 +58,52 @@ export interface SignUpFutureCreateParams extends SignUpFutureAdditionalParams { | AppleIdTokenStrategy | PhoneCodeStrategy; /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress?: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber?: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username?: string; /** - * The user's password. Only supported if - * [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled. + * The user's password. [Password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) must be enabled in the instance settings. */ password?: string; /** - * When set to `true`, the `SignUp` will attempt to retrieve information from the active `SignIn` instance and use it - * to complete the sign-up process. This is useful when you want to seamlessly transition a user from a sign-in - * attempt to a sign-up attempt. + * When set to `true`, the `SignUp` will attempt to retrieve information from the active `SignIn` instance and use it to complete the sign-up process. This is useful when you want to seamlessly transition a user from a sign-in attempt to a sign-up attempt. */ transfer?: boolean; /** - * The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) - * generated from the Backend API. **Required** if `strategy` is set to `'ticket'`. + * **Required** if `strategy` is set to `'ticket'`. The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) generated from the Backend API. */ ticket?: string; /** - * The Web3 wallet address, made up of 0x + 40 hexadecimal characters. **Required** if - * [Web3 authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#web3-authentication) - * is enabled. + * The Web3 wallet address, made up of 0x + 40 hexadecimal characters. Only supported if [Web3 authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#web3-authentication) is enabled in the instance settings. */ web3Wallet?: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureUpdateParams extends SignUpFutureAdditionalParams { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress?: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber?: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username?: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureEmailCodeVerifyParams { /** * The code that was sent to the user. @@ -125,6 +111,7 @@ export interface SignUpFutureEmailCodeVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureEmailLinkSendParams { /** * The full URL that the user will be redirected to when they visit the email link. @@ -132,91 +119,72 @@ export interface SignUpFutureEmailLinkSendParams { verificationUrl: string; } +/** @generateWithEmptyComment */ export type SignUpFuturePasswordParams = SignUpFutureAdditionalParams & { /** - * The user's password. Only supported if - * [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled. + * The user's password. [Password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) must be enabled in the instance settings. */ password: string; } & ( | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber?: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username?: string; } | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress?: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username?: string; } | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress?: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber?: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username: string; } | { /** - * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) - * is enabled. Keep in mind that the email address requires an extra verification process. + * The user's email address. Only supported if [Email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. Keep in mind that the email address requires an extra verification process. */ emailAddress?: string; /** - * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled. - * Keep in mind that the phone number requires an extra verification process. + * The user's phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164). Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. Keep in mind that the phone number requires an extra verification process. */ phoneNumber?: string; /** - * The user's username. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The user's username. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ username?: string; } ); +/** @generateWithEmptyComment */ export interface SignUpFuturePhoneCodeSendParams { /** * The mechanism to use to send the code to the provided phone number. Defaults to `'sms'`. @@ -224,6 +192,7 @@ export interface SignUpFuturePhoneCodeSendParams { channel?: PhoneCodeChannel; } +/** @generateWithEmptyComment */ export interface SignUpFuturePhoneCodeVerifyParams { /** * The code that was sent to the user. @@ -231,23 +200,23 @@ export interface SignUpFuturePhoneCodeVerifyParams { code: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureSSOParams extends SignUpFutureAdditionalParams { /** - * The strategy to use for authentication. + * The strategy to use for authentication. Either [`OAuthStrategy`](https://clerk.com/docs/reference/types/oauth-strategy) or [`EnterpriseSSOStrategy`](https://clerk.com/docs/reference/types/enterprise-sso-strategy). */ strategy: string; /** - * The URL or path to navigate to after the OAuth or SAML flow completes. Can be provided as a relative URL (such as - * `/dashboard`), in which case it will be prefixed with the base URL of the current page. + * The URL or path to navigate to after the OAuth or SAML flow completes. Can be provided as a relative URL (such as `/dashboard`), in which case it will be prefixed with the base URL of the current page. */ redirectUrl: string; /** + * The URL or path to navigate to if a session was not created, and needs additional information. * TODO @revamp-hooks: This should be handled by FAPI instead. */ redirectCallbackUrl: string; /** - * If provided, a `Window` to use for the OAuth flow. Useful in instances where you cannot navigate to an - * OAuth provider. + * If provided, a `Window` to use for the OAuth flow. Useful in instances where you cannot navigate to an OAuth provider. * * @example * ```ts @@ -260,29 +229,29 @@ export interface SignUpFutureSSOParams extends SignUpFutureAdditionalParams { */ popup?: Window; /** - * Optional for `oauth_` or `enterprise_sso` strategies. The value to pass to the - * [OIDC prompt parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=prompt,reauthentication%20and%20consent.) - * in the generated OAuth redirect URL. + * The value to pass to the [OIDC prompt parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=prompt,reauthentication%20and%20consent.) in the generated OAuth redirect URL. */ oidcPrompt?: string; /** + * The identifier of the enterprise connection to target when using the `enterprise_sso` strategy. * @experimental */ enterpriseConnectionId?: string; /** - * Email address to use for targeting an enterprise connection at sign-up. + * The email address to use for targeting an enterprise connection at sign-up. */ emailAddress?: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureTicketParams extends SignUpFutureAdditionalParams { /** - * The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) - * generated from the Backend API. **Required** if `strategy` is set to `'ticket'`. + * **Required** if `strategy` is set to `'ticket'`. The [ticket _or token_](https://clerk.com/docs/guides/development/custom-flows/authentication/application-invitations) generated from the Backend API. */ ticket: string; } +/** @generateWithEmptyComment */ export interface SignUpFutureWeb3Params extends SignUpFutureAdditionalParams { /** * The verification strategy to validate the user's sign-up request. @@ -290,36 +259,45 @@ export interface SignUpFutureWeb3Params extends SignUpFutureAdditionalParams { strategy: Web3Strategy; } +/** @generateWithEmptyComment */ export interface SignUpFutureFinalizeParams { + /** + * A custom navigation function to be called just before the session and/or Organization is set. When provided, it takes precedence over the `redirectUrl` parameter for navigation. The callback receives a `decorateUrl` function that should be used to wrap destination URLs. This enables Safari ITP cookie refresh when needed. The decorated URL may be an external URL (starting with `https://`) that requires `window.location.href` instead of client-side navigation. See the [section on using the `navigate()` parameter](https://clerk.com/docs/reference/objects/clerk#using-the-navigate-parameter) for more details. + */ navigate?: SetActiveNavigate; } /** - * An object that contains information about all available verification strategies. + * Contains information about the available verification strategies for a sign-up attempt. */ export interface SignUpFutureVerifications { /** - * An object holding information about the email address verification. + * Holds information about the email address verification. */ readonly emailAddress: SignUpVerificationResource; /** - * An object holding information about the phone number verification. + * Holds information about the phone number verification. */ readonly phoneNumber: SignUpVerificationResource; /** - * An object holding information about the Web3 wallet verification. + * Holds information about the Web3 wallet verification. */ readonly web3Wallet: VerificationResource; /** - * An object holding information about the external account verification. + * Holds information about the external account verification. */ readonly externalAccount: VerificationResource; /** * The verification status for email link flows. + *
      + *
    • `status`: The verification status.
    • + *
    • `createdSessionId`: The ID of the session that was created upon successful verification.
    • + *
    • `verifiedFromTheSameClient`: Whether the verification was from the same client (browser) that initiated the email link flow.
    • + *
    */ readonly emailLinkVerification: { /** @@ -339,39 +317,38 @@ export interface SignUpFutureVerifications { } | null; /** - * Used to send an email code to verify an email address. + * Sends an email code to verify an email address. */ sendEmailCode: () => Promise<{ error: ClerkError | null }>; /** - * Used to verify a code sent via email. + * Verifies a code sent with the [`verifications.sendEmailCode()`](https://clerk.com/docs/reference/objects/sign-up-future#verifications-send-email-code) method. */ verifyEmailCode: (params: SignUpFutureEmailCodeVerifyParams) => Promise<{ error: ClerkError | null }>; /** - * Used to send an email link to verify an email address. + * Sends an email link to verify an email address. */ sendEmailLink: (params: SignUpFutureEmailLinkSendParams) => Promise<{ error: ClerkError | null }>; /** - * Will wait for email link verification to complete or expire. + * Will wait for email link verification to complete or expire after calling [`verifications.sendEmailLink()`](https://clerk.com/docs/reference/objects/sign-up-future#verifications-send-email-link). */ waitForEmailLinkVerification: () => Promise<{ error: ClerkError | null }>; /** - * Used to send a phone code to verify a phone number. + * Sends a phone code to verify a phone number. */ sendPhoneCode: (params?: SignUpFuturePhoneCodeSendParams) => Promise<{ error: ClerkError | null }>; /** - * Used to verify a code sent via phone. + * Verifies a code sent with the [`verifications.sendPhoneCode()`](https://clerk.com/docs/reference/objects/sign-up-future#verifications-send-phone-code) method. */ verifyPhoneCode: (params: SignUpFuturePhoneCodeVerifyParams) => Promise<{ error: ClerkError | null }>; } /** - * The `SignUpFuture` class holds the state of the current sign-up attempt and provides methods to drive custom sign-up - * flows, including email/phone verification, password, SSO, ticket-based, and Web3-based account creation. + * The `SignUpFuture` class holds the state of the current sign-up attempt and provides methods to drive custom sign-up flows, including email/phone verification, password, SSO, ticket-based, and Web3-based account creation. */ export interface SignUpFutureResource { /** @@ -385,92 +362,77 @@ export interface SignUpFutureResource { readonly status: SignUpStatus; /** - * An array of all the required fields that need to be supplied and verified in order for this sign-up to be marked - * as complete and converted into a user. + * An array of all the required fields that need to be supplied and verified in order for this sign-up to be marked as complete and converted into a user. */ readonly requiredFields: SignUpField[]; /** - * An array of all the fields that can be supplied to the sign-up, but their absence does not prevent the sign-up - * from being marked as complete. + * An array of all the fields that can be supplied to the sign-up, but their absence does not prevent the sign-up from being marked as complete. */ readonly optionalFields: SignUpField[]; /** - * An array of all the fields whose values are not supplied yet but they are mandatory in order for a sign-up to be - * marked as complete. + * An array of all the fields whose values are not supplied yet but they are mandatory in order for a sign-up to be marked as complete. */ readonly missingFields: SignUpField[]; /** - * An array of all the fields whose values have been supplied, but they need additional verification in order for - * them to be accepted. Examples of such fields are `email_address` and `phone_number`. + * An array of all the fields whose values have been supplied, but they need additional verification in order for them to be accepted. Examples of such fields are `email_address` and `phone_number`. */ readonly unverifiedFields: SignUpIdentificationField[]; /** - * Indicates that there is a matching user for provided identifier, and that the sign-up can be transferred to - * a sign-in. + * Indicates that there is a matching user for provided identifier, and that the sign-up can be transferred to a sign-in. */ readonly isTransferable: boolean; - readonly existingSession?: { sessionId: string }; + /** + * Indicates that the sign-up was not able to create a new session because the identifier already exists in an existing session. + */ + readonly existingSession?: { + /** + * The ID of the existing session. + */ + sessionId: string; + }; /** - * The `username` supplied to the current sign-up. Only supported if - * [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in - * the instance settings. + * The `username` supplied to the current sign-up. Only supported if [username](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#username) is enabled in the instance settings. */ readonly username: string | null; /** - * The `firstName` supplied to the current sign-up. Only supported if - * [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) - * is enabled in the instance settings. + * The `firstName` supplied to the current sign-up. Only supported if [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) is enabled in the instance settings. */ readonly firstName: string | null; /** - * The `lastName` supplied to the current sign-up. Only supported if - * [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) - * is enabled in the instance settings. + * The `lastName` supplied to the current sign-up. Only supported if [First and last name](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#user-model) is enabled in the instance settings. */ readonly lastName: string | null; /** - * The `emailAddress` supplied to the current sign-up. Only supported if - * [email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled - * in the instance settings. + * The `emailAddress` supplied to the current sign-up. Only supported if [email address](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) is enabled in the instance settings. */ readonly emailAddress: string | null; /** - * The `phoneNumber` supplied to the current sign-up in E.164 format. Only supported if - * [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled - * in the instance settings. + * The `phoneNumber` supplied to the current sign-up in E.164 format. Only supported if [phone number](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) is enabled in the instance settings. */ readonly phoneNumber: string | null; /** - * The Web3 wallet address supplied to the current sign-up, made up of 0x + 40 hexadecimal characters. Only supported - * if - * [Web3 authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#web3-authentication) - * is enabled in the instance settings. + * The Web3 wallet address supplied to the current sign-up, made up of 0x + 40 hexadecimal characters. Only supported if [Web3 authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#web3-authentication) is enabled in the instance settings. */ readonly web3Wallet: string | null; /** - * The value of this attribute is true if a password was supplied to the current sign-up. Only supported if - * [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled in - * the instance settings. + * The value of this attribute is true if a password was supplied to the current sign-up. Only supported if [password](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#password) is enabled in the instance settings. */ readonly hasPassword: boolean; /** - * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be - * automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use - * it to implement custom fields that can be collected during sign-up and will automatically be attached to the - * created User object. + * Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created User object. */ readonly unsafeMetadata: SignUpUnsafeMetadata; @@ -490,13 +452,12 @@ export interface SignUpFutureResource { readonly abandonAt: number | null; /** - * The epoch numerical time when the user agreed to the - * [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. + * The epoch numerical time when the user agreed to the [legal compliance](https://clerk.com/docs/guides/secure/legal-compliance) documents. */ readonly legalAcceptedAt: number | null; /** - * The locale of the user in BCP 47 format. + * The locale of the user in [BCP 47](https://developer.mozilla.org/en-US/docs/Glossary/BCP_47_language_tag) format (e.g., "en-US", "fr-FR"), or `null` if not set. */ readonly locale: string | null; @@ -508,66 +469,57 @@ export interface SignUpFutureResource { readonly canBeDiscarded: boolean; /** - * Creates a new `SignUp` instance initialized with the provided parameters. The instance maintains the sign-up - * lifecycle state through its `status` property, which updates as the authentication flow progresses. Will also - * deactivate any existing sign-up process the client may already have in progress. + * Creates a new `SignUp` instance initialized with the provided parameters. The instance maintains the sign-up lifecycle state through its `status` property, which updates as the authentication flow progresses. Will also deactivate any existing sign-up process the client may already have in progress. Once the sign-up process is complete, call the [`signUp.finalize()`](https://clerk.com/docs/reference/objects/sign-up-future#finalize) method to set the newly created session as the active session. * - * What you must pass to `params` depends on which - * [sign-up options](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options) you have - * enabled in your app's settings in the Clerk Dashboard. + * What you must pass to `params` depends on which [sign-up options](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options) you have enabled in your app's settings in the Clerk Dashboard. * - * You can complete the sign-up process in one step if you supply the required fields to `create()`. Otherwise, - * Clerk's sign-up process provides great flexibility and allows users to easily create multi-step sign-up flows. + * You can complete the sign-up process in one step if you supply the required fields to `create()`. Otherwise, Clerk's sign-up process provides great flexibility and allows users to easily create multi-step sign-up flows. * - * > [!WARNING] - * > Once the sign-up process is complete, call the `signUp.finalize()` method to set the newly created session as - * > the active session. + * > [!IMPORTANT] + * > The `signUp.create()` method is intended for advanced use cases. For most use cases, prefer the use of the factor-specific methods such as `signUp.password()`, `signUp.sso()`, etc. */ create: (params: SignUpFutureCreateParams) => Promise<{ error: ClerkError | null }>; /** - * Updates the current `SignUp`. + * Updates the current `SignUpFuture` instance with the provided parameters. */ update: (params: SignUpFutureUpdateParams) => Promise<{ error: ClerkError | null }>; /** * An object that contains information about all available verification strategies. + * @extractMethods */ verifications: SignUpFutureVerifications; /** - * Used to sign up using an email address and password. + * Performs a password-based sign-up. */ password: (params: SignUpFuturePasswordParams) => Promise<{ error: ClerkError | null }>; /** - * Used to create an account using an OAuth connection. + * Performs an SSO-based sign-up ([Social/OAuth](https://clerk.com/docs/guides/configure/auth-strategies/social-connections/overview) or [Enterprise](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/overview)). */ sso: (params: SignUpFutureSSOParams) => Promise<{ error: ClerkError | null }>; /** - * Used to perform a ticket-based sign-up. + * Performs a ticket-based sign-up. */ ticket: (params?: SignUpFutureTicketParams) => Promise<{ error: ClerkError | null }>; /** - * Used to perform a Web3-based sign-up. + * Performs a Web3-based sign-up. */ web3: (params: SignUpFutureWeb3Params) => Promise<{ error: ClerkError | null }>; /** - * Used to convert a sign-up with `status === 'complete'` into an active session. Will cause anything observing the - * session state (such as the `useUser()` hook) to update automatically. + * Converts a sign-up with `status === 'complete'` into an active session. Will cause anything observing the session state (such as the [`useUser()`](https://clerk.com/docs/reference/hooks/use-user) hook) to update automatically. */ finalize: (params?: SignUpFutureFinalizeParams) => Promise<{ error: ClerkError | null }>; /** - * Resets the current sign-up attempt by clearing all local state back to null. - * This is useful when you want to allow users to go back to the beginning of - * the sign-up flow (e.g., to change their email address during verification). + * Resets the current sign-up attempt by clearing all local state back to null. This is useful when you want to allow users to go back to the beginning of the sign-up flow (e.g., to change their email address during verification). * - * Unlike other methods, `reset()` does not trigger the `fetchStatus` to change - * to `'fetching'` and does not make any API calls - it only clears local state. + * Unlike other methods, `reset()` does not trigger the `fetchStatus` to change to `'fetching'` and does not make any API calls - it only clears local state. */ reset: () => Promise<{ error: ClerkError | null }>; } diff --git a/packages/shared/src/types/strategies.ts b/packages/shared/src/types/strategies.ts index eb6dde71ed5..2055c1a5056 100644 --- a/packages/shared/src/types/strategies.ts +++ b/packages/shared/src/types/strategies.ts @@ -1,20 +1,37 @@ import type { OAuthProvider } from './oauth'; import type { Web3Provider } from './web3'; +/** @inline */ export type GoogleOneTapStrategy = 'google_one_tap'; +/** @inline */ export type AppleIdTokenStrategy = 'oauth_token_apple'; +/** @inline */ export type PasskeyStrategy = 'passkey'; +/** @inline */ export type PasswordStrategy = 'password'; +/** @inline */ export type PhoneCodeStrategy = 'phone_code'; +/** @inline */ export type EmailCodeStrategy = 'email_code'; +/** @inline */ export type EmailLinkStrategy = 'email_link'; +/** @inline */ export type TicketStrategy = 'ticket'; +/** @inline */ export type TOTPStrategy = 'totp'; +/** @inline */ export type BackupCodeStrategy = 'backup_code'; +/** @inline */ export type ResetPasswordPhoneCodeStrategy = 'reset_password_phone_code'; +/** @inline */ export type ResetPasswordEmailCodeStrategy = 'reset_password_email_code'; +/** @inline */ export type CustomOAuthStrategy = `oauth_custom_${string}`; +/** @inline */ export type EnterpriseSSOStrategy = 'enterprise_sso'; +/** OAuth-related authentication strategies (`oauth_` and custom OAuth). */ export type OAuthStrategy = `oauth_${OAuthProvider}` | CustomOAuthStrategy; + +/** @inline */ export type Web3Strategy = `web3_${Web3Provider}_signature`; diff --git a/packages/shared/src/types/telemetry.ts b/packages/shared/src/types/telemetry.ts index bc518207818..02512197d43 100644 --- a/packages/shared/src/types/telemetry.ts +++ b/packages/shared/src/types/telemetry.ts @@ -57,9 +57,24 @@ export interface TelemetryLogEntry { readonly userId?: string; } +/** + * @inline + */ export interface TelemetryCollector { + /** + * Indicates whether telemetry is enabled. + */ isEnabled: boolean; + /** + * If `true`, telemetry events are only logged to the console and not sent to Clerk. + */ isDebug: boolean; + /** + * Records a telemetry event. + */ record(event: TelemetryEventRaw): void; + /** + * Records a telemetry log entry. + */ recordLog(entry: TelemetryLogEntry): void; } diff --git a/packages/shared/src/types/user.ts b/packages/shared/src/types/user.ts index cdd8003eaab..f3e8905be64 100644 --- a/packages/shared/src/types/user.ts +++ b/packages/shared/src/types/user.ts @@ -63,71 +63,248 @@ declare global { } /** - * The `User` object holds all of the information for a single user of your application and provides a set of methods to manage their account. + * The `User` object holds all of the information for a single user of your application and provides a set of methods to manage their account. Each `User` has at least one authentication identifier, which might be their email address, phone number, or a username. * - * A user can be contacted at their primary email address or primary phone number. They can have more than one registered email address, but only one of them will be their primary email address. This goes for phone numbers as well; a user can have more than one, but only one phone number will be their primary. At the same time, a user can also have one or more external accounts by connecting to [social providers](https://clerk.com/docs/guides/configure/auth-strategies/social-connections/overview) such as Google, Apple, Facebook, and many more. + * A user can be contacted at their primary email address or primary phone number. They can have more than one registered email address or phone number, but only one of them will be their primary email address (`User.primaryEmailAddress`) or primary phone number (`User.primaryPhoneNumber`). At the same time, a user can also have one or more external accounts by connecting to [social providers](https://clerk.com/docs/guides/configure/auth-strategies/social-connections/overview) such as Google, Apple, Facebook, and many more (`User.externalAccounts`). * - * Finally, a `User` object holds profile data like the user's name, profile picture, and a set of [metadata](/docs/guides/users/extending) that can be used internally to store arbitrary information. The metadata are split into `publicMetadata` and `privateMetadata`. Both types are set from the [Backend API](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }}, but public metadata can also be accessed from the [Frontend API](https://clerk.com/docs/reference/frontend-api){{ target: '_blank' }}. - * - * The ClerkJS SDK provides some helper [methods](#methods) on the `User` object to help retrieve and update user information and authentication status. + * Finally, a `User` object holds profile data like the user's name, profile picture, and a set of [metadata](https://clerk.com/docs/guides/users/extending) that can be used internally to store arbitrary information. The metadata are split into `publicMetadata` and `privateMetadata`. Both types are set from the [Backend API](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }}, but public metadata can also be accessed from the [Frontend API](https://clerk.com/docs/reference/frontend-api){{ target: '_blank' }}. + */ export interface UserResource extends ClerkResource, BillingPayerMethods { + /** + * The unique identifier of the user. + */ id: string; + /** + * The user's ID as used in your external systems. Must be unique across your instance. + */ externalId: string | null; + /** + * The ID of the user's primary email address. + */ primaryEmailAddressId: string | null; + /** + * The user's primary email address. + */ primaryEmailAddress: EmailAddressResource | null; + /** + * The ID of the user's primary phone number. + */ primaryPhoneNumberId: string | null; + /** + * The user's primary phone number. + */ primaryPhoneNumber: PhoneNumberResource | null; + /** + * The ID of the user's primary Web3 wallet. + */ primaryWeb3WalletId: string | null; + /** + * The user's primary Web3 wallet. + */ primaryWeb3Wallet: Web3WalletResource | null; + /** + * The user's username. + */ username: string | null; + /** + * The user's full name. + */ fullName: string | null; + /** + * The user's first name. + */ firstName: string | null; + /** + * The user's last name. + */ lastName: string | null; + /** + * Holds the default avatar or user's uploaded profile image. Compatible with Clerk's [Image Optimization](https://clerk.com/docs/guides/development/image-optimization). + */ imageUrl: string; + /** + * Indicates whether the user has uploaded an image or one was copied from OAuth. Returns `false` if Clerk is displaying an avatar for the user. + */ hasImage: boolean; + /** + * An array of all the `EmailAddress` objects associated with the user. Includes the primary. + */ emailAddresses: EmailAddressResource[]; + /** + * An array of all the `PhoneNumber` objects associated with the user. Includes the primary. + */ phoneNumbers: PhoneNumberResource[]; + /** + * An array of all the `Web3Wallet` objects associated with the user. Includes the primary. + */ web3Wallets: Web3WalletResource[]; + /** + * An array of all the `ExternalAccount` objects associated with the user via OAuth. + */ externalAccounts: ExternalAccountResource[]; + /** + * An array of all the `EnterpriseAccount` objects associated with the user via enterprise SSO. + */ enterpriseAccounts: EnterpriseAccountResource[]; + /** + * An array of all the `Passkey` objects associated with the user. + */ passkeys: PasskeyResource[]; + /** + * An array of all the `OrganizationMembership` objects associated with the user. + */ organizationMemberships: OrganizationMembershipResource[]; + /** + * Indicates whether the user has a password on their account. + */ passwordEnabled: boolean; + /** + * Indicates whether the user has enabled TOTP. + */ totpEnabled: boolean; + /** + * Indicates whether the user has enabled backup codes. + */ backupCodeEnabled: boolean; + /** + * Indicates whether the user has enabled two-factor authentication. + */ twoFactorEnabled: boolean; + /** + * Metadata that can be read from the Frontend API and Backend API and can be set only from the Backend API. + */ publicMetadata: UserPublicMetadata; + /** + * Metadata that can be read and set from the Frontend API. It's considered unsafe because it can be modified from the frontend. + * + * There is also an `unsafeMetadata` attribute in the [`SignUp`](https://clerk.com/docs/reference/objects/sign-up-future) object. The value of that field will be automatically copied to the user's unsafe metadata once the sign-up is complete. + */ unsafeMetadata: UserUnsafeMetadata; + /** + * The date and time when the user last signed in. + */ lastSignInAt: Date | null; + /** + * The date and time when the user accepted the legal compliance documents. `null` if [**Require express consent to legal documents**](https://clerk.com/docs/guides/secure/legal-compliance) is not enabled. + */ legalAcceptedAt: Date | null; + /** + * Indicates whether the user can create organizations. + */ createOrganizationEnabled: boolean; + /** + * The maximum number of organizations the user can create. + */ createOrganizationsLimit: number | null; + /** + * Indicates whether the user can delete their own account. + */ deleteSelfEnabled: boolean; + /** + * The date and time when the user was last updated. + */ updatedAt: Date | null; + /** + * The date and time when the user was created. + */ createdAt: Date | null; + /** + * Updates the user's attributes. Use this method to save information you collected about the user. + * + * The appropriate settings must be enabled in the Clerk Dashboard for the user to be able to update their attributes. For example, if you want to use the `update({ firstName })` method, you must enable the **First and last name** setting. It can be found on the [**User & authentication**](https://dashboard.clerk.com/~/user-authentication/user-and-authentication?user_auth_tab=user-profile) page in the Clerk Dashboard. + * @skipParametersSection + */ update: (params: UpdateUserParams) => Promise; + /** + * Updates the user's `unsafeMetadata` using deep-merge semantics. Unlike [`update()`](https://clerk.com/docs/reference/objects/user#update), which fully replaces `unsafeMetadata`, this method merges the provided value with the existing `unsafeMetadata`. Top-level and nested keys are merged, and any key set to `null` is removed. Only `unsafeMetadata` is writable from the frontend; `publicMetadata` and `privateMetadata` can only be set from the [Backend API](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }}. + */ updateMetadata: (params: UpdateUserMetadataParams) => Promise; + /** + * Deletes the current user. + */ delete: () => Promise; + /** + * Updates the user's password. + */ updatePassword: (params: UpdateUserPasswordParams) => Promise; + /** + * Removes the user's password. + */ removePassword: (params: RemoveUserPasswordParams) => Promise; + /** + * Adds an email address for the user. A new [`EmailAddress`](https://clerk.com/docs/reference/types/email-address) will be created and associated with the user. + * + * > [!WARNING] + * > [**Email** must be enabled](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#email) in your app's settings in the Clerk Dashboard. + */ createEmailAddress: (params: CreateEmailAddressParams) => Promise; + /** + * Creates a passkey for the signed-in user. For an example, see the [custom flow guide](https://clerk.com/docs/guides/development/custom-flows/authentication/passkeys#create-user-passkeys). + * @returns A [`PasskeyResource`](https://clerk.com/docs/reference/types/passkey-resource) object. + * + * > [!NOTE] + * > When creating a passkey for a user in a multi-domain Clerk app, `createPasskey()` must be called from the primary domain. + */ createPasskey: () => Promise; + /** + * Adds a phone number for the user. A new [`PhoneNumber`](https://clerk.com/docs/reference/types/phone-number) will be created and associated with the user. + * + * > [!WARNING] + * > [**Phone** must be enabled](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#phone) in your app's settings in the Clerk Dashboard. + */ createPhoneNumber: (params: CreatePhoneNumberParams) => Promise; + /** + * Adds a Web3 wallet for the user. A new [`Web3WalletResource`](https://clerk.com/docs/reference/types/web3-wallet) will be created and associated with the user. + */ createWeb3Wallet: (params: CreateWeb3WalletParams) => Promise; + /** + * A check whether or not the given resource is the primary identifier for the user. + * @param ident - The resource checked against the user to see if it is the primary identifier. + */ isPrimaryIdentification: (ident: EmailAddressResource | PhoneNumberResource | Web3WalletResource) => boolean; + /** + * Gets all **active** sessions for this user. This method uses a cache so a network request will only be triggered only once. + * @returns An array of [`SessionWithActivities`](https://clerk.com/docs/reference/types/session-with-activities) objects. + */ getSessions: () => Promise; + /** + * Adds the user's profile image or replaces it if one already exists. This method will upload an image and associate it with the user. + */ setProfileImage: (params: SetProfileImageParams) => Promise; + /** + * Adds an external account for the user. A new [`ExternalAccount`](https://clerk.com/docs/reference/types/external-account) will be created and associated with the user. This method is useful if you want to allow an already signed-in user to connect their account with an external provider, such as Facebook, GitHub, etc., so that they can sign in with that provider in the future. + * + * > [!WARNING] + * > The social provider that you want to connect to [must be enabled](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#sso-connections) in your app's settings in the Clerk Dashboard. + */ createExternalAccount: (params: CreateExternalAccountParams) => Promise; getOrganizationMemberships: GetOrganizationMemberships; + /** + * Gets a list of Organization invitations for the user. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`UserOrganizationInvitation`](https://clerk.com/docs/reference/types/user-organization-invitation) objects. + */ getOrganizationInvitations: ( params?: GetUserOrganizationInvitationsParams, ) => Promise>; + /** + * Gets a list of Organization suggestions for the user. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationSuggestionResource`](https://clerk.com/docs/reference/types/organization-suggestion) objects. + */ getOrganizationSuggestions: ( params?: GetUserOrganizationSuggestionsParams, ) => Promise>; + /** + * Gets organization creation defaults for the current user. + * @returns A [`OrganizationCreationDefaultsResource`](https://clerk.com/docs/reference/types/organization-creation-defaults) object. + */ getOrganizationCreationDefaults: () => Promise; + /** + * Leaves an organization that the user is a member of. + * @param organizationId - The ID of the organization to leave. + * @returns A [`DeletedObjectResource`](https://clerk.com/docs/reference/types/deleted-object-resource) object. + */ leaveOrganization: (organizationId: string) => Promise; getEnterpriseConnections: (params?: GetEnterpriseConnectionsParams) => Promise; createEnterpriseConnection: ( @@ -145,9 +322,34 @@ export interface UserResource extends ClerkResource, BillingPayerMethods { enterpriseConnectionId: string, params?: GetEnterpriseConnectionTestRunsParams, ) => Promise>; + /** + * Generates a TOTP secret for a user that can be used to register the application on the user's authenticator app of choice. If this method is called again (while still unverified), it replaces the previously generated secret. + * @returns A [`TOTPResource`](https://clerk.com/docs/reference/types/totp-resource) object. + * + * > [!WARNING] + * > The **Authenticator application** multi-factor strategy must be enabled in your app's settings in the Clerk Dashboard. See the [Multi-factor authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#multi-factor-authentication) section to learn more. + */ createTOTP: () => Promise; + /** + * Verifies a TOTP secret after a user has created it. The user must provide a code from their authenticator app that has been generated using the previously created secret. This way, correct set up and ownership of the authenticator app can be validated. + * @returns A [`TOTPResource`](https://clerk.com/docs/reference/types/totp-resource) object. + * + * > [!WARNING] + * > The **Authenticator application** multi-factor strategy must be enabled in your app's settings in the Clerk Dashboard. See the [Multi-factor authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#multi-factor-authentication) section to learn more. + */ verifyTOTP: (params: VerifyTOTPParams) => Promise; + /** + * Disables TOTP by deleting the user's TOTP secret. + * @returns A [`DeletedObjectResource`](https://clerk.com/docs/reference/types/deleted-object-resource) object. + * + * > [!WARNING] + * > The **Authenticator application** multi-factor strategy must be enabled in your app's settings in the Clerk Dashboard. See the [Multi-factor authentication](https://clerk.com/docs/guides/configure/auth-strategies/sign-up-sign-in-options#multi-factor-authentication) section to learn more. + */ disableTOTP: () => Promise; + /** + * Generates a fresh new set of backup codes for the user. Every time the method is called, it will replace the previously generated backup codes. + * @returns A [`BackupCodeResource`](https://clerk.com/docs/reference/types/backup-code-resource) object. + */ createBackupCode: () => Promise; get verifiedExternalAccounts(): ExternalAccountResource[]; @@ -163,19 +365,69 @@ export interface UserResource extends ClerkResource, BillingPayerMethods { __internal_toSnapshot: () => UserJSONSnapshot; } -export type CreateEmailAddressParams = { email: string }; -export type CreatePhoneNumberParams = { phoneNumber: string }; -export type CreateWeb3WalletParams = { web3Wallet: string }; -export type SetProfileImageParams = { file: Blob | File | string | null }; +/** @generateWithEmptyComment */ +export type CreateEmailAddressParams = { + /** + * The email address to add to the user. + */ + email: string; +}; +/** @generateWithEmptyComment */ +export type CreatePhoneNumberParams = { + /** + * The phone number to add to the user. + */ + phoneNumber: string; +}; +/** @generateWithEmptyComment */ +export type CreateWeb3WalletParams = { + /** + * The Web3 wallet address, made up of either 0x + 40 hexadecimal characters or a `base58` encoded `ed25519` public key (for Solana wallets). + */ + web3Wallet: string; +}; +/** @generateWithEmptyComment */ +export type SetProfileImageParams = { + /** + * The file to set as the user's profile image, or `null` to remove the current image. + */ + file: Blob | File | string | null; +}; +/** @generateWithEmptyComment */ export type CreateExternalAccountParams = { + /** + * The strategy corresponding to the OAuth provider. For example: `'oauth_google'`. + */ strategy?: OAuthStrategy; + /** + * The ID of the enterprise connection to connect to the user. + */ enterpriseConnectionId?: string; + /** + * The full URL or path that the OAuth provider should redirect to, on successful authorization on their part. Typically, this will be a simple `/sso-callback` route that calls [`Clerk.handleRedirectCallback`](https://clerk.com/docs/reference/objects/clerk#handle-redirect-callback) or mounts the [``](https://clerk.com/docs/reference/components/control/authenticate-with-redirect-callback) component. See the [custom flow](https://clerk.com/docs/guides/development/custom-flows/authentication/oauth-connections) for implementation details. + + */ redirectUrl?: string; + /** + * Additional scopes for your user to be prompted to approve. + */ additionalScopes?: OAuthScope[]; + /** + * The value to pass to the [OIDC `prompt` parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=prompt,reauthentication%20and%20consent.) in the generated OAuth redirect URL. + */ oidcPrompt?: string; + /** + * The value to pass to the [OIDC `login_hint` parameter](https://openid.net/specs/openid-connect-core-1_0.html#:~:text=login_hint,in%20\(if%20necessary\).) in the generated OAuth redirect URL. + */ oidcLoginHint?: string; }; -export type VerifyTOTPParams = { code: string }; +/** @generateWithEmptyComment */ +export type VerifyTOTPParams = { + /** + * The code to verify. + */ + code: string; +}; type UpdateUserJSON = Pick< UserJSON, @@ -190,34 +442,60 @@ type UpdateUserJSON = Pick< export type UpdateUserParams = Partial>; -/** - * Parameters for {@link UserResource.updateMetadata}. Only `unsafeMetadata` - * is end-user-writable on the Frontend API and the field is required: the - * submitted value is deep-merged with the existing `unsafeMetadata`, and keys - * at any level whose value is `null` are removed. - */ +/** @generateWithEmptyComment */ export type UpdateUserMetadataParams = { + /** + * The metadata to deep-merge with the user's existing `unsafeMetadata`. Keys at any nesting level whose value is `null` are removed. + */ unsafeMetadata: UserUnsafeMetadata; }; +/** @generateWithEmptyComment */ export type UpdateUserPasswordParams = { + /** + * The user's new password. + */ newPassword: string; + /** + * The user's current password. + */ currentPassword?: string; + /** + * Whether to sign out the user from all their active sessions once their password is updated. + */ signOutOfOtherSessions?: boolean; }; -export type RemoveUserPasswordParams = Pick; +/** @generateWithEmptyComment */ +export type RemoveUserPasswordParams = { + /** + * The user's current password. + */ + currentPassword?: string; +}; +/** @generateWithEmptyComment */ export type GetUserOrganizationInvitationsParams = ClerkPaginationParams<{ + /** + * The status an invitation can have. + */ status?: OrganizationInvitationStatus; }>; +/** @generateWithEmptyComment */ export type GetUserOrganizationSuggestionsParams = ClerkPaginationParams<{ + /** + * The status a suggestion can have. + */ status?: OrganizationSuggestionStatus | OrganizationSuggestionStatus[]; }>; export type GetUserOrganizationMembershipParams = ClerkPaginationParams; +/** + * Gets a list of Organization memberships for the user. + * @returns A [`ClerkPaginatedResponse`](https://clerk.com/docs/reference/types/clerk-paginated-response) of [`OrganizationMembershipResource`](https://clerk.com/docs/reference/types/organization-membership) objects. + */ export type GetOrganizationMemberships = ( params?: GetUserOrganizationMembershipParams, ) => Promise>; diff --git a/packages/shared/src/types/waitlist.ts b/packages/shared/src/types/waitlist.ts index 52f16a427b6..06e6258e624 100644 --- a/packages/shared/src/types/waitlist.ts +++ b/packages/shared/src/types/waitlist.ts @@ -23,6 +23,10 @@ export interface WaitlistResource extends ClerkResource { join: (params: JoinWaitlistParams) => Promise<{ error: ClerkError | null }>; } +/** @generateWithEmptyComment */ export type JoinWaitlistParams = { + /** + * The email address of the user to add to the waitlist. + */ emailAddress: string; }; diff --git a/packages/shared/src/types/web3.ts b/packages/shared/src/types/web3.ts index 450c8533946..0b38b6f52cb 100644 --- a/packages/shared/src/types/web3.ts +++ b/packages/shared/src/types/web3.ts @@ -6,14 +6,21 @@ export interface Web3ProviderData { name: string; } +/** @inline */ export type MetamaskWeb3Provider = 'metamask'; +/** @inline */ export type CoinbaseWalletWeb3Provider = 'coinbase_wallet'; +/** @inline */ export type OKXWalletWeb3Provider = 'okx_wallet'; +/** @inline */ export type BaseWeb3Provider = 'base'; +/** @inline */ export type SolanaWeb3Provider = 'solana'; +/** @inline */ export type Web3Provider = EthereumWeb3Provider | SolanaWeb3Provider; +/** @inline */ export type EthereumWeb3Provider = | MetamaskWeb3Provider | BaseWeb3Provider diff --git a/packages/ui/src/internal/appearance.ts b/packages/ui/src/internal/appearance.ts index 7a4fa14ff68..512d0dd8e5c 100644 --- a/packages/ui/src/internal/appearance.ts +++ b/packages/ui/src/internal/appearance.ts @@ -933,7 +933,7 @@ export type BaseTheme = (BaseThemeTaggedType | 'clerk' | 'simple') & { cssLayerN export type Theme = { /** * A theme used as the base theme for the components. - * For further customisation, you can use the {@link Theme.options}, {@link Theme.variables} and {@link Theme.elements} props. + * For further customization, you can use the {@link Theme.options}, {@link Theme.variables} and {@link Theme.elements} props. * * Supports both object-based themes and string-based themes: * diff --git a/packages/ui/src/styledSystem/StyleCacheProvider.tsx b/packages/ui/src/styledSystem/StyleCacheProvider.tsx index 55ee736f5f4..0863f32172b 100644 --- a/packages/ui/src/styledSystem/StyleCacheProvider.tsx +++ b/packages/ui/src/styledSystem/StyleCacheProvider.tsx @@ -7,9 +7,9 @@ import React, { useMemo } from 'react'; const el = document.querySelector('style#cl-style-insertion-point'); type StyleCacheProviderProps = React.PropsWithChildren<{ - /** Optional nonce value for CSP (Content Security Policy) */ + /** The nonce value for CSP (Content Security Policy). */ nonce?: string; - /** Optional CSS layer name to wrap styles in */ + /** The CSS layer name to wrap styles in. */ cssLayerName?: string; }>; diff --git a/packages/vue/src/plugin.ts b/packages/vue/src/plugin.ts index 0aba60a8d0c..7c6ff11109e 100644 --- a/packages/vue/src/plugin.ts +++ b/packages/vue/src/plugin.ts @@ -32,7 +32,7 @@ export type PluginOptions = Without< initialState?: InitialState; appearance?: Appearance; /** - * Optional object to use the bundled Clerk UI instead of loading from CDN. + * An object to use the bundled Clerk UI instead of loading from CDN. * Import `ui` from `@clerk/ui` and pass it here to bundle the UI with your application. * When omitted, UI is loaded from Clerk's CDN. */ diff --git a/scripts/renovate-config-generator.mjs b/scripts/renovate-config-generator.mjs index 5cd9ae09594..749e4f443f3 100644 --- a/scripts/renovate-config-generator.mjs +++ b/scripts/renovate-config-generator.mjs @@ -203,13 +203,7 @@ const renovateConfig = { 'integration/templates/**', 'packages/upgrade/src/__tests__/fixtures/**', ], - includePaths: [ - '.github/actions/**', - '.github/workflows/**', - 'package.json', - 'packages/**', - 'pnpm-workspace.yaml', - ], + includePaths: ['.github/actions/**', '.github/workflows/**', 'package.json', 'packages/**', 'pnpm-workspace.yaml'], major: { dependencyDashboardApproval: true }, minimumReleaseAge: '3 days', nvm: { enabled: false }, diff --git a/tsconfig.typedoc.json b/tsconfig.typedoc.json index f2461cbc421..71338f87dc4 100644 --- a/tsconfig.typedoc.json +++ b/tsconfig.typedoc.json @@ -6,5 +6,5 @@ "strict": false, "importHelpers": false }, - "exclude": ["node_modules", "dist", "**/dist/**", "packages/*/dist/**", "**/*.test.ts', '**/*.test.tsx"] + "exclude": ["node_modules", "dist", "**/dist/**", "packages/*/dist/**", "**/*.test.ts", "**/*.test.tsx"] } diff --git a/turbo.json b/turbo.json index 45f99b43aa8..c5dc2142264 100644 --- a/turbo.json +++ b/turbo.json @@ -341,8 +341,8 @@ }, "//#typedoc:generate": { "dependsOn": ["@clerk/nextjs#build", "@clerk/react#build", "@clerk/shared#build"], - "inputs": ["tsconfig.typedoc.json", "typedoc.config.mjs"], - "outputs": [".typedoc/**"], + "inputs": ["tsconfig.typedoc.json", "typedoc.config.mjs", ".typedoc/**/*.mjs"], + "outputs": [".typedoc/docs/**"], "outputLogs": "new-only" }, "//#test:typedoc": { diff --git a/typedoc.config.mjs b/typedoc.config.mjs index bbd02278b1a..77a8e44470d 100644 --- a/typedoc.config.mjs +++ b/typedoc.config.mjs @@ -81,11 +81,21 @@ const config = { './.typedoc/custom-router.mjs', './.typedoc/custom-theme.mjs', './.typedoc/custom-plugin.mjs', + /** Must load after custom-plugin.mjs so its END listener (link replacements) fires first. */ + './.typedoc/extract-methods.mjs', ], theme: 'clerkTheme', router: 'clerk-router', readme: 'none', - notRenderedTags: [...OptionDefaults.notRenderedTags, ...CUSTOM_BLOCK_TAGS], + notRenderedTags: [ + ...OptionDefaults.notRenderedTags, + ...CUSTOM_BLOCK_TAGS, + /** Parsed for router/theme; must not appear as a doc section (otherwise renders as **Inline**). */ + '@inline', + '@inlineType', + /** Opts into a dedicated reference page despite `@inline` (see `.typedoc/standalone-page-tag.mjs`). */ + '@standalonePage', + ], packageOptions: { includeVersion: false, excludePrivate: true, @@ -96,7 +106,29 @@ const config = { excludeNotDocumented: true, gitRevision: 'main', blockTags: [...OptionDefaults.blockTags, ...CUSTOM_BLOCK_TAGS], - modifierTags: [...OptionDefaults.modifierTags.filter(tag => tag !== '@experimental')], + modifierTags: [ + ...OptionDefaults.modifierTags.filter(tag => tag !== '@experimental'), + /** Suppresses the Parameters table in `.typedoc/extract-methods.mjs` method MDX. */ + '@skipParametersSection', + /** + * On a reference-object property whose value is an inline object type: omit the parent from the main Properties table; + * extract each callable member as `methods/-.mdx` and each non-callable object member as a nested heading + property table (see `.typedoc/extract-methods.mjs`). + */ + '@extractMethods', + /** Type-only / router hints; not user-facing prose (see `notRenderedTags`). */ + '@inline', + '@inlineType', + /** With `@inline`, still emit a standalone `.mdx` page (see `.typedoc/standalone-page-tag.mjs`). */ + '@standalonePage', + /** Self-documenting placeholder for declarations intentionally left without a description. */ + '@generateWithEmptyComment', + ], + /** + * Keep `@inline` / `@inlineType` / `@standalonePage` in the model so the custom router and theme can read them. + */ + excludeTags: OptionDefaults.excludeTags.filter( + tag => tag !== '@inline' && tag !== '@inlineType' && tag !== '@standalonePage', + ), exclude: ['src/**/*.test.ts', 'src/**/*.test.tsx'], readme: 'none', disableGit: true,