Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions .github/workflows/docs-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Generate API Documentation

on:
# Manual trigger for testing
workflow_dispatch:
inputs:
target_branch:
description: "Branch to generate docs from (defaults to main)"
required: false
type: string
default: "main"

# Trigger on push to main for testing
push:
branches:
- 'main'

# Automatically trigger after successful npm publish
workflow_run:
workflows: ["Publish to Public NPM"]
types: [completed]
branches: [main]

permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
generate-docs:
name: Generate API Docs
runs-on: ubuntu-latest
# Only run if manually triggered, push event, OR if publish workflow succeeded
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.workflow_run.conclusion == 'success' }}

steps:
- name: Determine target branch
id: branch
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
BRANCH="${{ inputs.target_branch }}"
elif [ "${{ github.event_name }}" == "push" ]; then
BRANCH="${{ github.ref_name }}"
else
BRANCH="main"
fi
echo "branch=${BRANCH:-main}" >> $GITHUB_OUTPUT
echo "Using branch: ${BRANCH:-main}"

- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
ref: ${{ steps.branch.outputs.branch }}
fetch-depth: 0

- name: Setup pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
with:
version: 10.6.5

- name: Setup Node.js
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "22"
cache: "pnpm"

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build packages
run: pnpm run build

- name: Generate API documentation
run: pnpm docs:api

- name: Setup GitHub Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: docs-api

- name: Generate Summary
run: |
echo "## 📚 API Documentation Generated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ steps.branch.outputs.branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Trigger:** \`${{ github.event_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Generated Files" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
find docs-api -type f | head -30 >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📦 Artifact uploaded, proceeding to deploy..." >> $GITHUB_STEP_SUMMARY

deploy-docs:
name: Deploy to GitHub Pages
needs: generate-docs
runs-on: ubuntu-latest

permissions:
pages: write
id-token: write

environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4

- name: Generate Deployment Summary
run: |
echo "## 🚀 API Documentation Deployed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**URL:** ${{ steps.deployment.outputs.page_url }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The API documentation is now live at:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🔗 **https://auth0.github.io/auth0-ui-components/**" >> $GITHUB_STEP_SUMMARY

3 changes: 3 additions & 0 deletions .github/workflows/preview-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ jobs:
- name: Build all packages
run: pnpm build

- name: Generate API documentation
run: pnpm docs:api

- name: Install Vercel CLI
run: npm install --global vercel@latest

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ coverage/
.cache/
.turbo
.vercel

