From 02858053a32711d1418db5f83aee4b04350c6892 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Mon, 7 Sep 2026 14:07:00 -0600 Subject: [PATCH 1/9] docs(shared): document OAuth device verification types --- .changeset/oauth-device-verification-docs.md | 5 ++ .../hooks/useOAuthDeviceVerification.types.ts | 32 +++++++++++ packages/shared/src/types/oauthApplication.ts | 56 ++++++++++++++++++- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 .changeset/oauth-device-verification-docs.md diff --git a/.changeset/oauth-device-verification-docs.md b/.changeset/oauth-device-verification-docs.md new file mode 100644 index 00000000000..37316627ebf --- /dev/null +++ b/.changeset/oauth-device-verification-docs.md @@ -0,0 +1,5 @@ +--- +'@clerk/shared': patch +--- + +Document the public fields, actions, and parameter types for OAuth device verification flows. diff --git a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts index 9b223a58caf..0dd1a8279a9 100644 --- a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts +++ b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts @@ -9,14 +9,46 @@ import type { type DecisionParams = Omit; +/** + * The current state and actions for an OAuth device verification flow. + * + * @interface + */ export type UseOAuthDeviceVerificationReturn = { + /** + * Information about the device authorization returned by the latest successful lookup, or `undefined` if no lookup has succeeded. + */ data: OAuthDeviceVerificationInfo | undefined; + /** + * The result of the latest approval or denial, or `undefined` if no decision has succeeded. + */ result: OAuthDeviceVerificationResult | undefined; + /** + * The most recent error returned while looking up or submitting a device authorization, or `null` if no error occurred. + */ error: ClerkAPIResponseError | ClerkRuntimeError | null; + /** + * Whether a device authorization lookup is in progress. + */ isLoading: boolean; + /** + * Whether an approval or denial is in progress. + */ isSubmitting: boolean; + /** + * Looks up a device authorization by its user code. + */ lookup: (params: LookupOAuthDeviceVerificationParams) => Promise; + /** + * Approves a device authorization. + */ approve: (params: DecisionParams) => Promise; + /** + * Denies a device authorization. + */ deny: (params: LookupOAuthDeviceVerificationParams) => Promise; + /** + * Clears the current device authorization state. + */ reset: () => void; }; diff --git a/packages/shared/src/types/oauthApplication.ts b/packages/shared/src/types/oauthApplication.ts index 584c976bc65..4ca73719910 100644 --- a/packages/shared/src/types/oauthApplication.ts +++ b/packages/shared/src/types/oauthApplication.ts @@ -101,31 +101,63 @@ export type OAuthConsentInfo = { scopes: OAuthConsentScope[]; }; +/** + * The current status of an OAuth device authorization. + */ export type OAuthDeviceVerificationStatus = 'pending' | 'approved' | 'denied' | 'consumed'; /** * A scope requested by an OAuth device authorization. + * + * @interface */ export type OAuthDeviceVerificationScope = OAuthConsentScope; /** * Information about an OAuth device authorization awaiting verification. + * + * @interface */ export type OAuthDeviceVerificationInfo = { + /** + * The display name of the OAuth application requesting authorization. + */ oauthApplicationName: string; + /** + * The URL of the OAuth application's logo image, or `null` if no logo is available. + */ oauthApplicationLogoUrl: string | null; + /** + * The OAuth `client_id` that identifies the application requesting authorization. + */ clientId: string; + /** + * The scopes the OAuth application is requesting. + */ scopes: OAuthDeviceVerificationScope[]; + /** + * The current status of the device authorization. + */ status: OAuthDeviceVerificationStatus; - /** Expiration time as Unix milliseconds. */ + /** + * The expiration time of the device authorization, as a Unix timestamp in milliseconds. + */ expiresAt: number; }; /** * The result of approving or denying an OAuth device authorization. + * + * @interface */ export type OAuthDeviceVerificationResult = { + /** + * The type of the resource. + */ object: 'oauth_device_verification'; + /** + * The final decision for the device authorization. + */ status: Extract; }; @@ -138,13 +170,35 @@ export type GetOAuthConsentInfoParams = { redirectUri?: string; }; +/** + * The parameters for looking up an OAuth device authorization. + * + * @interface + */ export type LookupOAuthDeviceVerificationParams = { + /** + * The user code displayed by the device requesting authorization. + */ userCode: string; }; +/** + * The parameters for approving or denying an OAuth device authorization. + * + * @interface + */ export type SubmitOAuthDeviceVerificationParams = { + /** + * The user code displayed by the device requesting authorization. + */ userCode: string; + /** + * Whether to approve or deny the authorization request. + */ approved: boolean; + /** + * The ID of the Organization to authorize the request for. Omit this to authorize the request for the user's personal account. + */ organizationId?: string; }; From cc21fd2f1fe95a7096d7734ede4458e04b947fbc Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 13:14:29 -0600 Subject: [PATCH 2/9] docs(shared): fix OAuth device verification TypeDoc output --- .../relative-link-replacements.test.ts | 30 +++++++++++++++++++ .typedoc/custom-plugin.mjs | 6 ++++ .../hooks/useOAuthDeviceVerification.types.ts | 4 +-- packages/shared/src/types/oauthApplication.ts | 20 +++++++++++-- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/.typedoc/__tests__/relative-link-replacements.test.ts b/.typedoc/__tests__/relative-link-replacements.test.ts index cf98e65efb9..b4dcc32c840 100644 --- a/.typedoc/__tests__/relative-link-replacements.test.ts +++ b/.typedoc/__tests__/relative-link-replacements.test.ts @@ -50,6 +50,36 @@ describe('applyRelativeLinkReplacements', () => { '[x](billing-proration-credit-detail.mdx)', '[x](/docs/reference/types/billing-proration-credit-detail)', ], + [ + 'OAuth device verification info routes to its standalone page', + '[x](o-auth-device-verification-info.mdx)', + '[x](/docs/reference/types/oauth-device-verification-info)', + ], + [ + 'OAuth device verification result routes to its standalone page', + '[x](o-auth-device-verification-result.mdx)', + '[x](/docs/reference/types/oauth-device-verification-result)', + ], + [ + 'OAuth device verification status routes to its standalone page', + '[x](o-auth-device-verification-status.mdx)', + '[x](/docs/reference/types/oauth-device-verification-status)', + ], + [ + 'lookup OAuth device verification params route to their standalone page', + '[x](lookup-o-auth-device-verification-params.mdx)', + '[x](/docs/reference/types/lookup-oauth-device-verification-params)', + ], + [ + 'submit OAuth device verification params route to their standalone page', + '[x](submit-o-auth-device-verification-params.mdx)', + '[x](/docs/reference/types/submit-oauth-device-verification-params)', + ], + [ + 'useOAuthDeviceVerification return routes to the hook returns section', + '[x](use-o-auth-device-verification-return.mdx)', + '[x](/docs/reference/hooks/use-oauth-device-verification#returns)', + ], [ 'resolves relative path prefixes', '[x](../../types/billing-credits.mdx)', diff --git a/.typedoc/custom-plugin.mjs b/.typedoc/custom-plugin.mjs index 6b0b71db41f..d0e86325fad 100644 --- a/.typedoc/custom-plugin.mjs +++ b/.typedoc/custom-plugin.mjs @@ -75,6 +75,12 @@ const LINK_REPLACEMENTS = [ ['o-auth-application-namespace', '/docs/reference/types/oauth-application'], ['o-auth-consent-info', '/docs/reference/types/oauth-consent-info'], ['o-auth-consent-scope', '/docs/reference/types/oauth-consent-scope'], + ['lookup-o-auth-device-verification-params', '/docs/reference/types/lookup-oauth-device-verification-params'], + ['o-auth-device-verification-info', '/docs/reference/types/oauth-device-verification-info'], + ['o-auth-device-verification-result', '/docs/reference/types/oauth-device-verification-result'], + ['o-auth-device-verification-status', '/docs/reference/types/oauth-device-verification-status'], + ['submit-o-auth-device-verification-params', '/docs/reference/types/submit-oauth-device-verification-params'], + ['use-o-auth-device-verification-return', '/docs/reference/hooks/use-oauth-device-verification#returns'], ['o-auth-strategy', '/docs/reference/types/sso#o-auth-strategy'], ['o-auth-provider', '/docs/reference/types/sso#o-auth-provider'], ['session', '/docs/reference/backend/types/backend-session'], diff --git a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts index 0dd1a8279a9..56305cdcab3 100644 --- a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts +++ b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts @@ -7,8 +7,6 @@ import type { SubmitOAuthDeviceVerificationParams, } from '../../types'; -type DecisionParams = Omit; - /** * The current state and actions for an OAuth device verification flow. * @@ -42,7 +40,7 @@ export type UseOAuthDeviceVerificationReturn = { /** * Approves a device authorization. */ - approve: (params: DecisionParams) => Promise; + approve: (params: Omit) => Promise; /** * Denies a device authorization. */ diff --git a/packages/shared/src/types/oauthApplication.ts b/packages/shared/src/types/oauthApplication.ts index 4ca73719910..35b42ed1dff 100644 --- a/packages/shared/src/types/oauthApplication.ts +++ b/packages/shared/src/types/oauthApplication.ts @@ -104,7 +104,23 @@ export type OAuthConsentInfo = { /** * The current status of an OAuth device authorization. */ -export type OAuthDeviceVerificationStatus = 'pending' | 'approved' | 'denied' | 'consumed'; +export type OAuthDeviceVerificationStatus = + /** + * The device authorization is awaiting approval or denial. + */ + | 'pending' + /** + * The device authorization was approved. + */ + | 'approved' + /** + * The device authorization was denied. + */ + | 'denied' + /** + * The approved device authorization has already been used by the device. + */ + | 'consumed'; /** * A scope requested by an OAuth device authorization. @@ -114,7 +130,7 @@ export type OAuthDeviceVerificationStatus = 'pending' | 'approved' | 'denied' | export type OAuthDeviceVerificationScope = OAuthConsentScope; /** - * Information about an OAuth device authorization awaiting verification. + * Information about an OAuth device authorization. * * @interface */ From 153bc28dc164abf42d568429663280cdf57b4921 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 13:58:03 -0600 Subject: [PATCH 3/9] docs(shared): inline OAuth device verification status --- .typedoc/__tests__/file-structure.test.ts | 11 ++++++++++- .typedoc/custom-tags.mjs | 1 + .typedoc/custom-theme.mjs | 6 +++--- .typedoc/standalone-page-tag.mjs | 15 +++++++++++++++ packages/shared/src/types/oauthApplication.ts | 2 ++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/.typedoc/__tests__/file-structure.test.ts b/.typedoc/__tests__/file-structure.test.ts index af306bbe658..654ddd9f911 100644 --- a/.typedoc/__tests__/file-structure.test.ts +++ b/.typedoc/__tests__/file-structure.test.ts @@ -1,4 +1,4 @@ -import { readdir } from 'fs/promises'; +import { readFile, readdir } from 'fs/promises'; import { join, relative } from 'path'; import { describe, expect, it } from 'vitest'; @@ -28,6 +28,15 @@ function isTopLevelPath(filePath: string) { } describe('Typedoc output', () => { + it('inlines OAuth device verification statuses while preserving their standalone page', async () => { + const info = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-info.mdx'), 'utf8'); + const status = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-status.mdx'), 'utf8'); + + expect(info).toContain('"pending" \\| "approved" \\| "denied" \\| "consumed"'); + expect(info).not.toContain('[OAuthDeviceVerificationStatus]'); + expect(status).toContain('The current status of an OAuth device authorization.'); + }); + it('should only have these top-level folders', async () => { const folders = await scanDirectory('directory'); const topLevelFolders = folders.filter(isTopLevelPath); diff --git a/.typedoc/custom-tags.mjs b/.typedoc/custom-tags.mjs index ea2f5abb8d7..fdd6f0bc9e4 100644 --- a/.typedoc/custom-tags.mjs +++ b/.typedoc/custom-tags.mjs @@ -24,6 +24,7 @@ export const CUSTOM_MODIFIER_TAGS = [ '@extractMethods', /** Type-only / router hints; not user-facing prose (see `notRenderedTags` in `typedoc.config.mjs`). */ '@inline', + /** Expands references to the type while preserving its standalone page. */ '@inlineType', /** With `@inline`, still emit a standalone `.mdx` page (see `.typedoc/standalone-page-tag.mjs`). */ '@standalonePage', diff --git a/.typedoc/custom-theme.mjs b/.typedoc/custom-theme.mjs index c2c0d1c79c3..f5b042c4ee6 100644 --- a/.typedoc/custom-theme.mjs +++ b/.typedoc/custom-theme.mjs @@ -5,7 +5,7 @@ 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 { isInlineModifierWithoutStandalonePage, shouldInlineTypeReference } from './standalone-page-tag.mjs'; import { unwrapOptional } from './type-utils.mjs'; export { REFERENCE_OBJECTS_LIST }; @@ -68,7 +68,7 @@ function isArrayElementReferenceInliningToUnion(elementType) { if (!ref.reflection) { return false; } - if (!isInlineModifierWithoutStandalonePage(ref.reflection)) { + if (!shouldInlineTypeReference(ref.reflection)) { return false; } const decl = /** @type {import('typedoc').DeclarationReflection} */ (ref.reflection); @@ -1181,7 +1181,7 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { * @param {import('typedoc').ReferenceType} model */ referenceType: model => { - if (isInlineModifierWithoutStandalonePage(model.reflection)) { + if (shouldInlineTypeReference(model.reflection)) { const decl = /** @type {import('typedoc').DeclarationReflection} */ (model.reflection); // Generic instantiation, e.g. `Fn` — let `someType` apply type arguments. if (model.typeArguments?.length) { diff --git a/.typedoc/standalone-page-tag.mjs b/.typedoc/standalone-page-tag.mjs index 20cf25c55e4..884241013e8 100644 --- a/.typedoc/standalone-page-tag.mjs +++ b/.typedoc/standalone-page-tag.mjs @@ -22,3 +22,18 @@ export function isInlineModifierWithoutStandalonePage(reflection) { } return true; } + +/** + * @param {import('typedoc').Reflection | undefined} reflection + * @returns {boolean} True when references to a type should render its underlying shape instead of a link. + */ +export function shouldInlineTypeReference(reflection) { + if (isInlineModifierWithoutStandalonePage(reflection)) { + return true; + } + const comment = + reflection && 'comment' in reflection + ? /** @type {{ comment?: import('typedoc').Comment | undefined }} */ (reflection).comment + : undefined; + return comment?.hasModifier('@inlineType') ?? false; +} diff --git a/packages/shared/src/types/oauthApplication.ts b/packages/shared/src/types/oauthApplication.ts index 35b42ed1dff..d47c63fb99b 100644 --- a/packages/shared/src/types/oauthApplication.ts +++ b/packages/shared/src/types/oauthApplication.ts @@ -103,6 +103,8 @@ export type OAuthConsentInfo = { /** * The current status of an OAuth device authorization. + * + * @inlineType */ export type OAuthDeviceVerificationStatus = /** From b5a735c7708c1f02df312077120a1581dbcd867f Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 14:01:57 -0600 Subject: [PATCH 4/9] docs(shared): simplify device verification hook return --- .typedoc/__tests__/file-structure.test.ts | 11 +++++++++++ .typedoc/custom-plugin.mjs | 1 + .../react/hooks/useOAuthDeviceVerification.types.ts | 2 -- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.typedoc/__tests__/file-structure.test.ts b/.typedoc/__tests__/file-structure.test.ts index 654ddd9f911..b66af3d60f0 100644 --- a/.typedoc/__tests__/file-structure.test.ts +++ b/.typedoc/__tests__/file-structure.test.ts @@ -28,6 +28,17 @@ function isTopLevelPath(filePath: string) { } describe('Typedoc output', () => { + it('renders the OAuth device verification hook return as an embeddable table', async () => { + const hookReturn = await readFile( + join(OUTPUT_LOCATION, 'shared/use-o-auth-device-verification-return.mdx'), + 'utf8', + ); + + expect(hookReturn).not.toContain('The current state and actions for an OAuth device verification flow.'); + expect(hookReturn).not.toContain('## Properties'); + expect(hookReturn).toMatch(/^\| Property/); + }); + it('inlines OAuth device verification statuses while preserving their standalone page', async () => { const info = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-info.mdx'), 'utf8'); const status = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-status.mdx'), 'utf8'); diff --git a/.typedoc/custom-plugin.mjs b/.typedoc/custom-plugin.mjs index d0e86325fad..a4df6b55387 100644 --- a/.typedoc/custom-plugin.mjs +++ b/.typedoc/custom-plugin.mjs @@ -40,6 +40,7 @@ const FILES_WITHOUT_HEADINGS = [ 'use-organization-creation-defaults-params.mdx', 'use-o-auth-consent-params.mdx', 'use-o-auth-consent-return.mdx', + 'use-o-auth-device-verification-return.mdx', 'create-organization-domain-params.mdx', ]; diff --git a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts index 56305cdcab3..228503025c6 100644 --- a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts +++ b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts @@ -8,8 +8,6 @@ import type { } from '../../types'; /** - * The current state and actions for an OAuth device verification flow. - * * @interface */ export type UseOAuthDeviceVerificationReturn = { From dc60f42828cefc4a3be2662bbb8a58195f297aa0 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 14:16:37 -0600 Subject: [PATCH 5/9] refactor(repo): simplify device verification TypeDoc --- .typedoc/__tests__/file-structure.test.ts | 6 ++-- .../relative-link-replacements.test.ts | 30 ------------------- .typedoc/custom-plugin.mjs | 6 ---- .typedoc/custom-tags.mjs | 1 - .typedoc/custom-theme.mjs | 6 ++-- .typedoc/standalone-page-tag.mjs | 15 ---------- packages/shared/src/types/oauthApplication.ts | 2 +- 7 files changed, 7 insertions(+), 59 deletions(-) diff --git a/.typedoc/__tests__/file-structure.test.ts b/.typedoc/__tests__/file-structure.test.ts index b66af3d60f0..b0b98a84772 100644 --- a/.typedoc/__tests__/file-structure.test.ts +++ b/.typedoc/__tests__/file-structure.test.ts @@ -39,13 +39,13 @@ describe('Typedoc output', () => { expect(hookReturn).toMatch(/^\| Property/); }); - it('inlines OAuth device verification statuses while preserving their standalone page', async () => { + it('inlines OAuth device verification statuses without generating a standalone page', async () => { const info = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-info.mdx'), 'utf8'); - const status = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-status.mdx'), 'utf8'); + const sharedFiles = await readdir(join(OUTPUT_LOCATION, 'shared')); expect(info).toContain('"pending" \\| "approved" \\| "denied" \\| "consumed"'); expect(info).not.toContain('[OAuthDeviceVerificationStatus]'); - expect(status).toContain('The current status of an OAuth device authorization.'); + expect(sharedFiles).not.toContain('o-auth-device-verification-status.mdx'); }); it('should only have these top-level folders', async () => { diff --git a/.typedoc/__tests__/relative-link-replacements.test.ts b/.typedoc/__tests__/relative-link-replacements.test.ts index b4dcc32c840..cf98e65efb9 100644 --- a/.typedoc/__tests__/relative-link-replacements.test.ts +++ b/.typedoc/__tests__/relative-link-replacements.test.ts @@ -50,36 +50,6 @@ describe('applyRelativeLinkReplacements', () => { '[x](billing-proration-credit-detail.mdx)', '[x](/docs/reference/types/billing-proration-credit-detail)', ], - [ - 'OAuth device verification info routes to its standalone page', - '[x](o-auth-device-verification-info.mdx)', - '[x](/docs/reference/types/oauth-device-verification-info)', - ], - [ - 'OAuth device verification result routes to its standalone page', - '[x](o-auth-device-verification-result.mdx)', - '[x](/docs/reference/types/oauth-device-verification-result)', - ], - [ - 'OAuth device verification status routes to its standalone page', - '[x](o-auth-device-verification-status.mdx)', - '[x](/docs/reference/types/oauth-device-verification-status)', - ], - [ - 'lookup OAuth device verification params route to their standalone page', - '[x](lookup-o-auth-device-verification-params.mdx)', - '[x](/docs/reference/types/lookup-oauth-device-verification-params)', - ], - [ - 'submit OAuth device verification params route to their standalone page', - '[x](submit-o-auth-device-verification-params.mdx)', - '[x](/docs/reference/types/submit-oauth-device-verification-params)', - ], - [ - 'useOAuthDeviceVerification return routes to the hook returns section', - '[x](use-o-auth-device-verification-return.mdx)', - '[x](/docs/reference/hooks/use-oauth-device-verification#returns)', - ], [ 'resolves relative path prefixes', '[x](../../types/billing-credits.mdx)', diff --git a/.typedoc/custom-plugin.mjs b/.typedoc/custom-plugin.mjs index a4df6b55387..480260efe33 100644 --- a/.typedoc/custom-plugin.mjs +++ b/.typedoc/custom-plugin.mjs @@ -76,12 +76,6 @@ const LINK_REPLACEMENTS = [ ['o-auth-application-namespace', '/docs/reference/types/oauth-application'], ['o-auth-consent-info', '/docs/reference/types/oauth-consent-info'], ['o-auth-consent-scope', '/docs/reference/types/oauth-consent-scope'], - ['lookup-o-auth-device-verification-params', '/docs/reference/types/lookup-oauth-device-verification-params'], - ['o-auth-device-verification-info', '/docs/reference/types/oauth-device-verification-info'], - ['o-auth-device-verification-result', '/docs/reference/types/oauth-device-verification-result'], - ['o-auth-device-verification-status', '/docs/reference/types/oauth-device-verification-status'], - ['submit-o-auth-device-verification-params', '/docs/reference/types/submit-oauth-device-verification-params'], - ['use-o-auth-device-verification-return', '/docs/reference/hooks/use-oauth-device-verification#returns'], ['o-auth-strategy', '/docs/reference/types/sso#o-auth-strategy'], ['o-auth-provider', '/docs/reference/types/sso#o-auth-provider'], ['session', '/docs/reference/backend/types/backend-session'], diff --git a/.typedoc/custom-tags.mjs b/.typedoc/custom-tags.mjs index fdd6f0bc9e4..ea2f5abb8d7 100644 --- a/.typedoc/custom-tags.mjs +++ b/.typedoc/custom-tags.mjs @@ -24,7 +24,6 @@ export const CUSTOM_MODIFIER_TAGS = [ '@extractMethods', /** Type-only / router hints; not user-facing prose (see `notRenderedTags` in `typedoc.config.mjs`). */ '@inline', - /** Expands references to the type while preserving its standalone page. */ '@inlineType', /** With `@inline`, still emit a standalone `.mdx` page (see `.typedoc/standalone-page-tag.mjs`). */ '@standalonePage', diff --git a/.typedoc/custom-theme.mjs b/.typedoc/custom-theme.mjs index f5b042c4ee6..c2c0d1c79c3 100644 --- a/.typedoc/custom-theme.mjs +++ b/.typedoc/custom-theme.mjs @@ -5,7 +5,7 @@ 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, shouldInlineTypeReference } from './standalone-page-tag.mjs'; +import { isInlineModifierWithoutStandalonePage } from './standalone-page-tag.mjs'; import { unwrapOptional } from './type-utils.mjs'; export { REFERENCE_OBJECTS_LIST }; @@ -68,7 +68,7 @@ function isArrayElementReferenceInliningToUnion(elementType) { if (!ref.reflection) { return false; } - if (!shouldInlineTypeReference(ref.reflection)) { + if (!isInlineModifierWithoutStandalonePage(ref.reflection)) { return false; } const decl = /** @type {import('typedoc').DeclarationReflection} */ (ref.reflection); @@ -1181,7 +1181,7 @@ class ClerkMarkdownThemeContext extends MarkdownThemeContext { * @param {import('typedoc').ReferenceType} model */ referenceType: model => { - if (shouldInlineTypeReference(model.reflection)) { + 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) { diff --git a/.typedoc/standalone-page-tag.mjs b/.typedoc/standalone-page-tag.mjs index 884241013e8..20cf25c55e4 100644 --- a/.typedoc/standalone-page-tag.mjs +++ b/.typedoc/standalone-page-tag.mjs @@ -22,18 +22,3 @@ export function isInlineModifierWithoutStandalonePage(reflection) { } return true; } - -/** - * @param {import('typedoc').Reflection | undefined} reflection - * @returns {boolean} True when references to a type should render its underlying shape instead of a link. - */ -export function shouldInlineTypeReference(reflection) { - if (isInlineModifierWithoutStandalonePage(reflection)) { - return true; - } - const comment = - reflection && 'comment' in reflection - ? /** @type {{ comment?: import('typedoc').Comment | undefined }} */ (reflection).comment - : undefined; - return comment?.hasModifier('@inlineType') ?? false; -} diff --git a/packages/shared/src/types/oauthApplication.ts b/packages/shared/src/types/oauthApplication.ts index d47c63fb99b..f0a5f1fc922 100644 --- a/packages/shared/src/types/oauthApplication.ts +++ b/packages/shared/src/types/oauthApplication.ts @@ -104,7 +104,7 @@ export type OAuthConsentInfo = { /** * The current status of an OAuth device authorization. * - * @inlineType + * @inline */ export type OAuthDeviceVerificationStatus = /** From 53d41692f81a4612b24f8cb936f49d7e01bba5a6 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 14:21:44 -0600 Subject: [PATCH 6/9] docs(repo): reserve device verification routes --- .../relative-link-replacements.test.ts | 25 +++++++++++++++++++ .typedoc/custom-plugin.mjs | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/.typedoc/__tests__/relative-link-replacements.test.ts b/.typedoc/__tests__/relative-link-replacements.test.ts index cf98e65efb9..18fd59fcab3 100644 --- a/.typedoc/__tests__/relative-link-replacements.test.ts +++ b/.typedoc/__tests__/relative-link-replacements.test.ts @@ -50,6 +50,31 @@ describe('applyRelativeLinkReplacements', () => { '[x](billing-proration-credit-detail.mdx)', '[x](/docs/reference/types/billing-proration-credit-detail)', ], + [ + 'OAuth device verification info routes to its future standalone page', + '[x](o-auth-device-verification-info.mdx)', + '[x](/docs/reference/types/oauth-device-verification-info)', + ], + [ + 'OAuth device verification result routes to its future standalone page', + '[x](o-auth-device-verification-result.mdx)', + '[x](/docs/reference/types/oauth-device-verification-result)', + ], + [ + 'lookup OAuth device verification params route to their future standalone page', + '[x](lookup-o-auth-device-verification-params.mdx)', + '[x](/docs/reference/types/lookup-oauth-device-verification-params)', + ], + [ + 'submit OAuth device verification params route to their future standalone page', + '[x](submit-o-auth-device-verification-params.mdx)', + '[x](/docs/reference/types/submit-oauth-device-verification-params)', + ], + [ + 'useOAuthDeviceVerification return routes to the future hook returns section', + '[x](use-o-auth-device-verification-return.mdx)', + '[x](/docs/reference/hooks/use-oauth-device-verification#returns)', + ], [ 'resolves relative path prefixes', '[x](../../types/billing-credits.mdx)', diff --git a/.typedoc/custom-plugin.mjs b/.typedoc/custom-plugin.mjs index 480260efe33..4b39b6e4888 100644 --- a/.typedoc/custom-plugin.mjs +++ b/.typedoc/custom-plugin.mjs @@ -76,6 +76,11 @@ const LINK_REPLACEMENTS = [ ['o-auth-application-namespace', '/docs/reference/types/oauth-application'], ['o-auth-consent-info', '/docs/reference/types/oauth-consent-info'], ['o-auth-consent-scope', '/docs/reference/types/oauth-consent-scope'], + ['lookup-o-auth-device-verification-params', '/docs/reference/types/lookup-oauth-device-verification-params'], + ['o-auth-device-verification-info', '/docs/reference/types/oauth-device-verification-info'], + ['o-auth-device-verification-result', '/docs/reference/types/oauth-device-verification-result'], + ['submit-o-auth-device-verification-params', '/docs/reference/types/submit-oauth-device-verification-params'], + ['use-o-auth-device-verification-return', '/docs/reference/hooks/use-oauth-device-verification#returns'], ['o-auth-strategy', '/docs/reference/types/sso#o-auth-strategy'], ['o-auth-provider', '/docs/reference/types/sso#o-auth-provider'], ['session', '/docs/reference/backend/types/backend-session'], From 989d669d6f644b95b7c9c9d0d6bf7a8f948d0503 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 8 Sep 2026 14:22:46 -0600 Subject: [PATCH 7/9] test(repo): remove redundant TypeDoc assertions --- .typedoc/__tests__/file-structure.test.ts | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/.typedoc/__tests__/file-structure.test.ts b/.typedoc/__tests__/file-structure.test.ts index b0b98a84772..af306bbe658 100644 --- a/.typedoc/__tests__/file-structure.test.ts +++ b/.typedoc/__tests__/file-structure.test.ts @@ -1,4 +1,4 @@ -import { readFile, readdir } from 'fs/promises'; +import { readdir } from 'fs/promises'; import { join, relative } from 'path'; import { describe, expect, it } from 'vitest'; @@ -28,26 +28,6 @@ function isTopLevelPath(filePath: string) { } describe('Typedoc output', () => { - it('renders the OAuth device verification hook return as an embeddable table', async () => { - const hookReturn = await readFile( - join(OUTPUT_LOCATION, 'shared/use-o-auth-device-verification-return.mdx'), - 'utf8', - ); - - expect(hookReturn).not.toContain('The current state and actions for an OAuth device verification flow.'); - expect(hookReturn).not.toContain('## Properties'); - expect(hookReturn).toMatch(/^\| Property/); - }); - - it('inlines OAuth device verification statuses without generating a standalone page', async () => { - const info = await readFile(join(OUTPUT_LOCATION, 'shared/o-auth-device-verification-info.mdx'), 'utf8'); - const sharedFiles = await readdir(join(OUTPUT_LOCATION, 'shared')); - - expect(info).toContain('"pending" \\| "approved" \\| "denied" \\| "consumed"'); - expect(info).not.toContain('[OAuthDeviceVerificationStatus]'); - expect(sharedFiles).not.toContain('o-auth-device-verification-status.mdx'); - }); - it('should only have these top-level folders', async () => { const folders = await scanDirectory('directory'); const topLevelFolders = folders.filter(isTopLevelPath); From 9e6f0c61c12ab01bb1589132f4409c1151256006 Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Tue, 8 Sep 2026 22:59:39 -0500 Subject: [PATCH 8/9] docs(shared): clarify useOAuthDeviceVerification error field semantics Preflight rejections (Clerk not loaded, or a conflicting request already in progress) reject the returned promise without populating `error`, so `null` does not mean no error occurred. Note that callers must handle rejections from lookup/approve/deny directly. Co-Authored-By: Claude Opus 4.8 --- .../shared/src/react/hooks/useOAuthDeviceVerification.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts index 228503025c6..201822b8e03 100644 --- a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts +++ b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts @@ -20,7 +20,7 @@ export type UseOAuthDeviceVerificationReturn = { */ result: OAuthDeviceVerificationResult | undefined; /** - * The most recent error returned while looking up or submitting a device authorization, or `null` if no error occurred. + * The error from the most recent lookup or submission request, or `null` if the latest request succeeded or none has run yet. Preflight rejections (Clerk not loaded, or a conflicting request already in progress) reject the returned promise without setting this, so callers must also handle rejections from `lookup`, `approve`, and `deny`. */ error: ClerkAPIResponseError | ClerkRuntimeError | null; /** From da016f16c008357b9b0440926372a4434fb01928 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 9 Sep 2026 10:08:32 -0600 Subject: [PATCH 9/9] docs(shared): clarify device verification error state --- .../shared/src/react/hooks/useOAuthDeviceVerification.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts index 201822b8e03..878a58f67ab 100644 --- a/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts +++ b/packages/shared/src/react/hooks/useOAuthDeviceVerification.types.ts @@ -20,7 +20,7 @@ export type UseOAuthDeviceVerificationReturn = { */ result: OAuthDeviceVerificationResult | undefined; /** - * The error from the most recent lookup or submission request, or `null` if the latest request succeeded or none has run yet. Preflight rejections (Clerk not loaded, or a conflicting request already in progress) reject the returned promise without setting this, so callers must also handle rejections from `lookup`, `approve`, and `deny`. + * The latest error recorded by a lookup or submission operation, or `null` if no error has been recorded since the state was last cleared. Preflight rejections (Clerk not loaded, or a conflicting request already in progress) reject the returned promise without setting this, so callers must also handle rejections from `lookup`, `approve`, and `deny`. */ error: ClerkAPIResponseError | ClerkRuntimeError | null; /**