Skip to content

Commit d32d724

Browse files
SarahSoutoulNWylynkoalexisintech
authored
docs(repo): Generate all params and return types (hooks work) (#6901)
Co-authored-by: Nick Wylynko <nickwylynko@clerk.dev> Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com>
1 parent de5acba commit d32d724

18 files changed

+437
-44
lines changed

.changeset/violet-boxes-watch.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/shared': minor
3+
'@clerk/types': minor
4+
---
5+
6+
Ensure all hooks use typedoc for clerk docs

.typedoc/custom-plugin.mjs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const FILES_WITHOUT_HEADINGS = [
1010
'use-organization-params.mdx',
1111
'paginated-resources.mdx',
1212
'pages-or-infinite-options.mdx',
13-
'pages-or-infinite-options.mdx',
1413
'paginated-hook-config.mdx',
1514
'use-organization-list-return.mdx',
1615
'use-organization-list-params.mdx',
@@ -19,6 +18,21 @@ const FILES_WITHOUT_HEADINGS = [
1918
'verify-token-options.mdx',
2019
'public-organization-data-json.mdx',
2120
'organization-membership-public-user-data.mdx',
21+
'use-checkout-return.mdx',
22+
'use-checkout-options.mdx',
23+
'use-payment-element-return.mdx',
24+
'use-payment-methods-return.mdx',
25+
'use-payment-attempts-return.mdx',
26+
'use-plans-return.mdx',
27+
'use-statements-return.mdx',
28+
'hook-params.mdx',
29+
'use-subscription-params.mdx',
30+
'subscription-result.mdx',
31+
'needs-reverification-parameters.mdx',
32+
'use-reverification-options.mdx',
33+
'use-reverification-params.mdx',
34+
'payment-element-provider-props.mdx',
35+
'payment-element-props.mdx',
2236
];
2337

2438
/**
@@ -29,6 +43,8 @@ const LINK_REPLACEMENTS = [
2943
['set-active-params', '/docs/reference/javascript/types/set-active-params'],
3044
['clerk-paginated-response', '/docs/reference/javascript/types/clerk-paginated-response'],
3145
['paginated-resources', '#paginated-resources'],
46+
['use-checkout-options', '#use-checkout-options'],
47+
['needs-reverification-parameters', '#needs-reverification-parameters'],
3248
['create-organization-params', '#create-organization-params'],
3349
['session-resource', '/docs/reference/javascript/session'],
3450
['signed-in-session-resource', '/docs/reference/javascript/session'],
@@ -62,13 +78,18 @@ const LINK_REPLACEMENTS = [
6278
['billing-payer-resource', '/docs/reference/javascript/types/billing-payer-resource'],
6379
['billing-plan-resource', '/docs/reference/javascript/types/billing-plan-resource'],
6480
['billing-checkout-totals', '/docs/reference/javascript/types/billing-checkout-totals'],
81+
['billing-checkout-resource', '/docs/reference/javascript/types/billing-checkout-resource'],
6582
['billing-money-amount', '/docs/reference/javascript/types/billing-money-amount'],
6683
['billing-subscription-item-resource', '/docs/reference/javascript/types/billing-subscription-item-resource'],
6784
['feature-resource', '/docs/reference/javascript/types/feature-resource'],
6885
['billing-statement-group', '/docs/reference/javascript/types/billing-statement-group'],
86+
['billing-statement-resource', '/docs/reference/javascript/types/billing-statement-resource'],
87+
['billing-subscription-resource', '/docs/reference/javascript/types/billing-subscription-resource'],
88+
['clerk-api-response-error', '/docs/reference/javascript/types/clerk-api-response-error'],
6989
['billing-statement-totals', '/docs/reference/javascript/types/billing-statement-totals'],
7090
['billing-payment-resource', '/docs/reference/javascript/types/billing-payment-resource'],
7191
['deleted-object-resource', '/docs/reference/javascript/types/deleted-object-resource'],
92+
['use-checkout-return', '/docs/reference/hooks/use-checkout#returns'],
7293
];
7394

7495
/**
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// @ts-check
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
import { fileURLToPath } from 'node:url';
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
/**
10+
* Extracts the "## Returns" section from a markdown file and writes it to a separate file.
11+
* @param {string} filePath - The path to the markdown file
12+
* @returns {boolean} True if a file was created
13+
*/
14+
function extractReturnsSection(filePath) {
15+
const content = fs.readFileSync(filePath, 'utf-8');
16+
17+
// Find the "## Returns" section
18+
const returnsStart = content.indexOf('## Returns');
19+
20+
if (returnsStart === -1) {
21+
return false; // No Returns section found
22+
}
23+
24+
// Find the next heading after "## Returns" (or end of file)
25+
const afterReturns = content.slice(returnsStart + 10); // Skip past "## Returns"
26+
const nextHeadingMatch = afterReturns.match(/\n## /);
27+
const returnsEnd =
28+
nextHeadingMatch && typeof nextHeadingMatch.index === 'number'
29+
? returnsStart + 10 + nextHeadingMatch.index
30+
: content.length;
31+
32+
// Extract the Returns section and trim trailing whitespace
33+
const returnsContent = content.slice(returnsStart, returnsEnd).trimEnd();
34+
35+
// Generate the new filename: use-auth.mdx -> use-auth-return.mdx
36+
const fileName = path.basename(filePath, '.mdx');
37+
const dirName = path.dirname(filePath);
38+
const newFilePath = path.join(dirName, `${fileName}-return.mdx`);
39+
40+
// Write the extracted Returns section to the new file
41+
fs.writeFileSync(newFilePath, returnsContent, 'utf-8');
42+
43+
console.log(`[extract-returns] Created ${path.relative(process.cwd(), newFilePath)}`);
44+
return true;
45+
}
46+
47+
/**
48+
* Replaces generic type names in the parameters table with expanded types.
49+
* @param {string} content
50+
* @returns {string}
51+
*/
52+
function replaceGenericTypesInParamsTable(content) {
53+
// Replace Fetcher in the parameters table
54+
content = content.replace(
55+
/(\|\s*`fetcher`\s*\|\s*)`Fetcher`(\s*\|)/g,
56+
'$1`Fetcher extends (...args: any[]) => Promise<any>`$2',
57+
);
58+
return content;
59+
}
60+
61+
/**
62+
* Extracts the "## Parameters" section from a markdown file and writes it to a separate file.
63+
* @param {string} filePath - The path to the markdown file
64+
* @returns {boolean} True if a file was created
65+
*/
66+
function extractParametersSection(filePath) {
67+
const content = fs.readFileSync(filePath, 'utf-8');
68+
const fileName = path.basename(filePath, '.mdx');
69+
const dirName = path.dirname(filePath);
70+
71+
// Always use -params suffix
72+
const suffix = '-params';
73+
const targetFileName = `${fileName}${suffix}.mdx`;
74+
const propsFileName = `${fileName}-props.mdx`;
75+
76+
// Delete any existing -props file (TypeDoc-generated)
77+
const propsFilePath = path.join(dirName, propsFileName);
78+
if (fs.existsSync(propsFilePath)) {
79+
fs.unlinkSync(propsFilePath);
80+
console.log(`[extract-returns] Deleted ${path.relative(process.cwd(), propsFilePath)}`);
81+
}
82+
83+
// Find the "## Parameters" section
84+
const paramsStart = content.indexOf('## Parameters');
85+
86+
if (paramsStart === -1) {
87+
return false; // No Parameters section found
88+
}
89+
90+
// Find the next heading after "## Parameters" (or end of file)
91+
const afterParams = content.slice(paramsStart + 13); // Skip past "## Parameters"
92+
const nextHeadingMatch = afterParams.match(/\n## /);
93+
const paramsEnd =
94+
nextHeadingMatch && typeof nextHeadingMatch.index === 'number'
95+
? paramsStart + 13 + nextHeadingMatch.index
96+
: content.length;
97+
98+
// Extract the Parameters section and trim trailing whitespace
99+
const paramsContent = content.slice(paramsStart, paramsEnd).trimEnd();
100+
const processedParams = replaceGenericTypesInParamsTable(paramsContent);
101+
102+
// Write to new file
103+
const newFilePath = path.join(dirName, targetFileName);
104+
fs.writeFileSync(newFilePath, processedParams, 'utf-8');
105+
106+
console.log(`[extract-returns] Created ${path.relative(process.cwd(), newFilePath)}`);
107+
return true;
108+
}
109+
110+
/**
111+
* Recursively reads all .mdx files in a directory, excluding generated files
112+
* @param {string} dir - The directory to read
113+
* @returns {string[]} Array of file paths
114+
*/
115+
function getAllMdxFiles(dir) {
116+
/** @type {string[]} */
117+
const files = [];
118+
119+
if (!fs.existsSync(dir)) {
120+
return files;
121+
}
122+
123+
const entries = fs.readdirSync(dir, { withFileTypes: true });
124+
125+
for (const entry of entries) {
126+
const fullPath = path.join(dir, entry.name);
127+
128+
if (entry.isDirectory()) {
129+
files.push(...getAllMdxFiles(fullPath));
130+
} else if (entry.isFile() && entry.name.endsWith('.mdx')) {
131+
// Exclude generated files
132+
const isGenerated =
133+
entry.name.endsWith('-return.mdx') || entry.name.endsWith('-params.mdx') || entry.name.endsWith('-props.mdx');
134+
if (!isGenerated) {
135+
files.push(fullPath);
136+
}
137+
}
138+
}
139+
140+
return files;
141+
}
142+
143+
/**
144+
* Main function to process all clerk-react files
145+
*/
146+
function main() {
147+
const packages = ['clerk-react'];
148+
const dirs = packages.map(folder => path.join(__dirname, 'temp-docs', folder));
149+
150+
for (const dir of dirs) {
151+
if (!fs.existsSync(dir)) {
152+
console.log(`[extract-returns] ${dir} directory not found, skipping extraction`);
153+
continue;
154+
}
155+
156+
const mdxFiles = getAllMdxFiles(dir);
157+
console.log(`[extract-returns] Processing ${mdxFiles.length} files in ${dir}/`);
158+
159+
let returnsCount = 0;
160+
let paramsCount = 0;
161+
162+
for (const filePath of mdxFiles) {
163+
// Extract Returns sections
164+
if (extractReturnsSection(filePath)) {
165+
returnsCount++;
166+
}
167+
168+
// Extract Parameters sections
169+
if (extractParametersSection(filePath)) {
170+
paramsCount++;
171+
}
172+
}
173+
174+
console.log(`[extract-returns] Extracted ${returnsCount} Returns sections`);
175+
console.log(`[extract-returns] Extracted ${paramsCount} Parameters sections`);
176+
}
177+
}
178+
179+
main();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"test:typedoc": "pnpm typedoc:generate && cd ./.typedoc && vitest run",
5757
"turbo:clean": "turbo daemon clean",
5858
"typedoc:generate": "pnpm build:declarations && pnpm typedoc:generate:skip-build",
59-
"typedoc:generate:skip-build": "typedoc --tsconfig tsconfig.typedoc.json && rm -rf .typedoc/docs && mv .typedoc/temp-docs .typedoc/docs",
59+
"typedoc:generate:skip-build": "typedoc --tsconfig tsconfig.typedoc.json && node .typedoc/extract-returns-and-params.mjs && rimraf .typedoc/docs && cpy '.typedoc/temp-docs/**' '.typedoc/docs' && rimraf .typedoc/temp-docs",
6060
"version-packages": "changeset version && pnpm install --lockfile-only --engine-strict=false",
6161
"version-packages:canary": "./scripts/canary.mjs",
6262
"version-packages:snapshot": "./scripts/snapshot.mjs",

packages/shared/src/errors/clerkApiResponseError.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ interface ClerkAPIResponseOptions extends Omit<ClerkErrorParams, 'message' | 'co
1111
retryAfter?: number;
1212
}
1313

14+
/**
15+
* Class representing a Clerk API Response Error.
16+
*/
1417
export class ClerkAPIResponseError extends ClerkError implements ClerkAPIResponseErrorInterface {
1518
static kind = 'ClerkAPIResponseError';
1619
status: number;

packages/shared/src/react/commerce.tsx

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,27 @@ type internalStripeAppearance = {
156156
spacingUnit: string;
157157
};
158158

159-
type PaymentElementProviderProps = {
159+
/**
160+
* @interface
161+
*/
162+
export type PaymentElementProviderProps = {
163+
/**
164+
* An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session.
165+
*/
160166
checkout?: BillingCheckoutResource | ReturnType<typeof useCheckout>['checkout'];
167+
/**
168+
* 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.
169+
*/
161170
stripeAppearance?: internalStripeAppearance;
162171
/**
163-
* Default to `user` if not provided.
172+
* Specifies whether to fetch for the current user or organization.
164173
*
165174
* @default 'user'
166175
*/
167176
for?: ForPayerType;
177+
/**
178+
* An optional description to display to the user within the payment element UI.
179+
*/
168180
paymentDescription?: string;
169181
};
170182

@@ -248,7 +260,17 @@ const PaymentElementInternalRoot = (props: PropsWithChildren) => {
248260
return <DummyStripeUtils>{props.children}</DummyStripeUtils>;
249261
};
250262

251-
const PaymentElement = ({ fallback }: { fallback?: ReactNode }) => {
263+
/**
264+
* @interface
265+
*/
266+
export type PaymentElementProps = {
267+
/**
268+
* Optional fallback content, such as a loading skeleton, to display while the payment form is being initialized.
269+
*/
270+
fallback?: ReactNode;
271+
};
272+
273+
const PaymentElement = ({ fallback }: PaymentElementProps) => {
252274
const {
253275
setIsPaymentElementReady,
254276
paymentMethodOrder,
@@ -315,7 +337,13 @@ const throwLibsMissingError = () => {
315337
);
316338
};
317339

318-
type UsePaymentElementReturn = {
340+
/**
341+
* @interface
342+
*/
343+
export type UsePaymentElementReturn = {
344+
/**
345+
* A function that submits the payment form data to the payment provider. It returns a promise that resolves with either a `data` object containing a payment token on success, or an `error` object on failure.
346+
*/
319347
submit: () => Promise<
320348
| {
321349
data: { gateway: 'stripe'; paymentToken: string };
@@ -326,13 +354,25 @@ type UsePaymentElementReturn = {
326354
error: PaymentElementError;
327355
}
328356
>;
357+
/**
358+
* A function that resets the payment form to its initial, empty state.
359+
*/
329360
reset: () => Promise<void>;
361+
/**
362+
* 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.
363+
*/
330364
isFormReady: boolean;
331365
} & (
332366
| {
367+
/**
368+
* An object containing information about the initialized payment provider. It is `undefined` until `isProviderReady` is `true`.
369+
*/
333370
provider: {
334371
name: 'stripe';
335372
};
373+
/**
374+
* A boolean that indicates if the underlying payment provider (e.g. Stripe) has been fully initialized.
375+
*/
336376
isProviderReady: true;
337377
}
338378
| {

packages/shared/src/react/contexts.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,23 @@ const [SessionContext, useSessionContext] = createContextAndHook<SignedInSession
2525

2626
const OptionsContext = React.createContext<ClerkOptions>({});
2727

28-
type UseCheckoutOptions = {
28+
/**
29+
* @interface
30+
*/
31+
export type UseCheckoutOptions = {
32+
/**
33+
* Specifies if the checkout is for an organization.
34+
*
35+
* @default 'user'
36+
*/
2937
for?: ForPayerType;
38+
/**
39+
* The billing period for the plan.
40+
*/
3041
planPeriod: BillingSubscriptionPlanPeriod;
42+
/**
43+
* The ID of the subscription plan to check out (e.g. `cplan_xxx`).
44+
*/
3145
planId: string;
3246
};
3347

0 commit comments

Comments
 (0)