# Generated API documentation
docs-api/
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ For detailed information on how to use these components and get started with Aut
- **[Auth0 Quickstarts](https://auth0.com/docs/quickstarts)**: Official guides for creating and configuring your application on the Auth0 platform.
- **[Auth0 APIs](https://auth0.com/docs/api)**: Comprehensive documentation for Auth0's APIs.
- **[Component Documentation](https://auth0-ui-components.vercel.app/)**: Live Storybook showcasing all available components, their props, and usage examples.
- **[Examples Folder](./examples/)**: Practical, hands-on sample applications demonstrating how to integrate and use these components in a real project.
- **[Examples Folder](https://github.com/auth0/auth0-ui-components/tree/main/examples)**: Practical, hands-on sample applications demonstrating how to integrate and use these components in a real project.
- **[Component Reference](#-component-reference)**: Explore public components available in @auth0/universal-components-react.

## 📦 Packages Overview
## Packages Overview

This project uses a **monorepo architecture** designed for multi-framework support. It is organized into two main types of packages:

Expand Down Expand Up @@ -135,6 +136,17 @@ pnpm run dev

_Note: The port may differ if other applications are running._

## 📚 Component Reference

Explore public components available in @auth0/universal-components-react.

- [UserMfaManagement](https://auth0.github.io/auth0-ui-components/variables/react_src.UserMFAMgmt.html)
- [DomainTable](https://auth0.github.io/auth0-ui-components/variables/react_src.DomainTable.html)
- [SsoProviderCreate](https://auth0.github.io/auth0-ui-components/variables/react_src.SsoProviderCreate.html)
- [SsoProviderEdit](https://auth0.github.io/auth0-ui-components/variables/react_src.SsoProviderEdit.html)
- [SsoProviderTable](https://auth0.github.io/auth0-ui-components/variables/react_src.SsoProviderTable.html)
- [OrganizationDetailsEdit](https://auth0.github.io/auth0-ui-components/variables/react_src.OrganizationDetailsEdit.html)

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a pull request or open an issue for any bugs, feature requests, or improvements.
Expand Down
63 changes: 63 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import tsParser from '@typescript-eslint/parser';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import importPlugin from 'eslint-plugin-import';
import jsdocPlugin from 'eslint-plugin-jsdoc';
import globals from 'globals';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
Expand All @@ -24,6 +25,9 @@ export default [
'**/.turbo/**',
'**/.next/**',
'**/*.d.ts',
'**/docs-api/**',
'**/examples/**',
'**/docs-site/**',
],
},

Expand Down Expand Up @@ -53,6 +57,7 @@ export default [
'react': reactPlugin,
'react-hooks': reactHooksPlugin,
'import': importPlugin,
'jsdoc': jsdocPlugin,
},
rules: {
// Disable base rules that TypeScript handles
Expand Down Expand Up @@ -99,11 +104,69 @@ export default [
'import/namespace': 'off',
'import/default': 'off',
'import/no-named-as-default-member': 'off',

// JSDoc validation (STRICT MODE) - ensures docs stay in sync with code
// CRITICAL: These rules ensure that if a function signature changes, the JSDoc must also change

// ERROR level - these are the core validation rules that catch doc/code mismatches
'jsdoc/check-param-names': ['error', {
checkDestructured: true, // Require @param for each destructured property
}],
'jsdoc/check-tag-names': ['error', {
definedTags: ['packageDocumentation', 'defaultValue', 'internal', 'see', 'category']
}],
'jsdoc/valid-types': 'error',

// WARN level - these encourage complete documentation but don't block builds
// These can be upgraded to 'error' incrementally as documentation is added
'jsdoc/require-param': ['warn', {
checkDestructured: true,
checkDestructuredRoots: true,
}],
'jsdoc/require-param-description': 'warn',
'jsdoc/require-returns': ['warn', {
checkGetters: false,
}],
'jsdoc/require-returns-description': 'warn',
'jsdoc/require-jsdoc': ['warn', {
require: {
FunctionDeclaration: true,
MethodDefinition: false,
ClassDeclaration: true,
ArrowFunctionExpression: false,
FunctionExpression: false,
},
publicOnly: false, // Require docs for all functions, not just exported ones
}],
},
settings: {
react: {
version: 'detect',
},
jsdoc: {
mode: 'typescript',
},
},
},

// Relaxed JSDoc rules for test, mock, asset, and UI atom component files
{
files: [
'**/__mocks__/**',
'**/__tests__/**',
'**/*.test.{ts,tsx}',
'**/*.spec.{ts,tsx}',
'**/assets/**',
'**/internals/**',
'**/components/ui/**', // shadcn/atom components - thin wrappers, not public API
],
rules: {
'jsdoc/require-param': 'off',
'jsdoc/check-param-names': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-param-description': 'off',
'jsdoc/require-returns-description': 'off',
},
},

Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"build:docs": "turbo run build --filter=auth0-ui-components-docs",
"build:shadcn": "cd packages/react && pnpm registry:build && cp -r public/r ../../docs-site/public/",
"dev:docs": "turbo run dev --filter=auth0-ui-components-docs",
"docs:api": "typedoc",
"test": "turbo run test:coverage",
"test:core": "turbo run test:coverage --filter=./packages/core",
"test:react": "turbo run test:coverage --filter=./packages/react",
Expand Down Expand Up @@ -59,6 +60,7 @@
"@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.39.1",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsdoc": "^62.3.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"globals": "^16.5.0",
Expand All @@ -68,6 +70,8 @@
"prettier": "^3.6.2",
"tsup": "^8.5.1",
"turbo": "^2.6.1",
"typedoc": "^0.28.16",
"typedoc-plugin-markdown": "^4.9.0",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
}
Expand Down
23 changes: 19 additions & 4 deletions packages/core/src/api/api-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export function isApiError(error: unknown): error is ApiError {
}

/**
* Type guard to check if an error has a structured API error body
* Type guard to check if an error has a structured API error body.
*
* @param error - The unknown value to test
* @returns `true` if the error has a body property with optional detail, title, status, or type fields
*/
export function hasApiErrorBody(
error: unknown,
Expand All @@ -39,9 +42,9 @@ export function hasApiErrorBody(
* function to map API error codes to user-friendly messages.
*
* @param error - The unknown error object or value to normalize.
* @param options - Optional settings including:
* - resolver: A function that maps error codes to user-friendly messages.
* - fallbackMessage: A default message used when the error cannot be mapped.
* @param options - Optional settings for error normalization.
* @param options.resolver - A function that maps error codes to user-friendly messages.
* @param options.fallbackMessage - A default message used when the error cannot be mapped.
* @returns A standard Error object with an appropriate message.
*/
export function normalizeError(
Expand All @@ -66,6 +69,18 @@ export function normalizeError(
return new Error(options?.fallbackMessage ?? 'An unknown error occurred');
}

/**
* Extracts the HTTP status code from an unknown error object.
*
* This function checks multiple common locations where status codes may be stored:
* - `error.status`
* - `error.statusCode`
* - `error.response.status`
* - `error.body.status`
*
* @param error - The unknown error to extract the status code from
* @returns The HTTP status code if found, otherwise `undefined`
*/
export function getStatusCode(error: unknown): number | undefined {
return typeof error === 'object' && error !== null
? [
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/auth/token-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ const TokenUtils = {
* Validates the parameters required for a token request.
*
* @param auth - The authentication details containing domain configuration
* @param scope - The OAuth scope being requested
* @throws {Error} When domain is not configured or scope is missing
* @throws {Error} When domain is not configured
*/
validateTokenRequest(auth: AuthDetails): void {
if (!auth.domain) {
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/theme/theme-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ export const getCoreStyles = (
/**
* Returns component styles supporting both flat and nested variable formats.
*
* @param styling - Object containing either direct styling variables or nested under 'variables'
* @param isDarkMode - Boolean indicating if dark mode is active
* @returns Merged styles with variables and classNames
* @param styling - Object containing styling configuration.
* @param styling.variables - Optional styling variables for common, light, and dark themes.
* @param styling.classes - Optional custom CSS class mappings.
* @param isDarkMode - Boolean indicating if dark mode is active.
* @returns Merged styles with variables and classNames.
*/
export const getComponentStyles = (
styling: { variables?: StylingVariables; classes?: Record<string, string | undefined> } = {},
Expand Down
Loading
Loading