diff --git a/.gitignore b/.gitignore index 496ee2c..c79885f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,12 @@ -.DS_Store \ No newline at end of file +.DS_Store + +# Translation pipeline +.translation-cache.json +.env + +# TypeScript +dist/ +*.tsbuildinfo + +# Node.js +node_modules \ No newline at end of file diff --git a/TRANSLATION.md b/TRANSLATION.md new file mode 100644 index 0000000..57a2ded --- /dev/null +++ b/TRANSLATION.md @@ -0,0 +1,176 @@ +# Multi-Language Translation Pipeline + +This document explains how to use the automated translation pipeline for Dodo Payments documentation. + +## Quick Start + +1. **Install dependencies:** + ```bash + npm install + ``` + +2. **Set up your OpenAI API key:** + ```bash + cp .env.example .env + # Edit .env and add: OPENAI_API_KEY=your_key_here + ``` + +3. **Run translation:** + ```bash + npm run translate + ``` + +4. **Update navigation:** + ```bash + npm run update-nav + ``` + +## Supported Languages + +- 🇬🇧 English (en) - Source language +- 🇨🇳 Chinese Simplified (zh) +- 🇫🇷 French (fr) +- 🇩🇪 German (de) +- 🇮🇩 Indonesian (id) +- 🇯🇵 Japanese (ja) +- 🇰🇷 Korean (ko) +- 🇧🇷 Portuguese Brazil (pt-BR) +- 🇪🇸 Spanish (es) + +## How It Works + +### 1. File Discovery +The pipeline scans all `.mdx` files in your repository (excluding language directories and build files). + +### 2. Content Parsing +Each MDX file is parsed to extract: +- **Frontmatter** (title, description, etc.) - Translated +- **Body text** - Translated +- **Code blocks** (```language) - Preserved as-is +- **Inline code** (`code`) - Preserved as-is +- **Mintlify components** - Text content translated, structure preserved +- **Links and images** - URLs preserved, alt text translated + +### 3. Translation +Uses OpenAI GPT-4o with specialized prompts that: +- Preserve technical terms (Dodo Payments, API, SDK, etc.) +- Maintain code syntax +- Keep URLs and file paths unchanged +- Translate user-facing content appropriately + +### 4. File Generation +Creates translated files in language-specific directories: +``` +docs/ +├── introduction.mdx # English (source) +├── es/ +│ └── introduction.mdx # Spanish +├── fr/ +│ └── introduction.mdx # French +└── ... +``` + +### 5. Navigation Update +Updates `docs.json` to use Mintlify's multi-language navigation structure. + +## Commands + +### Translate (Incremental) +Only translates files that are new or have been modified: +```bash +npm run translate +``` + +### Translate (Full) +Re-translates all files regardless of cache: +```bash +npm run translate:full +``` + +### Translate Specific Language +```bash +npm run translate:lang -- --lang=es +``` + +### Update Navigation +After translation, update the navigation structure: +```bash +npm run update-nav +``` + +## Translation Cache + +The pipeline maintains `.translation-cache.json` to track: +- Which files have been translated +- When source files were last modified +- File hashes for change detection + +To clear the cache: +```bash +rm .translation-cache.json +``` + +## Cost Estimation + +- **Model**: GPT-4o +- **Average cost per page**: ~$0.01-0.03 per language +- **Total pages**: ~200+ MDX files +- **Estimated cost for full translation**: ~$15-50 (one-time) + +Subsequent runs (incremental) will only translate changed files, significantly reducing costs. + +## Troubleshooting + +### API Rate Limits +If you hit rate limits, wait a few minutes and re-run. The cache prevents re-translating completed files. + +### Translation Quality Issues +- Technical terms should be preserved automatically +- Review translated files and manually adjust if needed +- Source English files remain unchanged + +### Missing Translations +If a file wasn't translated: +1. Check the error messages in the console +2. Delete the cache entry for that file +3. Re-run the translation + +## Workflow + +### Initial Setup +1. Run `npm run translate` to translate all files +2. Run `npm run update-nav` to update navigation +3. Review translated files +4. Commit changes + +### Ongoing Updates +1. Edit English source files +2. Run `npm run translate` (only changed files will be translated) +3. Review changes +4. Commit + +## Notes + +- English files stay in the root directory +- Translated files are in language subdirectories +- Mintlify automatically handles language switching +- Code examples are preserved in all languages +- Technical terms and brand names are preserved + +## File Structure + +``` +dodo-docs/ +├── scripts/ +│ ├── translate.js # Main translation script +│ ├── update-navigation.js # Navigation updater +│ └── utils/ +│ ├── mdx-parser.js # MDX content parser +│ ├── translator.js # OpenAI translation service +│ └── cache.js # Translation cache manager +├── .translation-cache.json # Translation cache (gitignored) +├── .env # API keys (gitignored) +├── package.json +└── docs.json # Updated with multi-language nav +``` + diff --git a/docs.json b/docs.json index da2c1e9..f948e10 100644 --- a/docs.json +++ b/docs.json @@ -9,640 +9,891 @@ }, "favicon": "/favicon.svg", "navigation": { - "tabs": [ + "languages": [ { - "tab": "Documentation", - "icon": "book", - "groups": [ + "language": "en", + "tabs": [ { - "group": "Getting Started", - "pages": [ - "introduction", - "migrate-to-dodo" + "tab": "Documentation", + "icon": "book", + "groups": [ + { + "group": "Getting Started", + "pages": [ + "introduction", + "migrate-to-dodo" + ] + }, + { + "group": "Features", + "pages": [ + "features/products", + "features/one-time-payment-products", + { + "group": "Subscriptions", + "icon": "infinity", + "pages": [ + "features/subscription", + "features/addons", + "developer-resources/ondemand-subscriptions" + ] + }, + { + "group": "Usage Based Billing", + "icon": "arrow-trend-up", + "tag": "NEW", + "pages": [ + "features/usage-based-billing/introduction", + "features/usage-based-billing/meters", + "features/usage-based-billing/event-ingestion", + "features/customer-credit", + { + "group": "Ingestion Blueprints", + "icon": "copy", + "pages": [ + "features/usage-based-billing/ingestion-blueprints", + "developer-resources/ingestion-blueprints/llm", + "developer-resources/ingestion-blueprints/api-gateway", + "developer-resources/ingestion-blueprints/object-storage", + "developer-resources/ingestion-blueprints/stream", + "developer-resources/ingestion-blueprints/time-range" + ] + } + ] + }, + { + "group": "Customers", + "icon": "user-group", + "pages": [ + "features/customers", + "features/customer-portal", + "features/customer-wallet" + ] + }, + "features/discount-codes", + { + "group": "Transactions", + "icon": "credit-card", + "pages": [ + "features/transactions/payments", + "features/transactions/refunds", + "features/transactions/disputes" + ] + }, + { + "group": "Entitlements", + "icon": "gift", + "pages": [ + "features/license-keys", + "features/digital-product-delivery" + ] + }, + { + "group": "Payouts and Balances", + "icon": "wallet", + "pages": [ + "features/payouts/payout-structure", + "features/account-summary-payout-wallet" + ] + }, + { + "group": "Account Management", + "icon": "user", + "pages": [ + "features/multi-brands", + "features/invoice-generation", + "features/team", + "miscellaneous/accounts" + ] + }, + { + "group": "Pricing", + "icon": "dollar-sign", + "pages": [ + "features/tax-inclusive-pricing", + "features/pay-what-you-want", + "features/b2b-payments", + "features/purchasing-power-parity" + ] + }, + "features/payment-methods", + "features/adaptive-currency", + "features/analytics-and-reporting", + "features/storefront", + "features/affiliates", + "features/appstore-digital-goods" + ] + }, + { + "group": "Integrate", + "pages": [ + { + "group": "SDKs", + "icon": "box-open", + "pages": [ + "developer-resources/dodo-payments-sdks", + "developer-resources/sdks/typescript", + "developer-resources/sdks/python", + "developer-resources/sdks/go", + "developer-resources/sdks/ruby", + "developer-resources/sdks/java", + "developer-resources/sdks/kotlin", + "developer-resources/sdks/cli", + "developer-resources/sdks/php", + "developer-resources/sdks/csharp", + "developer-resources/react-native-integration" + ] + }, + { + "group": "Framework Adaptors", + "icon": "frame", + "pages": [ + "developer-resources/nextjs-adaptor", + "developer-resources/nuxt-adaptor", + "developer-resources/better-auth-adaptor", + "developer-resources/express-adaptor", + "developer-resources/astro-adaptor", + "developer-resources/sveltekit-adaptor", + "developer-resources/hono-adaptor", + "developer-resources/remix-adaptor", + "developer-resources/tanstack-adaptor", + "developer-resources/fastify-adaptor", + "developer-resources/convex-component" + ] + }, + { + "group": "Webhooks", + "icon": "webhook", + "pages": [ + "developer-resources/webhooks", + "developer-resources/webhooks/intents/webhook-events-guide", + { + "group": "Webhook Payloads", + "icon": "code", + "pages": [ + "developer-resources/webhooks/intents/payment", + "developer-resources/webhooks/intents/subscription", + "developer-resources/webhooks/intents/refund", + "developer-resources/webhooks/intents/dispute", + "developer-resources/webhooks/intents/license-key" + ] + }, + { + "group": "Deploy to Cloud", + "icon": "rocket", + "pages": [ + "developer-resources/webhooks/examples/vercel-example", + "developer-resources/webhooks/examples/cloudflare-example", + "developer-resources/webhooks/examples/supabase-example", + "developer-resources/webhooks/examples/netlify-example" + ] + } + ] + }, + { + "group": "Testing & Demo Tools", + "icon": "flask", + "pages": [ + "miscellaneous/test-mode-vs-live-mode", + "miscellaneous/testing-process", + "features/atlas-demo-website" + ] + }, + { + "group": "Boilerplates", + "icon": "box-open", + "pages": [ + "developer-resources/expo-boilerplate", + "developer-resources/supabase-boilerplate", + "integrations/figma-plugin", + "developer-resources/nextjs-boilerplate", + "developer-resources/astro-boilerplate" + ] + }, + "developer-resources/billingsdk", + "developer-resources/mcp-server" + ] + }, + { + "group": "Merchant of Record", + "pages": [ + "miscellaneous/verification-process", + "miscellaneous/list-of-countries-we-accept-payments-from", + "miscellaneous/merchant-acceptance", + "miscellaneous/review-monitoring-policy", + "features/mor-vs-pg", + "features/bypassing-app-store-fees" + ] + }, + { + "group": "Miscellaneous", + "pages": [ + { + "group": "Support Channels", + "icon": "headset", + "pages": [ + "miscellaneous/help-support", + "features/feature-request" + ] + }, + { + "group": "GTM Tools", + "icon": "chart-line", + "pages": [ + "miscellaneous/gtm-tools/saas-pricing-calculator", + "miscellaneous/gtm-tools/saas-revenue-and-profit-growth", + "miscellaneous/gtm-tools/saas-kpi-measurement", + "miscellaneous/gtm-tools/freemium-model", + "miscellaneous/gtm-tools/feature-prioritization-tool" + ] + }, + "features/mobile-app", + "miscellaneous/faq", + "miscellaneous/security-policy" + ] + } ] }, { - "group": "Features", - "pages": [ - "features/products", - "features/one-time-payment-products", + "tab": "Guides", + "icon": "compass", + "groups": [ { - "group": "Subscriptions", - "icon": "infinity", + "group": "Integration Guides", + "pages": [ + "developer-resources/integration-guide", + "developer-resources/subscription-integration-guide", + "developer-resources/usage-based-billing-guide", + "developer-resources/checkout-session", + "developer-resources/subscription-upgrade-downgrade", + "developer-resources/overlay-checkout", + "developer-resources/mobile-integration" + ] + }, + { + "group": "Cookbooks", + "tag": "New", + "pages": [ + "developer-resources/usage-based-billing-build-ai-image-generator", + "developer-resources/seat-based-pricing", + "developer-resources/build-an-ai-chat-app-with-usage-based-billing" + ] + } + ] + }, + { + "tab": "API Reference", + "icon": "rectangle-code", + "groups": [ + { + "group": "API Reference", "pages": [ - "features/subscription", - "features/addons", - "developer-resources/ondemand-subscriptions" + "api-reference/introduction", + "api-reference/error-codes", + "api-reference/transaction-failures", + "api-reference/metadata" ] }, { - "group": "Usage Based Billing", - "icon": "arrow-trend-up", + "group": "Checkout Sessions", "tag": "NEW", "pages": [ - "features/usage-based-billing/introduction", - "features/usage-based-billing/meters", - "features/usage-based-billing/event-ingestion", - "features/customer-credit", - { - "group": "Ingestion Blueprints", - "icon": "copy", - "pages": [ - "features/usage-based-billing/ingestion-blueprints", - "developer-resources/ingestion-blueprints/llm", - "developer-resources/ingestion-blueprints/api-gateway", - "developer-resources/ingestion-blueprints/object-storage", - "developer-resources/ingestion-blueprints/stream", - "developer-resources/ingestion-blueprints/time-range" - ] - } + "api-reference/checkout-sessions/create", + "api-reference/checkout-sessions/get-checkouts" + ] + }, + { + "group": "Payments", + "pages": [ + "api-reference/payments/get-payments", + "api-reference/payments/get-payments-1", + "api-reference/payments/get-invoice", + "api-reference/payments/retrieve-line-items", + "api-reference/payments/post-payments" + ] + }, + { + "group": "Subscriptions", + "pages": [ + "api-reference/subscriptions/get-subscriptions-1", + "api-reference/subscriptions/get-subscriptions", + "api-reference/subscriptions/change-plan", + "api-reference/subscriptions/patch-subscriptions", + "api-reference/subscriptions/create-charge", + "api-reference/subscriptions/get-usage-history", + "api-reference/subscriptions/update-payment-method", + "api-reference/subscriptions/post-subscriptions" + ] + }, + { + "group": "Discounts", + "pages": [ + "api-reference/discounts/list-discounts", + "api-reference/discounts/create-discount", + "api-reference/discounts/validate-discount", + "api-reference/discounts/update-discount", + "api-reference/discounts/delete-discount" + ] + }, + { + "group": "Licenses", + "pages": [ + "api-reference/licenses/activate-license", + "api-reference/licenses/deactivate-license", + "api-reference/licenses/validate-license", + "api-reference/licenses/list-license-keys", + "api-reference/licenses/get-license-key", + "api-reference/licenses/update-license-key", + "api-reference/licenses/get-license-key-instances", + "api-reference/licenses/get-license-key-instance", + "api-reference/licenses/update-license-key-instance" ] }, { "group": "Customers", - "icon": "user-group", "pages": [ - "features/customers", - "features/customer-portal", - "features/customer-wallet" + "api-reference/customers/create-customer", + "api-reference/customers/get-customers", + "api-reference/customers/get-customers-1", + "api-reference/customers/patch-customer", + "api-reference/customers/create-customer-portal-session", + "api-reference/customers/get-customer-payment-methods" ] }, - "features/discount-codes", { - "group": "Transactions", - "icon": "credit-card", + "group": "Customer Wallets", + "tag": "NEW", "pages": [ - "features/transactions/payments", - "features/transactions/refunds", - "features/transactions/disputes" + "api-reference/customers/get-customer-wallets", + "api-reference/customers/get-customer-wallets-ledger-entries", + "api-reference/customers/post-customer-wallets-ledger-entries" ] }, { - "group": "Entitlements", - "icon": "gift", + "group": "Products", "pages": [ - "features/license-keys", - "features/digital-product-delivery" + "api-reference/products/get-products", + "api-reference/products/post-products", + "api-reference/products/get-products-1", + "api-reference/products/patch-products", + "api-reference/products/put-products-images", + "api-reference/products/archive-product", + "api-reference/products/unarchive-product", + "api-reference/products/update-files" ] }, { - "group": "Payouts and Balances", - "icon": "wallet", + "group": "Addons", "pages": [ - "features/payouts/payout-structure", - "features/account-summary-payout-wallet" + "api-reference/addons/create-addon", + "api-reference/addons/list-addons", + "api-reference/addons/get-addon", + "api-reference/addons/update-addon", + "api-reference/addons/update-addon-images" ] }, { - "group": "Account Management", - "icon": "user", + "group": "Meters", "pages": [ - "features/multi-brands", - "features/invoice-generation", - "features/team", - "miscellaneous/accounts" + "api-reference/meters/create-meter", + "api-reference/meters/get-meters", + "api-reference/meters/retrieve-meter", + "api-reference/meters/archive-meter", + "api-reference/meters/unarchive-meter" ] }, { - "group": "Pricing", - "icon": "dollar-sign", + "group": "Usage Events", "pages": [ - "features/tax-inclusive-pricing", - "features/pay-what-you-want", - "features/b2b-payments", - "features/purchasing-power-parity" + "api-reference/usage-events/ingest-events", + "api-reference/usage-events/get-event", + "api-reference/usage-events/list-events" ] }, - "features/payment-methods", - "features/adaptive-currency", - "features/analytics-and-reporting", - "features/storefront", - "features/affiliates", - "features/appstore-digital-goods" - ] - }, - { - "group": "Integrate", - "pages": [ { - "group": "SDKs", - "icon": "box-open", + "group": "Refunds", "pages": [ - "developer-resources/dodo-payments-sdks", - "developer-resources/sdks/typescript", - "developer-resources/sdks/python", - "developer-resources/sdks/go", - "developer-resources/sdks/ruby", - "developer-resources/sdks/java", - "developer-resources/sdks/kotlin", - "developer-resources/sdks/cli", - "developer-resources/sdks/php", - "developer-resources/sdks/csharp", - "developer-resources/react-native-integration" + "api-reference/refunds/get-refunds", + "api-reference/refunds/post-refunds", + "api-reference/refunds/get-refunds-1", + "api-reference/refunds/get-refund-receipt" ] }, { - "group": "Framework Adaptors", - "icon": "frame", + "group": "Disputes", "pages": [ - "developer-resources/nextjs-adaptor", - "developer-resources/nuxt-adaptor", - "developer-resources/better-auth-adaptor", - "developer-resources/express-adaptor", - "developer-resources/astro-adaptor", - "developer-resources/sveltekit-adaptor", - "developer-resources/hono-adaptor", - "developer-resources/remix-adaptor", - "developer-resources/tanstack-adaptor", - "developer-resources/fastify-adaptor", - "developer-resources/convex-component" + "api-reference/disputes/get-disputes", + "api-reference/disputes/get-disputes-1" ] }, { - "group": "Webhooks", - "icon": "webhook", + "group": "Payouts", "pages": [ - "developer-resources/webhooks", - "developer-resources/webhooks/intents/webhook-events-guide", - { - "group": "Webhook Payloads", - "icon": "code", - "pages": [ - "developer-resources/webhooks/intents/payment", - "developer-resources/webhooks/intents/subscription", - "developer-resources/webhooks/intents/refund", - "developer-resources/webhooks/intents/dispute", - "developer-resources/webhooks/intents/license-key" - ] - }, - { - "group": "Deploy to Cloud", - "icon": "rocket", - "pages": [ - "developer-resources/webhooks/examples/vercel-example", - "developer-resources/webhooks/examples/cloudflare-example", - "developer-resources/webhooks/examples/supabase-example", - "developer-resources/webhooks/examples/netlify-example" - ] - } + "api-reference/payouts/get-payouts" ] }, { - "group": "Testing & Demo Tools", - "icon": "flask", + "group": "Brands", "pages": [ - "miscellaneous/test-mode-vs-live-mode", - "miscellaneous/testing-process", - "features/atlas-demo-website" + "api-reference/brands/list-brands", + "api-reference/brands/create-brand", + "api-reference/brands/get-brand", + "api-reference/brands/update-brand", + "api-reference/brands/update-brand-images" ] }, { - "group": "Boilerplates", - "icon": "box-open", + "group": "Webhooks", "pages": [ - "developer-resources/expo-boilerplate", - "developer-resources/supabase-boilerplate", - "integrations/figma-plugin", - "developer-resources/nextjs-boilerplate", - "developer-resources/astro-boilerplate" + "api-reference/webhooks/list-webhooks", + "api-reference/webhooks/create-webhook", + "api-reference/webhooks/get-details", + "api-reference/webhooks/update-webhook", + "api-reference/webhooks/delete-webhook", + "api-reference/webhooks/get-webhook-headers", + "api-reference/webhooks/update-webhook-headers", + "api-reference/webhooks/get-webhook-signing-key" ] }, - "developer-resources/billingsdk", - "developer-resources/mcp-server" - ] - }, - { - "group": "Merchant of Record", - "pages": [ - "miscellaneous/verification-process", - "miscellaneous/list-of-countries-we-accept-payments-from", - "miscellaneous/merchant-acceptance", - "miscellaneous/review-monitoring-policy", - "features/mor-vs-pg", - "features/bypassing-app-store-fees" + { + "group": "Miscellaneous", + "pages": [ + "api-reference/misc/supported-countries", + "api-reference/misc/charge-subscriptions" + ] + } ] }, { - "group": "Miscellaneous", - "pages": [ + "tab": "External Integrations", + "icon": "plug", + "groups": [ { - "group": "Support Channels", - "icon": "headset", + "group": "External Integrations", "pages": [ - "miscellaneous/help-support", - "features/feature-request" + "integrations/introduction", + "integrations/woocommerce-plugin", + "integrations/framer-plugin", + "integrations/raycast-extension" ] }, { - "group": "GTM Tools", - "icon": "chart-line", + "group": "Messaging", "pages": [ - "miscellaneous/gtm-tools/saas-pricing-calculator", - "miscellaneous/gtm-tools/saas-revenue-and-profit-growth", - "miscellaneous/gtm-tools/saas-kpi-measurement", - "miscellaneous/gtm-tools/freemium-model", - "miscellaneous/gtm-tools/feature-prioritization-tool" + "integrations/slack", + "integrations/discord", + "integrations/microsoft-teams" ] }, - "features/mobile-app", - "miscellaneous/faq", - "miscellaneous/security-policy" - ] - } - ] - }, - { - "tab": "Guides", - "icon": "compass", - "groups": [ - { - "group": "Integration Guides", - "pages": [ - "developer-resources/integration-guide", - "developer-resources/subscription-integration-guide", - "developer-resources/usage-based-billing-guide", - "developer-resources/checkout-session", - "developer-resources/subscription-upgrade-downgrade", - "developer-resources/overlay-checkout", - "developer-resources/mobile-integration" - ] - }, - { - "group": "Cookbooks", - "tag": "New", - "pages": [ - "developer-resources/usage-based-billing-build-ai-image-generator", - "developer-resources/seat-based-pricing", - "developer-resources/build-an-ai-chat-app-with-usage-based-billing" - ] - } - ] - }, - { - "tab": "API Reference", - "icon": "rectangle-code", - "groups": [ - { - "group": "API Reference", - "pages": [ - "api-reference/introduction", - "api-reference/error-codes", - "api-reference/transaction-failures", - "api-reference/metadata" - ] - }, - { - "group": "Checkout Sessions", - "tag": "NEW", - "pages": [ - "api-reference/checkout-sessions/create", - "api-reference/checkout-sessions/get-checkouts" - ] - }, - { - "group": "Payments", - "pages": [ - "api-reference/payments/get-payments", - "api-reference/payments/get-payments-1", - "api-reference/payments/get-invoice", - "api-reference/payments/retrieve-line-items", - "api-reference/payments/post-payments" - ] - }, - { - "group": "Subscriptions", - "pages": [ - "api-reference/subscriptions/get-subscriptions-1", - "api-reference/subscriptions/get-subscriptions", - "api-reference/subscriptions/change-plan", - "api-reference/subscriptions/patch-subscriptions", - "api-reference/subscriptions/create-charge", - "api-reference/subscriptions/get-usage-history", - "api-reference/subscriptions/update-payment-method", - "api-reference/subscriptions/post-subscriptions" - ] - }, - { - "group": "Discounts", - "pages": [ - "api-reference/discounts/list-discounts", - "api-reference/discounts/create-discount", - "api-reference/discounts/validate-discount", - "api-reference/discounts/update-discount", - "api-reference/discounts/delete-discount" - ] - }, - { - "group": "Licenses", - "pages": [ - "api-reference/licenses/activate-license", - "api-reference/licenses/deactivate-license", - "api-reference/licenses/validate-license", - "api-reference/licenses/list-license-keys", - "api-reference/licenses/get-license-key", - "api-reference/licenses/update-license-key", - "api-reference/licenses/get-license-key-instances", - "api-reference/licenses/get-license-key-instance", - "api-reference/licenses/update-license-key-instance" - ] - }, - { - "group": "Customers", - "pages": [ - "api-reference/customers/create-customer", - "api-reference/customers/get-customers", - "api-reference/customers/get-customers-1", - "api-reference/customers/patch-customer", - "api-reference/customers/create-customer-portal-session", - "api-reference/customers/get-customer-payment-methods" - ] - }, - { - "group": "Customer Wallets", - "tag": "NEW", - "pages": [ - "api-reference/customers/get-customer-wallets", - "api-reference/customers/get-customer-wallets-ledger-entries", - "api-reference/customers/post-customer-wallets-ledger-entries" - ] - }, - { - "group": "Products", - "pages": [ - "api-reference/products/get-products", - "api-reference/products/post-products", - "api-reference/products/get-products-1", - "api-reference/products/patch-products", - "api-reference/products/put-products-images", - "api-reference/products/archive-product", - "api-reference/products/unarchive-product", - "api-reference/products/update-files" - ] - }, - { - "group": "Addons", - "pages": [ - "api-reference/addons/create-addon", - "api-reference/addons/list-addons", - "api-reference/addons/get-addon", - "api-reference/addons/update-addon", - "api-reference/addons/update-addon-images" - ] - }, - { - "group": "Meters", - "pages": [ - "api-reference/meters/create-meter", - "api-reference/meters/get-meters", - "api-reference/meters/retrieve-meter", - "api-reference/meters/archive-meter", - "api-reference/meters/unarchive-meter" - ] - }, - { - "group": "Usage Events", - "pages": [ - "api-reference/usage-events/ingest-events", - "api-reference/usage-events/get-event", - "api-reference/usage-events/list-events" - ] - }, - { - "group": "Refunds", - "pages": [ - "api-reference/refunds/get-refunds", - "api-reference/refunds/post-refunds", - "api-reference/refunds/get-refunds-1", - "api-reference/refunds/get-refund-receipt" - ] - }, - { - "group": "Disputes", - "pages": [ - "api-reference/disputes/get-disputes", - "api-reference/disputes/get-disputes-1" - ] - }, - { - "group": "Payouts", - "pages": [ - "api-reference/payouts/get-payouts" - ] - }, - { - "group": "Brands", - "pages": [ - "api-reference/brands/list-brands", - "api-reference/brands/create-brand", - "api-reference/brands/get-brand", - "api-reference/brands/update-brand", - "api-reference/brands/update-brand-images" - ] - }, - { - "group": "Webhooks", - "pages": [ - "api-reference/webhooks/list-webhooks", - "api-reference/webhooks/create-webhook", - "api-reference/webhooks/get-details", - "api-reference/webhooks/update-webhook", - "api-reference/webhooks/delete-webhook", - "api-reference/webhooks/get-webhook-headers", - "api-reference/webhooks/update-webhook-headers", - "api-reference/webhooks/get-webhook-signing-key" - ] - }, - { - "group": "Miscellaneous", - "pages": [ - "api-reference/misc/supported-countries", - "api-reference/misc/charge-subscriptions" - ] - } - ] - }, - { - "tab": "External Integrations", - "icon": "plug", - "groups": [ - { - "group": "External Integrations", - "pages": [ - "integrations/introduction", - "integrations/woocommerce-plugin", - "integrations/framer-plugin", - "integrations/raycast-extension" - ] - }, - { - "group": "Messaging", - "pages": [ - "integrations/slack", - "integrations/discord", - "integrations/microsoft-teams" - ] - }, - { - "group": "Workflow Automation", - "pages": [ - "integrations/zapier", - "integrations/windmill", - "integrations/inngest" - ] - }, - { - "group": "CRM", - "pages": [ - "integrations/hubspot", - "integrations/close-crm" - ] - }, - { - "group": "Email", - "pages": [ - "integrations/resend", - "integrations/loops", - "integrations/sendgrid" - ] - }, - { - "group": "Analytics", - "pages": [ - "integrations/segment", - "integrations/customer-io" - ] - } - ] - }, - { - "tab": "Changelog", - "icon": "calendar-days", - "groups": [ - { - "group": "Changelog", - "pages": [ - "changelog/introduction" - ] - }, - { - "group": "November 2025", - "pages": [ - "changelog/v1.61.5" - ] - }, - { - "group": "October 2025", - "pages": [ - "changelog/v1.56.0" - ] - }, - { - "group": "September 2025", - "pages": [ - "changelog/v1.53.2", - "changelog/v1.52.4" - ] - }, - { - "group": "August 2025", - "pages": [ - "changelog/v1.51.0", - "changelog/v1.47.0", - "changelog/v1.44.0" - ] - }, - { - "group": "July 2025", - "pages": [ - "changelog/v1.43.0", - "changelog/v1.38.0", - "changelog/v1.37.0" - ] - }, - { - "group": "June 2025", - "pages": [ - "changelog/v1.34.4", - "changelog/v1.34.0", - "changelog/v1.32.0", - "changelog/v1.30.0" - ] - }, - { - "group": "May 2025", - "pages": [ - "changelog/v1.27.0", - "changelog/v1.25.0", - "changelog/v1.22.0", - "changelog/v1.21.0" - ] - }, - { - "group": "April 2025", - "pages": [ - "changelog/v1.18.3", - "changelog/v1.16.1", - "changelog/v1.14.0", - "changelog/v1.13.0" - ] - }, - { - "group": "March 2025", - "pages": [ - "changelog/v1.11.0", - "changelog/v1.10.1", - "changelog/v1.7.0", - "changelog/v1.5.0", - "changelog/v1.4.0" - ] - }, - { - "group": "February 2025", - "pages": [ - "changelog/v1.3.2", - "changelog/v1.0.0", - "changelog/v0.24.0", - "changelog/v0.22.0" - ] - }, - { - "group": "January 2025", - "pages": [ - "changelog/v0.20.1", - "changelog/v0.19.0", - "changelog/v0.18.0", - "changelog/v0.16.1", - "changelog/v0.15.1" + { + "group": "Workflow Automation", + "pages": [ + "integrations/zapier", + "integrations/windmill", + "integrations/inngest" + ] + }, + { + "group": "CRM", + "pages": [ + "integrations/hubspot", + "integrations/close-crm" + ] + }, + { + "group": "Email", + "pages": [ + "integrations/resend", + "integrations/loops", + "integrations/sendgrid" + ] + }, + { + "group": "Analytics", + "pages": [ + "integrations/segment", + "integrations/customer-io" + ] + } ] }, { - "group": "December 2024", - "pages": [ - "changelog/v0.14.0", - "changelog/v0.13.2", - "changelog/v0.12.0", - "changelog/v0.11.0", - "changelog/v0.10.0" + "tab": "Changelog", + "icon": "calendar-days", + "groups": [ + { + "group": "Changelog", + "pages": [ + "changelog/introduction" + ] + }, + { + "group": "November 2025", + "pages": [ + "changelog/v1.61.5" + ] + }, + { + "group": "October 2025", + "pages": [ + "changelog/v1.56.0" + ] + }, + { + "group": "September 2025", + "pages": [ + "changelog/v1.53.2", + "changelog/v1.52.4" + ] + }, + { + "group": "August 2025", + "pages": [ + "changelog/v1.51.0", + "changelog/v1.47.0", + "changelog/v1.44.0" + ] + }, + { + "group": "July 2025", + "pages": [ + "changelog/v1.43.0", + "changelog/v1.38.0", + "changelog/v1.37.0" + ] + }, + { + "group": "June 2025", + "pages": [ + "changelog/v1.34.4", + "changelog/v1.34.0", + "changelog/v1.32.0", + "changelog/v1.30.0" + ] + }, + { + "group": "May 2025", + "pages": [ + "changelog/v1.27.0", + "changelog/v1.25.0", + "changelog/v1.22.0", + "changelog/v1.21.0" + ] + }, + { + "group": "April 2025", + "pages": [ + "changelog/v1.18.3", + "changelog/v1.16.1", + "changelog/v1.14.0", + "changelog/v1.13.0" + ] + }, + { + "group": "March 2025", + "pages": [ + "changelog/v1.11.0", + "changelog/v1.10.1", + "changelog/v1.7.0", + "changelog/v1.5.0", + "changelog/v1.4.0" + ] + }, + { + "group": "February 2025", + "pages": [ + "changelog/v1.3.2", + "changelog/v1.0.0", + "changelog/v0.24.0", + "changelog/v0.22.0" + ] + }, + { + "group": "January 2025", + "pages": [ + "changelog/v0.20.1", + "changelog/v0.19.0", + "changelog/v0.18.0", + "changelog/v0.16.1", + "changelog/v0.15.1" + ] + }, + { + "group": "December 2024", + "pages": [ + "changelog/v0.14.0", + "changelog/v0.13.2", + "changelog/v0.12.0", + "changelog/v0.11.0", + "changelog/v0.10.0" + ] + }, + { + "group": "November 2024", + "pages": [ + "changelog/v0.1.0" + ] + } ] }, { - "group": "November 2024", - "pages": [ - "changelog/v0.1.0" + "tab": "Community Projects", + "icon": "users", + "groups": [ + { + "group": "Community Projects", + "pages": [ + "community/overview", + "community/projects", + "community/submit" + ] + } ] } ] }, { - "tab": "Community Projects", - "icon": "users", - "groups": [ + "language": "zh", + "tabs": [ { - "group": "Community Projects", - "pages": [ - "community/overview", - "community/projects", - "community/submit" + "tab": "Documentation", + "icon": "book", + "groups": [ + { + "group": "Getting Started", + "pages": [ + "zh/introduction", + "zh/migrate-to-dodo" + ] + }, + { + "group": "Features", + "pages": [ + "zh/features/products", + "zh/features/one-time-payment-products", + { + "group": "Subscriptions", + "icon": "infinity", + "pages": [ + "zh/features/subscription", + "zh/features/addons", + "zh/developer-resources/ondemand-subscriptions" + ] + }, + { + "group": "Usage Based Billing", + "icon": "arrow-trend-up", + "tag": "NEW", + "pages": [ + "zh/features/usage-based-billing/introduction", + "zh/features/usage-based-billing/meters", + "zh/features/usage-based-billing/event-ingestion", + "zh/features/customer-credit", + { + "group": "Ingestion Blueprints", + "icon": "copy", + "pages": [ + "zh/features/usage-based-billing/ingestion-blueprints", + "zh/developer-resources/ingestion-blueprints/llm", + "zh/developer-resources/ingestion-blueprints/api-gateway", + "zh/developer-resources/ingestion-blueprints/object-storage", + "zh/developer-resources/ingestion-blueprints/stream", + "zh/developer-resources/ingestion-blueprints/time-range" + ] + } + ] + }, + { + "group": "Customers", + "icon": "user-group", + "pages": [ + "zh/features/customers", + "zh/features/customer-portal", + "zh/features/customer-wallet" + ] + }, + "zh/features/discount-codes", + { + "group": "Transactions", + "icon": "credit-card", + "pages": [ + "zh/features/transactions/payments", + "zh/features/transactions/refunds", + "zh/features/transactions/disputes" + ] + }, + { + "group": "Entitlements", + "icon": "gift", + "pages": [ + "zh/features/license-keys", + "zh/features/digital-product-delivery" + ] + }, + { + "group": "Payouts and Balances", + "icon": "wallet", + "pages": [ + "zh/features/payouts/payout-structure", + "zh/features/account-summary-payout-wallet" + ] + }, + { + "group": "Account Management", + "icon": "user", + "pages": [ + "zh/features/multi-brands", + "zh/features/invoice-generation", + "zh/features/team", + "zh/miscellaneous/accounts" + ] + }, + { + "group": "Pricing", + "icon": "dollar-sign", + "pages": [ + "zh/features/tax-inclusive-pricing", + "zh/features/pay-what-you-want", + "zh/features/b2b-payments", + "zh/features/purchasing-power-parity" + ] + }, + "zh/features/payment-methods", + "zh/features/adaptive-currency", + "zh/features/analytics-and-reporting", + "zh/features/storefront", + "zh/features/affiliates", + "zh/features/appstore-digital-goods" + ] + }, + { + "group": "Integrate", + "pages": [ + { + "group": "SDKs", + "icon": "box-open", + "pages": [ + "zh/developer-resources/dodo-payments-sdks", + "zh/developer-resources/sdks/typescript", + "zh/developer-resources/sdks/python", + "zh/developer-resources/sdks/go", + "zh/developer-resources/sdks/ruby", + "zh/developer-resources/sdks/java", + "zh/developer-resources/sdks/kotlin", + "zh/developer-resources/sdks/cli", + "zh/developer-resources/sdks/php", + "zh/developer-resources/sdks/csharp", + "zh/developer-resources/react-native-integration" + ] + }, + { + "group": "Framework Adaptors", + "icon": "frame", + "pages": [ + "zh/developer-resources/nextjs-adaptor", + "zh/developer-resources/nuxt-adaptor", + "zh/developer-resources/better-auth-adaptor", + "zh/developer-resources/express-adaptor", + "zh/developer-resources/astro-adaptor", + "zh/developer-resources/sveltekit-adaptor", + "zh/developer-resources/hono-adaptor", + "zh/developer-resources/remix-adaptor", + "zh/developer-resources/tanstack-adaptor", + "zh/developer-resources/fastify-adaptor", + "zh/developer-resources/convex-component" + ] + }, + { + "group": "Webhooks", + "icon": "webhook", + "pages": [ + "zh/developer-resources/webhooks", + "zh/developer-resources/webhooks/intents/webhook-events-guide", + { + "group": "Webhook Payloads", + "icon": "code", + "pages": [ + "zh/developer-resources/webhooks/intents/payment", + "zh/developer-resources/webhooks/intents/subscription", + "zh/developer-resources/webhooks/intents/refund", + "zh/developer-resources/webhooks/intents/dispute", + "zh/developer-resources/webhooks/intents/license-key" + ] + }, + { + "group": "Deploy to Cloud", + "icon": "rocket", + "pages": [ + "zh/developer-resources/webhooks/examples/vercel-example", + "zh/developer-resources/webhooks/examples/cloudflare-example", + "zh/developer-resources/webhooks/examples/supabase-example", + "zh/developer-resources/webhooks/examples/netlify-example" + ] + } + ] + }, + { + "group": "Testing & Demo Tools", + "icon": "flask", + "pages": [ + "zh/miscellaneous/test-mode-vs-live-mode", + "zh/miscellaneous/testing-process", + "zh/features/atlas-demo-website" + ] + }, + { + "group": "Boilerplates", + "icon": "box-open", + "pages": [ + "zh/developer-resources/expo-boilerplate", + "zh/developer-resources/supabase-boilerplate", + "zh/integrations/figma-plugin", + "zh/developer-resources/nextjs-boilerplate", + "zh/developer-resources/astro-boilerplate" + ] + }, + "zh/developer-resources/billingsdk", + "zh/developer-resources/mcp-server" + ] + }, + { + "group": "Merchant of Record", + "pages": [ + "zh/miscellaneous/verification-process", + "zh/miscellaneous/list-of-countries-we-accept-payments-from", + "zh/miscellaneous/merchant-acceptance", + "zh/miscellaneous/review-monitoring-policy", + "zh/features/mor-vs-pg", + "zh/features/bypassing-app-store-fees" + ] + }, + { + "group": "Miscellaneous", + "pages": [ + { + "group": "Support Channels", + "icon": "headset", + "pages": [ + "zh/miscellaneous/help-support", + "zh/features/feature-request" + ] + }, + { + "group": "GTM Tools", + "icon": "chart-line", + "pages": [ + "zh/miscellaneous/gtm-tools/saas-pricing-calculator", + "zh/miscellaneous/gtm-tools/saas-revenue-and-profit-growth", + "zh/miscellaneous/gtm-tools/saas-kpi-measurement", + "zh/miscellaneous/gtm-tools/freemium-model", + "zh/miscellaneous/gtm-tools/feature-prioritization-tool" + ] + }, + "zh/features/mobile-app", + "zh/miscellaneous/faq", + "zh/miscellaneous/security-policy" + ] + } ] } ] @@ -983,4 +1234,4 @@ "destination": "https://dodopayments.com/pricing" } ] -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 1108c1e..ce2b4cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,1892 @@ { "name": "dodo-docs", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, - "packages": {} + "packages": { + "": { + "name": "dodo-docs", + "version": "1.0.0", + "license": "GPL-3.0", + "dependencies": { + "chalk": "^5.3.0", + "dotenv": "^16.4.5", + "fs-extra": "^11.2.0", + "glob": "^10.3.10", + "gray-matter": "^4.0.3", + "openai": "^4.28.0", + "ora": "^8.0.1" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/node": "^20.11.0", + "tsx": "^4.7.0", + "typescript": "^5.3.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", + "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } } diff --git a/package.json b/package.json new file mode 100644 index 0000000..160e562 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "dodo-docs", + "version": "1.0.0", + "description": "Dodo Payments Documentation with Multi-Language Support", + "type": "module", + "scripts": { + "translate": "tsx scripts/translate.ts", + "translate:full": "tsx scripts/translate.ts --full", + "translate:lang": "tsx scripts/translate.ts --lang", + "update-nav": "tsx scripts/update-navigation.ts", + "build": "tsc", + "type-check": "tsc --noEmit" + }, + "keywords": [ + "documentation", + "mintlify", + "translation" + ], + "author": "", + "license": "GPL-3.0", + "dependencies": { + "openai": "^4.28.0", + "gray-matter": "^4.0.3", + "glob": "^10.3.10", + "fs-extra": "^11.2.0", + "chalk": "^5.3.0", + "ora": "^8.0.1", + "dotenv": "^16.4.5" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/node": "^20.11.0", + "tsx": "^4.7.0", + "typescript": "^5.3.3" + } +} + diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..574d9df --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,142 @@ +# Translation Pipeline + +Automated translation pipeline for Dodo Payments documentation using OpenAI's API. + +## Setup + +1. **Install dependencies:** + ```bash + npm install + ``` + +2. **Set up environment variables:** + ```bash + cp .env.example .env + # Edit .env and add your OPENAI_API_KEY + ``` + +3. **Get OpenAI API Key:** + - Visit https://platform.openai.com/api-keys + - Create a new API key + - Add it to your `.env` file + +## Usage + +### Translate all files (incremental) + +By default, the pipeline only translates files that: +- Don't exist in the target language +- Have been modified since the last translation + +```bash +npm run translate +``` + +### Translate all files (full re-translation) + +Re-translate all files regardless of cache: + +```bash +npm run translate:full +``` + +### Translate to specific language + +```bash +npm run translate:lang -- --lang=es +``` + +### Update navigation + +After translation, update `docs.json` with multi-language navigation: + +```bash +npm run update-nav +``` + +## Supported Languages + +- `en` - English (source) +- `zh` - Chinese (Simplified) +- `fr` - French +- `de` - German +- `id` - Indonesian +- `ja` - Japanese +- `ko` - Korean +- `pt-BR` - Portuguese (Brazil) +- `es` - Spanish + +## How It Works + +1. **File Discovery**: Scans all `.mdx` files in the repository +2. **Content Parsing**: Extracts translatable content while preserving: + - Code blocks (```language) + - Inline code (`code`) + - Mintlify components structure + - Image paths and URLs +3. **Translation**: Uses OpenAI GPT-4 Turbo to translate content with specialized prompts for technical documentation +4. **File Generation**: Creates translated files in language-specific directories (e.g., `es/introduction.mdx`) +5. **Caching**: Stores file hashes to enable incremental updates + +## Translation Cache + +The pipeline maintains a `.translation-cache.json` file that tracks: +- Which files have been translated +- When source files were last modified +- File hashes for change detection + +To clear the cache and force re-translation of all files: +```bash +rm .translation-cache.json +npm run translate +``` + +## Cost Considerations + +- Uses GPT-4 Turbo for high-quality translations +- Processes files sequentially to avoid rate limits +- Caches translations to minimize API calls +- Typical cost: ~$0.01-0.03 per page per language + +## Troubleshooting + +### API Rate Limits + +If you hit rate limits, the script will show errors. Wait a few minutes and re-run. The cache will prevent re-translating already completed files. + +### Translation Quality + +The pipeline is optimized for technical documentation. If you notice issues: +- Check that technical terms are preserved (they should be) +- Review the translated files and manually adjust if needed +- The source English files remain unchanged + +### Missing Files + +If a translated file is missing, delete it from the cache and re-run: +```bash +# Edit .translation-cache.json and remove the entry for that file +npm run translate +``` + +## File Structure + +After translation, your directory structure will look like: + +``` +docs/ +├── introduction.mdx # English (source) +├── es/ +│ └── introduction.mdx # Spanish +├── fr/ +│ └── introduction.mdx # French +└── ... +``` + +## Notes + +- English files remain in the root directory +- Translated files are organized in language subdirectories +- Mintlify's navigation system will automatically handle language switching +- Code examples and technical terms are preserved in all translations + diff --git a/scripts/translate.ts b/scripts/translate.ts new file mode 100644 index 0000000..0ab1f0f --- /dev/null +++ b/scripts/translate.ts @@ -0,0 +1,250 @@ +#!/usr/bin/env node + +import 'dotenv/config'; +import { glob } from 'glob'; +import fs from 'fs-extra'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import crypto from 'crypto'; +import chalk from 'chalk'; +import ora from 'ora'; +import { parseMDX, reconstructMDX } from './utils/mdx-parser.js'; +import { translateContent } from './utils/translator.js'; +import { getTranslationCache, updateTranslationCache } from './utils/cache.js'; +import type { Language, TranslationResult, TranslationResults } from './utils/types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const rootDir = path.resolve(__dirname, '..'); + +// Supported languages +const LANGUAGES: Record = { + en: 'English', + zh: 'Chinese (Simplified)', + fr: 'French', + de: 'German', + id: 'Indonesian', + ja: 'Japanese', + ko: 'Korean', + 'pt-BR': 'Portuguese (Brazil)', + es: 'Spanish' +}; + +// Files/directories to exclude +const EXCLUDE_PATTERNS = [ + 'node_modules/**', + '.git/**', + 'scripts/**', + 'coordination/**', + '**/en/**', // Exclude existing language directories + '**/zh/**', + '**/fr/**', + '**/de/**', + '**/id/**', + '**/ja/**', + '**/ko/**', + '**/pt-BR/**', + '**/es/**', + 'package*.json', + '*.lock', + '*.log', + '.env*', + 'README.md', + 'CONTRIBUTING.md', + 'LICENSE' +]; + +async function findMDXFiles(): Promise { + const spinner = ora('Scanning for MDX files...').start(); + + try { + const files = await glob('**/*.mdx', { + cwd: rootDir, + ignore: EXCLUDE_PATTERNS, + absolute: true + }); + + spinner.succeed(`Found ${files.length} MDX files`); + return files; + } catch (error) { + spinner.fail('Failed to scan files'); + throw error; + } +} + +function getRelativePath(filePath: string): string { + return path.relative(rootDir, filePath); +} + +function getTargetPath(filePath: string, language: Language): string { + const relativePath = getRelativePath(filePath); + const dir = path.dirname(relativePath); + const filename = path.basename(relativePath); + + if (dir === '.') { + return path.join(rootDir, language, filename); + } + return path.join(rootDir, language, dir, filename); +} + +function calculateContentHash(content: string): string { + return crypto.createHash('sha256').update(content).digest('hex'); +} + +async function shouldTranslate(filePath: string, language: Language, fullMode = false): Promise { + const targetPath = getTargetPath(filePath, language); + const targetExists = await fs.pathExists(targetPath); + + if (!targetExists) { + return true; // File doesn't exist, needs translation + } + + if (fullMode) { + return true; // Full mode, translate everything + } + + // Check if source file content has changed + const cache = getTranslationCache(); + const relativePath = getRelativePath(filePath); + + // Calculate content-based hash + const content = await fs.readFile(filePath, 'utf-8'); + const sourceHash = calculateContentHash(content); + + const cacheKey = `${relativePath}:${language}`; + const cachedHash = cache[cacheKey]; + + if (cachedHash !== sourceHash) { + return true; // File content has changed + } + + return false; // File is up to date +} + +async function translateFile(filePath: string, language: Language, fullMode = false): Promise { + const relativePath = getRelativePath(filePath); + + if (!(await shouldTranslate(filePath, language, fullMode))) { + return { skipped: true, path: relativePath }; + } + + const spinner = ora(`Translating ${relativePath} to ${LANGUAGES[language]}...`).start(); + + try { + // Read source file + const content = await fs.readFile(filePath, 'utf-8'); + + // Calculate content-based hash for cache + const sourceHash = calculateContentHash(content); + + // Parse MDX content + const parsed = parseMDX(content); + + // Translate content + const translated = await translateContent(parsed, language); + + // Reconstruct MDX + const translatedMDX = reconstructMDX(translated); + + // Write translated file + const targetPath = getTargetPath(filePath, language); + await fs.ensureDir(path.dirname(targetPath)); + await fs.writeFile(targetPath, translatedMDX, 'utf-8'); + + // Update cache with content hash + updateTranslationCache(getRelativePath(filePath), language, sourceHash); + + spinner.succeed(`Translated ${relativePath} to ${LANGUAGES[language]}`); + return { success: true, path: relativePath }; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + spinner.fail(`Failed to translate ${relativePath}: ${errorMessage}`); + return { error: true, path: relativePath, message: errorMessage }; + } +} + +async function main(): Promise { + const args = process.argv.slice(2); + const fullMode = args.includes('--full'); + const langArg = args.find(arg => arg.startsWith('--lang=')); + const targetLanguages = (langArg + ? [langArg.split('=')[1] as Language] + : Object.keys(LANGUAGES).filter(lang => lang !== 'en') as Language[]); + + console.log(chalk.blue.bold('\n🌍 Dodo Docs Translation Pipeline\n')); + + if (fullMode) { + console.log(chalk.yellow('⚠️ Full mode: All files will be re-translated\n')); + } + + // Check for OpenAI API key + if (!process.env.OPENAI_API_KEY) { + console.error(chalk.red('❌ Error: OPENAI_API_KEY environment variable is not set')); + console.log(chalk.gray('Please set it in your .env file or export it in your shell')); + process.exit(1); + } + + try { + // Find all MDX files + const files = await findMDXFiles(); + + if (files.length === 0) { + console.log(chalk.yellow('No MDX files found to translate')); + return; + } + + console.log(chalk.cyan(`\nTranslating to ${targetLanguages.length} language(s): ${targetLanguages.join(', ')}\n`)); + + const results: TranslationResults = { + success: 0, + skipped: 0, + errors: 0 + }; + + // Process each language + for (const language of targetLanguages) { + console.log(chalk.blue.bold(`\n📝 Processing ${LANGUAGES[language]} (${language})...\n`)); + + // Process each file + for (const file of files) { + const result = await translateFile(file, language, fullMode); + + if (result.success) { + results.success++; + } else if (result.skipped) { + results.skipped++; + } else if (result.error) { + results.errors++; + } + + // Small delay to avoid rate limiting + await new Promise(resolve => setTimeout(resolve, 100)); + } + } + + // Save cache + const cache = getTranslationCache(); + await fs.writeJSON( + path.join(rootDir, '.translation-cache.json'), + cache, + { spaces: 2 } + ); + + // Print summary + console.log(chalk.blue.bold('\n\n📊 Translation Summary\n')); + console.log(chalk.green(`✅ Successfully translated: ${results.success}`)); + console.log(chalk.yellow(`⏭️ Skipped (up to date): ${results.skipped}`)); + if (results.errors > 0) { + console.log(chalk.red(`❌ Errors: ${results.errors}`)); + } + console.log(chalk.cyan('\n✨ Translation complete!')); + console.log(chalk.gray('\nNext step: Run "npm run update-nav" to update docs.json with multi-language navigation\n')); + + } catch (error) { + console.error(chalk.red('\n❌ Fatal error:'), error); + process.exit(1); + } +} + +main(); + diff --git a/scripts/update-navigation.ts b/scripts/update-navigation.ts new file mode 100644 index 0000000..0528aa8 --- /dev/null +++ b/scripts/update-navigation.ts @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +import fs from 'fs-extra'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import chalk from 'chalk'; +import type { Language } from './utils/types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const rootDir = path.resolve(__dirname, '..'); + +const LANGUAGES: Language[] = ['en', 'zh', 'fr', 'de', 'id', 'ja', 'ko', 'pt-BR', 'es']; + +type NavigationItem = string | NavigationObject | NavigationArray; +type NavigationObject = Record; +type NavigationArray = NavigationItem[]; + +/** + * Recursively processes a navigation structure and updates paths + */ +function processNavigationStructure(navItem: NavigationItem, language: Language): NavigationItem { + if (typeof navItem === 'string') { + // Simple page path + if (language === 'en') { + return navItem; + } + return `${language}/${navItem}`; + } + + if (Array.isArray(navItem)) { + return navItem.map(item => processNavigationStructure(item, language)); + } + + if (typeof navItem === 'object' && navItem !== null) { + const processed: NavigationObject = {}; + + for (const [key, value] of Object.entries(navItem)) { + if (key === 'pages' && Array.isArray(value)) { + processed[key] = value.map(page => processNavigationStructure(page, language)); + } else if (key === 'groups' && Array.isArray(value)) { + processed[key] = value.map(group => processNavigationStructure(group, language)); + } else if (key === 'tabs' && Array.isArray(value)) { + processed[key] = value.map(tab => processNavigationStructure(tab, language)); + } else { + processed[key] = value; + } + } + + return processed; + } + + return navItem; +} + +/** + * Creates language-specific navigation structure + */ +function createLanguageNavigation(originalNavigation: NavigationObject, language: Language): NavigationObject { + return processNavigationStructure(originalNavigation, language) as NavigationObject; +} + +/** + * Main function to update docs.json with multi-language navigation + */ +async function main(): Promise { + console.log(chalk.blue.bold('\n🌍 Updating Navigation for Multi-Language Support\n')); + + try { + // Read current docs.json + const docsJsonPath = path.join(rootDir, 'docs.json'); + const docsConfig = await fs.readJSON(docsJsonPath) as { navigation?: NavigationObject }; + + if (!docsConfig.navigation) { + console.error(chalk.red('❌ Error: docs.json does not have a navigation property')); + process.exit(1); + } + + const originalNavigation = docsConfig.navigation; + + // Create languages array + const languages = LANGUAGES.map(language => { + const languageNav = createLanguageNavigation(originalNavigation, language); + return { + language, + ...languageNav // Spread tabs, groups, or pages depending on structure + }; + }); + + // Update docs.json with languages structure + docsConfig.navigation = { + languages + } as NavigationObject; + + // Keep other navigation properties if they exist (like global anchors) + if ('global' in originalNavigation) { + (docsConfig.navigation as NavigationObject).global = originalNavigation.global; + } + + // Write updated docs.json + await fs.writeJSON(docsJsonPath, docsConfig, { spaces: 2 }); + + console.log(chalk.green('✅ Successfully updated docs.json with multi-language navigation')); + console.log(chalk.cyan(`\n📝 Configured languages: ${LANGUAGES.join(', ')}`)); + console.log(chalk.gray('\nNote: Make sure all translated files exist before deploying.\n')); + + } catch (error) { + console.error(chalk.red('\n❌ Error updating navigation:'), error); + process.exit(1); + } +} + +main(); + diff --git a/scripts/utils/cache.ts b/scripts/utils/cache.ts new file mode 100644 index 0000000..2226086 --- /dev/null +++ b/scripts/utils/cache.ts @@ -0,0 +1,61 @@ +import fs from 'fs-extra'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import type { Language, TranslationCache } from './types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const rootDir = path.resolve(__dirname, '../..'); +const cachePath = path.join(rootDir, '.translation-cache.json'); + +let cache: TranslationCache | null = null; + +/** + * Loads translation cache from disk + */ +function loadCache(): TranslationCache { + if (cache !== null) { + return cache; + } + + if (fs.existsSync(cachePath)) { + try { + cache = fs.readJSONSync(cachePath) as TranslationCache; + return cache; + } catch (error) { + console.warn('Failed to load translation cache, starting fresh'); + cache = {}; + return cache; + } + } + + cache = {}; + return cache; +} + +/** + * Gets the translation cache + */ +export function getTranslationCache(): TranslationCache { + return loadCache(); +} + +/** + * Updates the translation cache + */ +export function updateTranslationCache(filePath: string, language: Language, hash: string): void { + const cache = loadCache(); + const key = `${filePath}:${language}`; + cache[key] = hash; +} + +/** + * Clears the translation cache + */ +export function clearTranslationCache(): void { + cache = {}; + if (fs.existsSync(cachePath)) { + fs.removeSync(cachePath); + } +} + diff --git a/scripts/utils/mdx-parser.ts b/scripts/utils/mdx-parser.ts new file mode 100644 index 0000000..2c05faa --- /dev/null +++ b/scripts/utils/mdx-parser.ts @@ -0,0 +1,173 @@ +import matter from 'gray-matter'; +import type { ParsedMDX, ParsedComponent, ComponentContent } from './types.js'; + +/** + * Parses MDX content into structured components + */ +export function parseMDX(content: string): ParsedMDX { + const { data: frontmatter, content: body } = matter(content); + + // Extract code blocks and replace with placeholders + const codeBlockRegex = /```[\s\S]*?```/g; + const codeBlocks: string[] = []; + let codeBlockIndex = 0; + + let processedBody = body.replace(codeBlockRegex, (match) => { + const placeholder = `__CODE_BLOCK_${codeBlockIndex}__`; + codeBlocks.push(match); + codeBlockIndex++; + return placeholder; + }); + + // Extract inline code and replace with placeholders + const inlineCodeRegex = /`[^`\n]+`/g; + const inlineCodes: string[] = []; + let inlineCodeIndex = 0; + + processedBody = processedBody.replace(inlineCodeRegex, (match) => { + const placeholder = `__INLINE_CODE_${inlineCodeIndex}__`; + inlineCodes.push(match); + inlineCodeIndex++; + return placeholder; + }); + + // Extract Mintlify components (handles both self-closing and paired tags) + const componentRegex = /<(\w+)([^>]*?)(?:\/>|>([\s\S]*?)<\/\1>)/g; + const components: ParsedComponent[] = []; + let componentIndex = 0; + + processedBody = processedBody.replace(componentRegex, (match, tagName: string, attributes: string, content: string | undefined) => { + const placeholder = `__COMPONENT_${componentIndex}__`; + + // Handle self-closing tags + if (match.endsWith('/>') || !content) { + components.push({ + tag: tagName, + attributes: attributes.trim(), + content: null, + original: match, + selfClosing: true + }); + } else { + // Parse component content recursively + const parsedContent = parseComponentContent(content); + + components.push({ + tag: tagName, + attributes: attributes.trim(), + content: parsedContent, + original: match, + selfClosing: false + }); + } + + componentIndex++; + return placeholder; + }); + + return { + frontmatter, + body: processedBody, + codeBlocks, + inlineCodes, + components + }; +} + +/** + * Recursively parse component content + */ +function parseComponentContent(content: string): ComponentContent { + // Extract nested code blocks + const codeBlockRegex = /```[\s\S]*?```/g; + const codeBlocks: string[] = []; + let codeBlockIndex = 0; + + let processed = content.replace(codeBlockRegex, (match) => { + const placeholder = `__CODE_BLOCK_${codeBlockIndex}__`; + codeBlocks.push(match); + codeBlockIndex++; + return placeholder; + }); + + // Extract inline code + const inlineCodeRegex = /`[^`\n]+`/g; + const inlineCodes: string[] = []; + let inlineCodeIndex = 0; + + processed = processed.replace(inlineCodeRegex, (match) => { + const placeholder = `__INLINE_CODE_${inlineCodeIndex}__`; + inlineCodes.push(match); + inlineCodeIndex++; + return placeholder; + }); + + return { + text: processed, + codeBlocks, + inlineCodes + }; +} + +/** + * Reconstructs MDX content from parsed structure + */ +export function reconstructMDX(parsed: ParsedMDX): string { + const { frontmatter, body, codeBlocks, inlineCodes, components } = parsed; + + // Restore components (in reverse order to maintain indices) + let processedBody = body; + for (let i = components.length - 1; i >= 0; i--) { + const component = components[i]; + const placeholder = `__COMPONENT_${i}__`; + + let restored: string; + if (component.selfClosing) { + restored = `<${component.tag}${component.attributes ? ' ' + component.attributes : ''} />`; + } else { + const restoredContent = restoreComponentContent(component.content!); + restored = `<${component.tag}${component.attributes ? ' ' + component.attributes : ''}>${restoredContent}`; + } + + processedBody = processedBody.replace(placeholder, restored); + } + + // Restore inline code (in reverse order) + for (let i = inlineCodes.length - 1; i >= 0; i--) { + const placeholder = `__INLINE_CODE_${i}__`; + processedBody = processedBody.replace(placeholder, inlineCodes[i]); + } + + // Restore code blocks (in reverse order) + for (let i = codeBlocks.length - 1; i >= 0; i--) { + const placeholder = `__CODE_BLOCK_${i}__`; + processedBody = processedBody.replace(placeholder, codeBlocks[i]); + } + + // Reconstruct frontmatter + const frontmatterString = matter.stringify('', frontmatter).trim(); + + return frontmatterString + '\n\n' + processedBody; +} + +/** + * Restore component content + */ +function restoreComponentContent(content: ComponentContent): string { + let { text, codeBlocks, inlineCodes } = content; + + // Restore inline code + for (let i = inlineCodes.length - 1; i >= 0; i--) { + const placeholder = `__INLINE_CODE_${i}__`; + text = text.replace(placeholder, inlineCodes[i]); + } + + // Restore code blocks + for (let i = codeBlocks.length - 1; i >= 0; i--) { + const placeholder = `__CODE_BLOCK_${i}__`; + text = text.replace(placeholder, codeBlocks[i]); + } + + return text; +} + diff --git a/scripts/utils/translator.ts b/scripts/utils/translator.ts new file mode 100644 index 0000000..4fabc02 --- /dev/null +++ b/scripts/utils/translator.ts @@ -0,0 +1,200 @@ +import 'dotenv/config'; +import OpenAI from 'openai'; +import chalk from 'chalk'; +import type { Language, ParsedMDX, ParsedComponent, ComponentContent } from './types.js'; + +const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY +}); + +const LANGUAGE_NAMES: Record = { + en: 'English', + zh: 'Simplified Chinese', + fr: 'French', + de: 'German', + id: 'Indonesian', + ja: 'Japanese', + ko: 'Korean', + 'pt-BR': 'Brazilian Portuguese', + es: 'Spanish' +}; + +/** + * Creates a translation prompt for technical documentation + */ +function createTranslationPrompt(language: Language): string { + const langName = LANGUAGE_NAMES[language]; + + return `You are a professional technical documentation translator. Translate the following content to ${langName} while following these strict rules: + +1. **Preserve all placeholders**: Do NOT translate or modify any placeholders like __CODE_BLOCK_0__, __INLINE_CODE_1__, __COMPONENT_2__, etc. Keep them exactly as they appear. + +2. **Preserve technical terms**: Keep the following terms in English (do not translate): + - "Dodo Payments" (brand name) + - API endpoint names, URLs, and paths + - Code variable names, function names, class names + - Technical acronyms (API, SDK, SaaS, AI, etc.) + - Framework names (Next.js, React, TypeScript, etc.) + - File extensions (.mdx, .json, .js, etc.) + +3. **Translate user-facing text**: Translate all headings, paragraphs, descriptions, and user-visible text. + +4. **Maintain markdown structure**: Preserve all markdown syntax (##, **, *, etc.) and structure. + +5. **Maintain technical style**: Use appropriate technical terminology in ${langName} that matches the style of professional software documentation. + +6. **Preserve links**: Keep all URLs and href attributes unchanged, but translate link text if it's user-facing. + +7. **Preserve image paths**: Keep all image src paths unchanged, but translate alt text. + +8. **Context awareness**: This is technical documentation for a payment processing platform. Use appropriate business and technical terminology. + +Return ONLY the translated content, maintaining the exact same structure and placeholder positions.`; +} + +/** + * Translates frontmatter fields + */ +async function translateFrontmatter(frontmatter: Record, language: Language): Promise> { + const translated = { ...frontmatter }; + + // Fields that should be translated + const translatableFields = ['title', 'description', 'sidebarTitle']; + + for (const field of translatableFields) { + if (frontmatter[field] && typeof frontmatter[field] === 'string') { + try { + const prompt = createTranslationPrompt(language); + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { role: 'system', content: prompt }, + { role: 'user', content: frontmatter[field] as string } + ], + temperature: 0.3, + max_tokens: 500 + }); + + translated[field] = response.choices[0].message.content?.trim() || frontmatter[field]; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + console.error(chalk.yellow(`Warning: Failed to translate frontmatter field "${field}": ${errorMessage}`)); + // Keep original if translation fails + translated[field] = frontmatter[field]; + } + } + } + + return translated; +} + +/** + * Translates body content + */ +async function translateBody(body: string, language: Language): Promise { + if (!body || body.trim().length === 0) { + return body; + } + + try { + const prompt = createTranslationPrompt(language); + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { role: 'system', content: prompt }, + { role: 'user', content: body } + ], + temperature: 0.3, + max_tokens: 4000 + }); + + return response.choices[0].message.content?.trim() || body; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new Error(`Translation failed: ${errorMessage}`); + } +} + +/** + * Translates component content + */ +async function translateComponentContent(componentContent: ComponentContent, language: Language): Promise { + const translated: ComponentContent = { + text: await translateBody(componentContent.text, language), + codeBlocks: componentContent.codeBlocks, + inlineCodes: componentContent.inlineCodes + }; + + return translated; +} + +/** + * Translates component attributes (like title, alt text, etc.) + */ +async function translateComponentAttributes(attributes: string, language: Language): Promise { + if (!attributes || attributes.trim().length === 0) { + return attributes; + } + + // Extract translatable attributes + const titleMatch = attributes.match(/title="([^"]+)"/); + const altMatch = attributes.match(/alt="([^"]+)"/); + const tipMatch = attributes.match(/tip="([^"]+)"/); + + let translatedAttributes = attributes; + + if (titleMatch) { + const translatedTitle = await translateBody(titleMatch[1], language); + translatedAttributes = translatedAttributes.replace( + /title="[^"]+"/, + `title="${translatedTitle}"` + ); + } + + if (altMatch) { + const translatedAlt = await translateBody(altMatch[1], language); + translatedAttributes = translatedAttributes.replace( + /alt="[^"]+"/, + `alt="${translatedAlt}"` + ); + } + + if (tipMatch) { + const translatedTip = await translateBody(tipMatch[1], language); + translatedAttributes = translatedAttributes.replace( + /tip="[^"]+"/, + `tip="${translatedTip}"` + ); + } + + return translatedAttributes; +} + +/** + * Main translation function + */ +export async function translateContent(parsed: ParsedMDX, language: Language): Promise { + const translated: ParsedMDX = { + frontmatter: await translateFrontmatter(parsed.frontmatter, language), + body: await translateBody(parsed.body, language), + codeBlocks: parsed.codeBlocks, // Preserve as-is + inlineCodes: parsed.inlineCodes, // Preserve as-is + components: [] + }; + + // Translate components + for (const component of parsed.components) { + const translatedComponent: ParsedComponent = { + tag: component.tag, + attributes: await translateComponentAttributes(component.attributes, language), + content: component.selfClosing ? null : await translateComponentContent(component.content!, language), + original: component.original, + selfClosing: component.selfClosing + }; + + translated.components.push(translatedComponent); + } + + return translated; +} + diff --git a/scripts/utils/types.ts b/scripts/utils/types.ts new file mode 100644 index 0000000..28b55cb --- /dev/null +++ b/scripts/utils/types.ts @@ -0,0 +1,40 @@ +export type Language = 'en' | 'zh' | 'fr' | 'de' | 'id' | 'ja' | 'ko' | 'pt-BR' | 'es'; + +export interface ComponentContent { + text: string; + codeBlocks: string[]; + inlineCodes: string[]; +} + +export interface ParsedComponent { + tag: string; + attributes: string; + content: ComponentContent | null; + original: string; + selfClosing: boolean; +} + +export interface ParsedMDX { + frontmatter: Record; + body: string; + codeBlocks: string[]; + inlineCodes: string[]; + components: ParsedComponent[]; +} + +export interface TranslationResult { + success?: boolean; + skipped?: boolean; + error?: boolean; + path: string; + message?: string; +} + +export interface TranslationResults { + success: number; + skipped: number; + errors: number; +} + +export type TranslationCache = Record; + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fbeb7ce --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "lib": ["ES2022"], + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./", + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["scripts/**/*"], + "exclude": ["node_modules", "dist"] +} + diff --git a/zh/development.mdx b/zh/development.mdx new file mode 100644 index 0000000..915513a --- /dev/null +++ b/zh/development.mdx @@ -0,0 +1,190 @@ +--- +title: >- + # 开发 + + + ## 概述 + + + 在本节中,我们将介绍如何使用 Dodo Payments 的 API 来集成支付功能。我们将涵盖从设置到实现的所有步骤。 + + + ## 设置 + + + 要开始使用 Dodo Payments API,您需要首先注册一个开发者账户。请访问 [Dodo Payments + 注册页面](https://example.com/signup) 并按照说明进行操作。 + + + ## API 认证 + + + 所有对 Dodo Payments API 的请求都需要进行认证。您需要在请求头中包含一个有效的 API 密钥。请参阅以下示例代码: + + + ```bash + + curl -X GET "https://api.dodopayments.com/v1/transactions" \ + + -H "Authorization: Bearer YOUR_API_KEY" + + ``` + + + ## 创建支付请求 + + + 要创建一个支付请求,请使用以下 API 端点: + + + ``` + + POST /v1/payments + + ``` + + + 请求体应该包含以下参数: + + + - `amount`: 支付金额 + + - `currency`: 支付货币 + + - `description`: 支付描述 + + + 以下是一个示例请求: + + + ```json + + { + "amount": 100, + "currency": "USD", + "description": "购买商品" + } + + ``` + + + ## 处理响应 + + + 成功的响应将返回一个支付请求的详细信息,包括支付状态和唯一的交易 ID。请参阅以下示例响应: + + + ```json + + { + "id": "txn_123456789", + "status": "pending", + "amount": 100, + "currency": "USD" + } + + ``` + + + ## 错误处理 + + + 如果请求失败,API 将返回一个错误响应。错误响应将包含一个错误代码和描述。请确保在您的代码中处理这些错误。 + + + ## 结论 + + + 通过遵循上述步骤,您可以成功地集成 Dodo Payments + 的支付功能。如果您有任何问题,请参阅我们的[开发者文档](https://example.com/docs)或联系支持团队。 +description: 在本地预览更改以更新您的文档 +--- + +**先决条件**:请在继续之前安装 Node.js(版本 19 或更高)。 + +按照以下步骤在您的操作系统上安装并运行 Mintlify: + +**步骤 1**:安装 Mintlify: + +```bash npm + npm i -g mintlify + ``` + +```bash yarn +yarn global add mintlify +``` + +**步骤 2**:导航到文档目录(`mint.json` 文件所在的位置)并执行以下命令: + +```bash +mintlify dev +``` + +您的文档本地预览将可在 `http://localhost:3000` 访问。 + +### 自定义端口 + +默认情况下,Mintlify 使用端口 3000。您可以通过使用 `--port` 标志自定义 Mintlify 运行的端口。例如,要在端口 3333 上运行 Mintlify,请使用以下命令: + +```bash +mintlify dev --port 3333 +``` + +如果您尝试在已被占用的端口上运行 Mintlify,它将使用下一个可用端口: + +```md +Port 3000 is already in use. Trying 3001 instead. +``` + +## Mintlify 版本 + +请注意,每个 CLI 版本都与特定版本的 Mintlify 相关联。如果您的本地网站与生产版本不一致,请更新 CLI: + +``` +```bash npm +npm i -g mintlify@latest +``` + +```bash yarn +yarn global upgrade mintlify +``` +``` + +## 验证链接 + +CLI 可以帮助验证文档中引用的链接。要识别任何损坏的链接,请使用以下命令: + +```bash +mintlify broken-links +``` + +## 部署 + +在 [Pro 计划](https://mintlify.com/pricing) 及以上版本中可使用无限编辑器。 + +如果部署成功,您应该会看到以下内容: + +```markdown +所有检查通过 +``` + +## 代码格式化 + +我们建议在您的 IDE 上使用扩展来识别和格式化 MDX。如果您是 VSCode 用户,可以考虑使用 [MDX VSCode 扩展](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) 进行语法高亮显示,以及 [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) 进行代码格式化。 + +## 疑难解答 + + + + 这可能是由于 Node 版本过旧导致的。尝试以下步骤: + 1. 移除当前安装的 mintlify 版本:`npm remove -g mintlify` + 2. 升级到 Node v19 或更高版本。 + 3. 重新安装 mintlify:`npm install -g mintlify` + + + + + 解决方案:进入设备的根目录并删除 \~/.mintlify 文件夹。然后,再次运行 `mintlify dev`。 + + +想知道 CLI 版本中有什么变化?[查看 CLI 更新日志。](https://www.npmjs.com/package/mintlify?activeTab=versions) \ No newline at end of file diff --git a/zh/introduction.mdx b/zh/introduction.mdx new file mode 100644 index 0000000..1d322cd --- /dev/null +++ b/zh/introduction.mdx @@ -0,0 +1,335 @@ +--- +title: 欢迎使用 Dodo Payments +description: 为SaaS、AI和数字产品提供完整的支付和计费平台。全球范围内接受支付,设置灵活的计费模型,并在几分钟内实现产品货币化——这一切无需构建您自己的基础设施。 +icon: rocket +--- + +Dodo Payments - 现代数字产品的完整支付和计费平台 + +## 什么是 Dodo Payments? + +Dodo Payments 是一个**一体化引擎**,用于启动、扩展和全球化盈利。专为新一代数字化 SaaS 和 AI 产品设计,我们处理从**支付到账单到分发**的一切——无需额外的工程投入。 + +**为SaaS和AI产品而建**:使用我们优化的计费基础设施处理一次性付款、订阅、积分、席位、代币或任何使用指标。 + +让 Sentra 为您编写集成代码。
+在 VS Code、Cursor 或 Windsurf 中使用我们的 AI 助手,通过描述您的需求来生成 SDK/API 代码、webhooks 等。 + + 试用 Sentra:AI 驱动的集成 → +
+ +### 为什么选择 Dodo Payments? + + + 一种解决方案,涵盖支付、账单和分发——无需再拼凑工具 + + + + 无复杂性地实现全球化:内置覆盖150多个国家,80多种货币和30多种支付方式 + + + + 无缝的API和SDK实现快速集成,此外还有Sentra用于无代码/低代码工作流 + + + + 几分钟内开始收取收入,而不是几周 + + + + 内置基于使用量的订阅附加组件或一次性付款 + + + + 处理积分、席位、令牌或任何使用指标 + + +## 快速入门指南 + +只需几个步骤即可开始使用 Dodo Payments: + + + 使用您的电子邮件在 [app.dodopayments.com](https://app.dodopayments.com/signup) 注册。 + + + 您将收到一封确认邮件以验证您的账户。 + + + + + 选择您的计费模式并添加产品以开始接受付款。 + + + + 适用于数字下载、课程或单次购买 + + + + 理想用于SaaS、会员或定期服务 + + + 为API调用、积分、代币或任何使用指标向客户计费——适用于AI和SaaS + + + + + + 选择最符合您的需求和技术要求的集成方法。 + + + + **快速入门的完美选择:** + + - 从您的仪表板创建 **支付链接** + - 通过电子邮件、社交媒体分享或嵌入网站 + - 立即开始接受付款 + + + + + + + + **最佳无缝、品牌化支付体验:** + + - 在您的网站或应用上以覆盖形式启动结账 + - 保持用户在您的页面上,提供无缝体验 + - 自定义外观以匹配您的品牌 + + + 通过一行代码添加我们的覆盖结账 + + + + + **适合高级、完全自定义解决方案:** + + - 使用我们的TypeScript/Python/Go/Java/Kotlin/C#/Ruby SDK进行无缝集成 + - 程序化访问所有支付、订阅和客户门户API + - 与您的后端、工作流和数据模型深度集成 + - 完全支持webhooks、高级功能和自动化 + + + 让Sentra为您编写集成代码。
+ 使用我们在VS Code、Cursor或Windsurf中的AI助手,通过描述您的需求生成SDK/API代码、webhooks等。 + + 试用Sentra:AI驱动的集成 → + +
+ + + 了解如何安装和使用我们的官方SDK + + + 探索完整的API和SDK文档 + +
+
+
+ +## 开发者集成 + +让 Sentra 为您编写集成代码。
+在 VS Code、Cursor 或 Windsurf 中使用我们的 AI 助手,通过描述您的需求来生成 SDK/API 代码、webhooks 等。 + + 试用 Sentra:AI 驱动的集成 → +
+ +### 框架适配器 + +通过我们的框架适配器在不到 10 行代码中进行集成。选择我们推荐的框架或探索所有支持的选项。 + +#### 推荐框架 + + + 基于React的全栈框架,支持App Router + + + + 具有内置集成的身份验证框架 + + + + 开源的Firebase替代方案,支持Postgres和Auth + + + + 具有实时功能的Backend-as-a-Service + + + + + + + + + + + + + + + +### 强大的 SDK + +使用我们的官方 SDK 加速开发。选择我们推荐的语言或探索所有支持的选项。 + +```markdown + + + + + + + + +``` + +### 账单 SDK + +不再重复造轮子。使用生产就绪的、可访问的账单组件,从定价卡到订阅仪表板,专为 React 和 ShadCN 构建。 + +美观且可定制的计费组件、定价表、订阅管理和使用量计量器 - 使用适用于计费和支付的生产就绪UI节省开发时间。 + +**开源和免费**:BillingSDK 完全免费供个人和商业项目使用和修改。由 Dodo Payments 团队为开发者打造。 + +### Android 和 iOS 的应用内购买 + +使用我们轻量级的支付链接和为 iOS 和 Android 优化的安全 React Native SDK 构建丰富的应用内支付体验。 + + + 完整指南,帮助在移动应用中集成支付 + + + + 适用于iOS和Android的原生移动SDK,提供无缝支付流程 + + + + 使用我们的开源Expo模板快速启动React Native应用内支付 + + +## 外部集成 + +将 Dodo Payments 与您喜爱的工具和平台连接,以自动化工作流程、发送通知并增强您的支付操作。 + +**自动化一切**:使用我们不断增长的集成库设置实时通知、触发工作流、同步客户数据等。 + +### 流行集成 + +快速将 Dodo Payments 连接到最常用的设计和生产力工具,以简化您的工作流程并自动化支付操作。 + + + 为 Framer 网站添加支付功能 + + + + 在 WooCommerce 商店接受支付 + + + + 从 Raycast 管理支付 + + + + 在 Figma 中访问 Dodo Payments + + +```markdown + + 使用团队通信工具中的实时通知,随时了解支付事件。 + + + + 将支付通知和警报发送到 Slack 频道 + + + 在 Discord 服务器中获取即时支付更新 + + + 直接在 Teams 频道中接收支付通知 + + + + + + 同步客户数据并根据支付事件触发电子邮件活动。 + + + + 使用 Resend 发送交易电子邮件 + + + 使用 SendGrid 自动化电子邮件活动 + + + 使用 Loops 触发电子邮件序列 + + + 将客户数据同步到 Customer.io + + + + + + 将您的支付数据与 CRM 平台连接,以简化销售和客户管理。 + + + + 将客户和交易同步到 HubSpot CRM + + + 使用 Close CRM 自动化销售工作流程 + + + + + + 使用工作流程自动化平台构建强大的自动化和数据管道。 + + + + 使用 Zapier 连接到 5,000+ 应用 + + + 使用 Windmill 构建自定义工作流程 + + + 使用 Inngest 创建事件驱动的工作流程 + + + 将支付数据流式传输到 Segment CDP + + + +``` + +探索我们完整的集成库及其详细的设置指南 + +## 需要帮助? + + + 探索全面的指南和API参考 + + + + 完整的OpenAPI参考,包括端点、参数和所有Dodo Payments API的示例请求 + + + + 加入我们的Discord社区以获得帮助和讨论 + + + + 从我们的支持团队获得直接帮助 + \ No newline at end of file diff --git a/zh/migrate-to-dodo.mdx b/zh/migrate-to-dodo.mdx new file mode 100644 index 0000000..ce604ce --- /dev/null +++ b/zh/migrate-to-dodo.mdx @@ -0,0 +1,138 @@ +--- +title: 迁移到 Dodo Payments +description: 轻松使用我们的CLI工具将您的数据从其他支付提供商迁移到Dodo Payments +icon: arrow-right-arrow-left +--- + +**从其他支付提供商切换到 Dodo Payments?** 我们的迁移工具使您可以轻松地迁移**产品、客户和折扣代码而不丢失任何数据。** 该过程安全、有指导,并且只需几分钟即可完成。 + +我们目前支持从 **Lemon Squeezy、Stripe、Polar.sh 和 Paddle** 的迁移。 + +### 支持的迁移 + +```markdown + + 迁移您所有的产品和定价详情。 + + + 转移您完整的客户数据库,包括联系信息。 + + + 无缝移动所有折扣码和促销优惠。 + +``` + +## 开始 + +首先,安装迁移工具: + +```bash +npm install -g dodo-migrate +``` + +您需要在您的计算机上安装 Node.js ≥ 18。 + +## 迁移您的数据 + +### 如果您来自 Lemon Squeezy: + +```bash +dodo-migrate lemonsqueezy +``` + +### 如果您来自 Stripe: + +```bash +dodo-migrate stripe +``` + +### 如果您来自 Polar.sh: + +```bash +dodo-migrate polar +``` + +### 如果您来自 Paddle: + +```bash +dodo-migrate paddle +``` + +该工具将逐步引导您完成所有操作。您需要: +- 您的提供商的 API 密钥(Lemon Squeezy、Stripe、Polar.sh、Paddle 等) +- 您的 Dodo Payments API 密钥 +- 您是否希望先进行测试(推荐)还是直接上线 +- 要迁移到哪个 Dodo Payments 品牌 + +## 为什么使用我们的迁移工具? + +- **无数据丢失** - 所有内容安全转移 +- **先测试** - 在上线前以测试模式尝试 +- **有指导的过程** - 我们引导您完成每一步 +- **需要时可恢复** - 如果出现问题,您可以从中断的地方继续 + +## 高级用法 + +如果您希望在没有提示的情况下运行迁移,可以提前提供所有详细信息: + +### Lemon Squeezy 迁移: + +```bash +dodo-migrate lemonsqueezy \ + --provider-api-key=lsq_XXXXXXXXXXXXXXXX \ + --dodo-api-key=dp_XXXXXXXXXXXXXXXX \ + --mode=test_mode \ + --dodo-brand-id=brand_XXXXXX +``` + +### Stripe 迁移: + +```bash +dodo-migrate stripe \ + --provider-api-key=sk_test_XXXXXXXXXXXXXXXX \ + --dodo-api-key=dp_XXXXXXXXXXXXXXXX \ + --mode=test_mode \ + --dodo-brand-id=brand_XXXXXX \ + --migrate-types=products,coupons +``` + +### Polar.sh 迁移: + +```bash +dodo-migrate polar \ + --provider-api-key=polar_org_XXXXXXXXXXXXXXXX \ + --dodo-api-key=dp_XXXXXXXXXXXXXXXX \ + --mode=test_mode \ + --dodo-brand-id=brand_XXXXXX \ + --migrate-types=products,discounts,customers +``` + +### Paddle 迁移: + +```bash +dodo-migrate paddle \ + --provider-api-key=paddle_XXXXXXXXXXXXXXXX \ + --dodo-api-key=dp_XXXXXXXXXXXXXXXX \ + --mode=test_mode \ + --dodo-brand-id=brand_XXXXXX +``` + +## 需要帮助? + +- **工具帮助**:`dodo-migrate --help` +- **Lemon Squeezy 帮助**:`dodo-migrate lemonsqueezy --help` +- **Stripe 帮助**:`dodo-migrate stripe --help` +- **Polar.sh 帮助**:`dodo-migrate polar --help` +- **Paddle 帮助**:`dodo-migrate paddle --help` +- **社区支持**:[Discord](https://discord.gg/bYqAp4ayYh) +- **报告问题**:[GitHub](https://github.com/dodopayments/dodo-migrate) + +## 更新工具 + +```bash +# Update to latest version +npm update -g dodo-migrate + +# Remove the tool +npm uninstall -g dodo-migrate +``` \ No newline at end of file diff --git a/zh/miscellaneous/taxation.mdx b/zh/miscellaneous/taxation.mdx new file mode 100644 index 0000000..a43133b --- /dev/null +++ b/zh/miscellaneous/taxation.mdx @@ -0,0 +1,119 @@ +--- +title: |- + ## 税务 + + 在使用 Dodo Payments 时,了解税务处理的相关信息是很重要的。以下是一些关键点: + + ### 税务设置 + + 在您的账户中,您可以通过访问 __INLINE_CODE_1__ 页面来配置税务设置。确保所有的税务信息都是最新的,以便正确地处理交易。 + + ### 自动税务计算 + + Dodo Payments 提供自动税务计算功能。这意味着在处理交易时,系统会根据配置的税率自动计算所需的税费。 + + ### 手动税务调整 + + 如果需要手动调整税务,您可以在交易详情页面中进行修改。使用 __INLINE_CODE_2__ 按钮来更新税务信息。 + + ### 常见问题 + + - **如何更新税率?** + + 您可以通过访问 __INLINE_CODE_3__ 页面来更新税率。确保保存更改以应用新的税率。 + + - **Dodo Payments 是否支持国际税务?** + + 是的,Dodo Payments 支持多种国际税务设置。请参考我们的[国际税务指南](https://example.com/international-tax-guide)以获取更多信息。 + + ### 支持 + + 如果您在税务处理方面有任何问题,请联系支持团队。您可以通过 __INLINE_CODE_4__ 页面提交支持请求。我们会尽快协助您解决问题。 +description: 本页面定义了有关税收的政策,并规定了每个地点适用的税率。 +icon: receipt +--- + +## **Dodo Payments 销售税指南** + +### **概述** + +在 Dodo Payments,遵守国际税收法规是我们的首要任务。在许多地区,SaaS 和数字产品交易需要扣除销售税以符合当地法律要求。本指南提供了 Dodo Payments 对不同国家和产品类别(SaaS 和数字产品)适用的销售税率的详细说明。 + +随着新的税收法规生效或我们在某些国家达到门槛限制时,本文件将进行更新。 + +### **为什么销售税是必要的?** + +销售税是许多国家的强制合规要求,尤其是对于数字交易。为了确保合规,Dodo Payments 会根据客户的所在地和所购买产品的类型自动计算适用的销售税。这些扣除帮助商家保持合规,避免潜在的法律问题或罚款。 + +### **重要说明:** + +1. **门槛限制**:在某些国家,只有当 Dodo Payments 超过指定的收入门槛时才适用销售税。对于这些地区,一旦超过此门槛,我们将开始扣除销售税。 + +2. **文件更新**:税率和法规可能会发生变化。本文件将定期修订以反映最新的税收要求。 + +税率将根据交易时适用的最新税率应用。每笔交易发票将清楚地标明适用的税率,商家可以在需要时参考。 + +## Dodo Payments 支持的国家及适用税率列表 + +下表列出了我们接受付款的国家以及这些国家的 SaaS 产品和数字产品的适用销售税率。 + +| 国家 | SaaS 税率 | 数字产品税率 | +| --------------------------- | --------- | ------------ | +| **美国** | NA | NA | +| **英国** | 20% | 20% | +| **德国** | 19% | 19% | +| **法国** | 20% | 20% | +| **意大利** | 22% | 22% | +| **西班牙** | 21% | 21% | +| **荷兰** | 21% | 21% | +| **爱尔兰** | 23% | 23% | +| **澳大利亚** | NA | NA | +| **新西兰** | NA | NA | +| **日本** | NA | NA | +| **印度** | 18% (GST) | 18% (GST) | +| **巴西** | NA | NA | +| **南非** | NA | NA | +| **瑞士** | NA | NA | +| **挪威** | 25% | 25% | +| **瑞典** | 25% | 25% | +| **丹麦** | 25% | 25% | +| **芬兰** | 24% | 24% | +| **比利时** | 21% | 21% | +| **奥地利** | 20% | 20% | +| **波兰** | 23% | 23% | +| **捷克共和国** | 21% | 21% | +| **匈牙利** | 27% | 27% | +| **罗马尼亚** | 19% | 19% | +| **中国** | NA | NA | +| **新加坡** | NA | NA | +| **马来西亚** | NA | NA | +| **泰国** | NA | NA | +| **印度尼西亚** | 10% | 10% | +| **阿联酋** | 5% | 5% | +| **克罗地亚** | 25% | 25% | +| **爱沙尼亚** | 22% | 22% | +| **希腊** | 24% | 24% | +| **冰岛** | 24% | 24% | +| **拉脱维亚** | 21% | 21% | +| **立陶宛** | 21% | 21% | +| **卢森堡** | 17% | 17% | +| **波斯尼亚和黑塞哥维那** | 17% | 17% | +| **塞尔维亚** | 20% | 20% | +| **摩尔多瓦** | 20% | 20% | +| **黑山** | 21% | 21% | + +*** + +### **国家列表** + +目前我们不接受来自上述列表之外国家的付款。随着我们添加更多国家到我们的名册中,我们将不断更新此列表。 + +### **基于门槛的销售税** + +对于某些国家,Dodo Payments 只有在达到特定销售门槛后才会开始扣除销售税。目前,销售税列为 **NA** 的国家属于此类。一旦这些国家的收入超过指定门槛,Dodo Payments 将开始扣除适用的税率。 + +*** + +### **税款汇缴** + +通过 Dodo Payments 收取的所有税款将根据每个国家的当地税收法规进行报告和汇缴。这种自动化的税务处理确保商家无需自己处理国际税法的复杂性即可保持合规。我们每年将通过电子邮件发送一份汇总各司法管辖区汇缴税款的报告,以确保完全透明。 \ No newline at end of file diff --git a/zh/miscellaneous/test-mode-vs-live-mode.mdx b/zh/miscellaneous/test-mode-vs-live-mode.mdx new file mode 100644 index 0000000..59c98a7 --- /dev/null +++ b/zh/miscellaneous/test-mode-vs-live-mode.mdx @@ -0,0 +1,81 @@ +--- +title: 测试模式与实时模式 +description: 了解测试模式和实时模式之间的区别以及如何在它们之间切换。 +icon: toggle-on +--- + +找到测试模式与实时模式下可用功能的详细对比 + +## 功能对比 + +| **功能** | **测试模式** | **实时模式** | **是否依赖环境?** | +| ------------------------------------------- | ------------ | ------------ | -------------------- | +| **创建产品(一次性/订阅)** | ✓ | ✓ | 是 | +| **生成支付链接** | ✓ | ✓ | 是 | +| **模拟支付(卡、钱包等)** | ✓ | x | 是 | +| **处理真实支付** | x | ✓ | 是 | +| **发起退款** | ✓(模拟) | ✓(真实) | 是 | +| **访问交易历史** | ✓(模拟) | ✓(真实) | 是 | +| **下载发票** | ✓(模拟) | ✓(真实) | 是 | +| **关联银行账户** | ✓ | ✓ | 不依赖环境 | +| **银行账户提现** | x | ✓ | 是 | +| **模拟失败交易** | ✓ | x | 是 | +| **分析部分** | ✓(模拟) | ✓(真实) | 是 | +| **查看详细报告** | ✓(模拟) | ✓(真实) | 是 | +| **自定义发票模板** | ✓ | ✓ | 不依赖环境 | +| **API 密钥生成** | ✓ | ✓ | 是 | +| **实时欺诈检测** | x | ✓ | 是 | +| **访问实时客户支持** | ✓ | ✓ | 不依赖环境 | +| **创建 Webhook** | ✓ | ✓ | 是 | +| **业务资料部分** | ✓ | ✓ | 不依赖环境 | +| **我的账户部分** | ✓ | ✓ | 不依赖环境 | +| **创建多个业务** | ✓ | ✓ | 不依赖环境 | +| **提现合规** | ✓ | ✓ | 不依赖环境 | +| **交易邮件** | x | ✓ | 是 | + +### 环境依赖性 + +**依赖环境:** 所有依赖环境的功能将在测试模式和实时模式中拥有独立的数据。在一个环境中所做的任何更改都不会影响另一个环境。例如,在测试模式下生成的 API 密钥将独立于实时模式生成的 API 密钥,反之亦然。 + +**不依赖环境:** 所有不依赖环境的功能将在实时模式和测试模式中拥有相同的数据。例如,“我的账户”部分在测试模式和实时模式中将拥有相同的数据。在一个环境中所做的更改将影响另一个环境。 + +实时模式仅在身份验证和业务验证成功完成后可用。您只能在 \`live mode\` 中接受真实支付。 + +测试模式和实时模式的 API 主机名如下: +- 测试模式:[`https://test.dodopayments.com`](https://test.dodopayments.com/) +- 实时模式:[`https://live.dodopayments.com`](https://live.dodopayments.com/) + +## 关键亮点 + +1. 在测试模式或实时模式下创建的所有产品仅在各自的环境中可用。在测试模式环境中有一个复制到实时模式的选项。这将复制产品的所有相关详细信息并在实时模式中创建相同的产品。 + +2. 在测试模式下创建的 API 密钥和 Webhooks 仅限于测试模式环境,不会影响实时模式的部署,反之亦然。 + +3. 提交的所有验证文件和银行账户详细信息在测试模式和实时模式中将是相同的。在任何环境中对此信息的更改也将在另一个环境中更改。 + +## 测试卡和 UPI ID + +有关测试卡、UPI ID 和其他测试方法的详细信息,请参阅我们的综合[测试流程](/miscellaneous/testing-process)指南。 + +本指南包括: +- 不同场景的测试卡号 +- 模拟支付的测试 UPI ID +- 测试各种支付结果的说明 +- 测试集成的最佳实践 + +测试支付方式仅在测试模式下有效。切勿将其用于真实支付。 + +## 测试模式下的交易 - 教程 + +请观看此视频,了解如何在测试模式下执行交易。 + +```html + +``` \ No newline at end of file diff --git a/zh/miscellaneous/testing-process.mdx b/zh/miscellaneous/testing-process.mdx new file mode 100644 index 0000000..ae0c273 --- /dev/null +++ b/zh/miscellaneous/testing-process.mdx @@ -0,0 +1,154 @@ +--- +title: >- + ## 测试流程 + + + 在本节中,我们将介绍如何测试您的集成以确保与 Dodo Payments 的无缝连接。 + + + ### 1. 创建测试账户 + + + 在开始测试之前,您需要创建一个 Dodo Payments 测试账户。请访问 [Dodo Payments + 测试账户注册](https://example.com) 页面并按照说明进行操作。 + + + ### 2. 配置测试环境 + + + 确保您的应用程序配置为使用测试环境。您需要更新以下配置文件: + + + - `config.json` 文件中的 `environment` 设置为 `test` + + - 确保使用测试 API 密钥 + + + ### 3. 执行测试交易 + + + 使用以下步骤执行测试交易: + + + 1. 导航到您的应用程序的支付页面。 + + 2. 输入测试信用卡信息: + - 卡号:`4111 1111 1111 1111` + - 有效期:`12/34` + - CVV:`123` + 3. 提交交易并验证响应。 + + + ### 4. 验证交易状态 + + + 使用 Dodo Payments 提供的 __API_ENDPOINT_0__ 检查交易状态。确保交易状态与预期结果一致。 + + + ### 5. 处理错误 + + + 在测试过程中,您可能会遇到错误。请参考以下常见错误代码及其解决方案: + + + - **错误代码 1001**: 无效的卡号。请检查输入的卡号。 + + - **错误代码 1002**: 余额不足。请使用不同的测试卡号。 + + + ### 6. 查看日志 + + + 检查您的应用程序日志以获取更多详细信息。日志文件通常位于 `/var/log/app.log`。 + + + ### 7. 完成测试 + + + 一旦所有测试通过,您可以将配置更改为生产环境并开始处理真实交易。 + + + 通过遵循这些步骤,您可以确保您的应用程序与 Dodo Payments 的集成是正确的,并且能够处理各种交易场景。 +description: 了解如何测试您的 Dodo Payments 集成 +icon: vial +--- + +```html + +``` + +## 测试卡信息 + +Dodo Payments 提供了一组测试卡号,您可以用来模拟各种支付场景。您可以使用这些测试卡号在测试模式下创建模拟支付,而无需处理实际支付或扣款。 + +测试卡号仅在测试模式下有效。请勿将其用于真实支付。 + +### 成功支付(美国) + +| **卡号** | **有效期 (MM/YY)** | **CVV/CVC** | +| ---------------- | ------------------ | ----------- | +| 4242424242424242 | 06/32 | 123 | + +### 成功支付(印度) + +| **卡号** | **有效期 (MM/YY)** | **CVV/CVC** | +| ---------------- | ------------------ | ----------- | +| 6074825972083818 | 06/32 | 123 | + +### 拒绝支付(美国) + +| **卡号** | **有效期 (MM/YY)** | **CVV/CVC** | +| ---------------- | ------------------ | ----------- | +| 4000000000000002 | 06/32 | 123 | + +### 拒绝支付(印度) + +| **卡号** | **有效期 (MM/YY)** | **CVV/CVC** | +| ---------------- | ------------------ | ----------- | +| 4000000000000127 | 06/32 | 123 | + +有关不同场景的各种测试卡的完整信息,请访问以下链接: + +[https://docs.stripe.com/testing#cards](https://docs.stripe.com/testing#cards) + +## 测试 UPI 信息 +[了解什么是 UPI。](/features/upi) + +| **状态** | **UPI ID** | +|------------------| --------------| +| 成功 | success@upi | +| 失败 | failure@upi | + +## 测试 Klarna 信息 + +| **状态** | **出生日期** | **名字** | **姓氏** | **电子邮件** | **街道** | **门牌号** | **城市** | **州** | **邮政编码** | **电话** | +|----------|----------------|----------|----------|----------------------------|----------------|----------------|------------|-----------|----------------|-------------------| +| 批准 | 07-10-1970 | Test | Person-us| customer@email.us | Amsterdam Ave | 509 | New York | New York | 10024-3941 | +13106683312 | +| 拒绝 | 07-10-1970 | Test | Person-us| customer+denied@email.us | Amsterdam Ave | 509 | New York | New York | 10024-3941 | +13106354386 | + +**注意**:Klarna 交易的最低金额要求为 $50。 + +## 测试 Afterpay 信息 + +在测试您的结账集成时,选择 Afterpay 作为支付方式并点击支付按钮。 + +### 成功支付 +- 使用任何有效的电子邮件地址和送货地址进行成功支付。 + +### 认证失败 +- 要测试用户认证失败的情况,请使用您的测试 API 密钥并查看重定向页面。在重定向页面上,关闭 Afterpay 模态窗口并验证支付失败。PaymentIntent 从 `requires_action` 转变为 `requires_payment_method`。 + +**注意**:Afterpay 交易的最低金额要求为 $50。 + +对于在测试模式下手动捕获的 PaymentIntents,未捕获的 PaymentIntent 在成功授权后 10 分钟内自动过期。 + +## 其他支付方式 + +要测试其他支付方式,如 Amazon Pay 和 Cash App,请遵循常规测试程序。请注意,Apple Pay 和 Google Pay 在测试模式下无法使用。 \ No newline at end of file diff --git a/zh/miscellaneous/user-access-and-management.mdx b/zh/miscellaneous/user-access-and-management.mdx new file mode 100644 index 0000000..debdec8 --- /dev/null +++ b/zh/miscellaneous/user-access-and-management.mdx @@ -0,0 +1,180 @@ +--- +title: 用户访问和管理 +description: Dodo Payments 的用户和访问管理功能使商家能够通过邀请团队成员、分配角色和控制权限来高效管理其账户的访问。 +icon: user-gear +--- + +## 主要亮点 + +商户可以邀请团队成员并分配角色,以高效管理业务运营。 + +允许商家为团队成员分配特定角色,确保他们在业务中拥有与其职责相符的适当权限。 + +## 我的账户部分指南 + +### 步骤 1:管理员登录到 Dodo Payments 仪表板 + +要访问用户和访问管理功能,账户管理员必须首先登录到他们的 Dodo Payments 账户。 + +- **如何登录**: + 1. 访问 **登录页面**。 + 2. 输入您的电子邮件地址和密码。 + 3. 完成任何额外的安全步骤,例如双因素认证(如果启用)。 + +### 步骤 2:导航到用户和访问管理部分 + +登录后,管理员可以访问 **用户和访问管理** 部分,在那里他们可以查看所有现有团队成员并管理他们的角色和权限。 + +- **如何访问**: + 1. 在仪表板中,点击 **设置**。 + 2. 从菜单中选择 **用户和访问管理**。 + +### 步骤 3:创建新团队成员 + +要添加新团队成员,管理员必须输入有关团队成员的基本信息,例如他们的 **姓名** 和 **电子邮件地址**。 + +- **如何添加团队成员**: + 1. 在用户和访问管理部分点击 **添加团队成员**。 + 2. 填写团队成员的姓名和电子邮件。 + 3. 点击 **下一步** 继续。 + +### 步骤 4:分配角色和权限 + +输入团队成员的详细信息后,管理员可以为其分配特定角色。Dodo Payments 提供预定义角色以及根据商户需求创建自定义角色的能力。 + +- **如何分配角色**: + 1. 从下拉菜单中选择一个预定义角色,或选择 **自定义角色**。 + 2. 对于自定义角色,通过勾选或取消勾选不同的访问点来指定权限。 + 3. 点击 **保存** 以分配角色。 + +### 步骤 5:发送邀请给团队成员 + +一旦设置了角色和权限,管理员可以向新团队成员发送邀请。这封电子邮件将包含设置他们账户和登录平台的说明。 + +- **如何发送邀请**: + 1. 分配角色后,点击 **发送邀请**。 + 2. 团队成员将收到一封电子邮件,其中包含创建登录凭证的链接。 + +### 步骤 6:团队成员接受邀请 + +被邀请的团队成员将收到一封主题为 **“您已被邀请加入 Dodo Payments”** 的电子邮件。他们将按照说明设置密码并完成账户设置。 + +- **团队成员需要做什么**: + 1. 打开邀请邮件并点击 **接受邀请** 按钮。 + 2. 创建密码并登录到 Dodo Payments 仪表板。 + 3. 根据他们的角色,团队成员将仅能访问他们被分配的部分。 + +### 步骤 7:管理和监控团队成员 + +团队成员加入后,管理员可以继续管理他们的访问权限。这包括编辑他们的角色、查看他们的活动以及在必要时移除他们。 + +- **如何管理团队成员**: + 1. 在 **用户和访问管理** 部分,点击团队成员的姓名以查看或编辑他们的权限。 + 2. 要移除团队成员,点击 **移除用户** 或 **停用** 以暂时撤销他们的访问权限。 + +## 角色 + +- **所有者** +- **编辑者** +- **查看者** + +## 基于角色的访问矩阵 + +| 功能 | 操作 | 所有者 | 编辑者 | 查看者 | +| --- | --- | --- | --- | --- | +| 入门 | | 是 | 是 | 否 | +| 主页 | | 是 | 是 | 是 | +| 交易 | | | | | +| | 支付查看 | 是 | 是 | 是 | +| | 关联发票下载 | 是 | 是 | 否 | +| | 退款查看 | 是 | 是 | 是 | +| | 退款发起 | 是 | 是 | 否 | +| | 争议 | 是 | 是 | 是 | +| 产品目录 | | | | | +| | 查看目录 | 是 | 是 | 是 | +| | 添加、编辑或删除产品/订阅 | 是 | 是 | 否 | +| 发票 | | | | | +| | 查看发票 | 是 | 是 | 是 | +| | 下载发票 | 是 | 是 | 否 | +| 支付 | | | | | +| | 查看报告 | 是 | 是 | 是 | +| | 下载报告 | 是 | 是 | 否 | +| 报告(销售、支付、退款) | | | | | +| | 查看报告 | 是 | 是 | 是 | +| | 下载报告 | 是 | 是 | 否 | +| 客户 | | | | | +| | 查看详情 | 是 | 是 | 是 | +| | 下载详情 | 是 | 是 | 否 | +| 设置 | | | | | +| | 激活 | 是 | 是 | 否 | +| | 支付 | 是 | 是 | 否 | +| | 合规 | 是 | 是 | 否 | +| 开发者文档 | | 是 | 是 | 是 | +| 实时模式/测试模式 | | 是 | 是 | 是 | \ No newline at end of file diff --git a/zh/miscellaneous/verification-process.mdx b/zh/miscellaneous/verification-process.mdx new file mode 100644 index 0000000..89a57c6 --- /dev/null +++ b/zh/miscellaneous/verification-process.mdx @@ -0,0 +1,338 @@ +--- +title: >- + ## 验证流程 + + + 在使用 Dodo Payments API 之前,您需要完成以下验证步骤以确保您的账户安全并符合合规要求。 + + + ### 1. 提交申请 + + + 首先,您需要提交一个申请以开始使用 Dodo Payments + 的服务。请访问我们的[申请页面](https://www.dodopayments.com/apply)以获取更多信息。 + + + ### 2. 提交必要文件 + + + 在您的申请获得初步批准后,您将需要提交一些必要的文件。这些文件包括但不限于: + + + - **公司注册证明** + + - **税务登记证明** + + - **法人身份证明** + + + ### 3. API 密钥生成 + + + 一旦您的文件被验证通过,您将收到一组 API 密钥。这些密钥将用于在您的应用程序中进行 API 调用。请妥善保管这些密钥,并不要与未经授权的人员分享。 + + + ### 4. 测试环境 + + + 在生产环境中使用 API 之前,建议您在测试环境中进行全面测试。您可以通过以下步骤来设置测试环境: + + + 1. 克隆我们的示例项目: + ```bash + git clone https://github.com/dodopayments/sample-project.git + ``` + 2. 安装依赖项: + ```bash + npm install + ``` + 3. 配置测试 API 密钥: + 在 __CODE_BLOCK_0__ 文件中设置您的测试 API 密钥。 + + ### 5. 生产环境 + + + 经过充分测试后,您可以将应用程序部署到生产环境。请确保在 __INLINE_CODE_1__ 中使用生产 API 密钥。 + + + ### 支持 + + + 如果您在验证过程中遇到任何问题,请随时通过 + [support@dodopayments.com](mailto:support@dodopayments.com) + 联系我们的支持团队。我们会尽快协助您解决问题。 +description: 了解如何成功完成入驻验证流程,包括身份、业务和银行验证步骤,以确保合规并加快审批速度。 +icon: id-card +--- + +在 Dodo Payments,我们要求所有企业完成彻底的验证流程,以确保符合监管标准和平台政策。此流程涵盖**身份验证**、**企业验证**以及对**反洗钱**和**产品类别**合规性的严格检查。 + +有关支持和禁止的产品类别以及受限和接受的商业地点的最新和全面的详细信息,请参阅我们的[商户接受政策](/miscellaneous/merchant-acceptance)。 + +## 验证表单 + +具体表单取决于您的账户类型: + +| 账户类型 | 所需表单 | +| --- | --- | +| **个人** | KYC + 银行表单 | +| **注册企业** | KYC + KYB + 银行表单 | + +如果您是**英国注册企业**,您还必须提交[税务表格 W-8BEN-E](#4-additional-compliance)作为验证过程的一部分。 + +### 1. 身份验证 + +我们使用**Persona**,一家领先的全球验证提供商,遵循行业标准的安全措施和全球数据隐私指南。 + +KYC通过以下方式确保个人企业的真实性: + +- **政府签发的身份证件验证**(护照、国家身份证、驾照等) +- **自拍检查**以确认活体并与身份证件匹配 + +Persona的AI驱动流程在几分钟内完成验证,同时保持银行级安全标准。 + +有关Persona安全措施的更多信息,请访问[withpersona.com/security](https://withpersona.com/security)。 + +**相机访问问题:** 如果在身份验证过程中遇到“无法访问您的相机”错误,您需要为设备和浏览器启用相机权限。步骤因浏览器和设备而异: + +- **Chrome:** 通过浏览器设置启用相机权限(桌面、iPhone & iPad 或 Android) +- **Safari:** 对于桌面,通过 Safari 偏好设置启用。对于移动设备,前往 设置 → Safari → 相机,将权限设置为“询问”或“允许” +- **iOS 应用:** 前往 设置 → 应用 → [您的应用] → 允许相机权限。同时确保锁定模式没有阻止应用 +- **Android 应用:** 前往 设置 → 应用 → [您的应用] → 允许相机权限 + +有关特定浏览器和设备的详细分步故障排除说明,请参阅 [Persona 的相机访问指南](https://help.withpersona.com/articles/3V9VoOoGLp6zRCwthpzpx4/)。 + +### 2. 银行表单 + +银行表单收集您的**银行账户详情**和**联系信息**。 + +**⚠️ 重要提示:** + +- 银行账户详情**必须与**已验证的身份或注册企业名称匹配。 +- 对于个人,账户持有人的姓名应与身份验证文件匹配。 +- 对于注册企业,应与企业验证中的公司法定名称匹配。 +- Dodo Payments无法处理与账户不匹配或第三方账户的付款。 + +### 3. 企业验证 + +企业验证仅对注册企业是必需的。如果您拥有个人账户,可以跳过此部分。 + +对于注册企业,验证确保公司的合法性及其授权代表的合法性。 + +#### 所需详情 + + +提供您的**公司注册号**和支持文件(根据您的司法管辖区,提供公司注册证书或类似文件)。 + + + +如果您希望在付款发票上反映您的税号以申请税收优惠,请提供有效的税号和文件。 + +各地区税号示例:EIN, CRN, VAT ID, GSTIN + + + +在验证表单中提供公司所有董事或最终受益所有人的详细信息。 + +**最终受益所有人** + +最终受益所有人是指任何自然人,无论是单独行动还是共同行动,或通过其他公司、有限责任合伙企业或法人,拥有或有权获得关联用户10%或以上的股份、资本或利润,或通过其他方式对关联用户行使控制权,包括享有任命其大多数董事的权利或通过股权或管理权利或通过股东协议或投票协议来控制其管理或政策决策。如果关联用户有超过1名最终受益所有人,请向我们提供所有人的必要文件。 + +**业务董事** + +根据您当地法律,任命并目前在关联用户董事会中任职的个人。请向我们提供所有董事的政府颁发的身份证明。 + + +### 4. 额外合规 + +W-8BEN-E:仅适用于英国注册企业。如果您的公司位于英国,请确保填写此表格。 + +来自英国的注册企业需要填写**W-8BEN-E**表格以符合国际税务报告法规。这确保了顺利的付款处理和税务文件的准确性。 + +```markdown + + 下载英国注册企业所需的官方 IRS W-8BEN-E 表格 (PDF)。
+ + 提示: 为获得最佳效果,请在打印和签署之前以数字方式填写表格。 + +
+```
+ +#### 什么是W-8 BEN-E表格? + +W-8 BEN-E表格是外国企业必须提交的美国国税局(IRS)表格,用于验证其税务目的的居住国家,证明其符合较低的税收预扣率。 + +#### 如何填写W-8 BEN-E表格 + + +**1. 实益拥有者的组织名称** + +这是您的实体名称。 + +**2. 注册或组织国家** + +这是居住国家(公司注册所在国家)。对于公司而言,这是注册国家。如果您是其他类型的实体,请输入您根据其法律创建、组织或管理的国家。 + +**3. 第三章状态** + +在此部分中,最常勾选的选项是“Corporation”。大多数从事业务的外国实体属于“Corporation”或“Partnership”状态。其他选项包括: + +- 外国政府 – 控制实体 +- 外国政府 – 整体部分 +- 遗产 +- 简单信托(包括授予者和复杂信托) +- 发行中央银行 +- 免税组织 +- 私人基金会 +- 国际组织 +- 被忽略的实体 + +对于私人有限公司 - 勾选 Corporation 框 +对于有限责任合伙 - 勾选 Partnership 框 + +**4. 第四章状态(FATCA 状态)** + +对于 SaaS/数字产品,这里最常见的选择是 Active NFFE。这意味着该业务是一个活跃的非金融外国实体。如果其他类别都不适合,Active NFFE 是最佳选择。 + +**5. 永久居住地址** + +这是您企业的永久居住地址。您的永久居住地址是您声称为该国所得税居民的国家的地址。 + +**8-10. 税务识别信息** + +您可以在第9b行提供您税务居住地辖区颁发的 FTIN,以申请条约优惠。 + + + +在表格的这一部分,您只需勾选第39项以证明: + +- 第一部分中的实体是一个非银行或金融机构的外国实体。 +- 上一日历年的总收入中被动收入少于50%。 +- 持有的资产中,用于产生或持有以产生被动收入的资产少于50%(按季度被动资产百分比的加权平均计算)。 + + + +文件中最重要的部分是认证和签名。在这里,需要书写名字、姓氏和日期(表格签署日期)。签署 W-8BEN-E 表格的人必须被授权代表实益拥有者签署。 + + +#### 查看W-8 BEN-E表格样本 + + + +**示例资料:** +- 公司:ABC Technologies PVT LTD +- 类型:SaaS / 数字产品 +- 国家:印度(示例) +- TIN:PAN或您所在国家的等效税号 + + +**第1页** + + + W-8 BEN-E 私人有限公司示例第1页 + + +**第2页** + + + W-8 BEN-E 私人有限公司示例第2页 + + +**第8页** + + + W-8 BEN-E 私人有限公司示例第8页 + + + + + +**示例资料:** +- 公司:ABC Technologies LLP +- 类型:SaaS / 数字产品 +- 国家:印度(示例) +- TIN:PAN或您所在国家的等效税号 + + +**第1页** + + + W-8 BEN-E LLP示例第1页 + + +**第2页** + + + W-8 BEN-E LLP示例第2页 + + +**第8页** + + + W-8 BEN-E LLP示例第8页 + + + +## 额外信息请求 + +作为我们**持续监控**的一部分,我们的合规团队可能会不时请求额外信息。 + +这些请求可以直接从仪表板完成,**不会阻止付款或支付**,但未能提交可能会触发付款/支付处理暂停、进一步的合规审查或账户限制。 + +有关更多详细信息,请参阅我们的[评论监控政策](/miscellaneous/review-monitoring-policy)。 + +## 时间表与支持 + +- 典型验证时间:**1-3个工作日(不包括周末和公共假期)** +- 如果需要额外审查,您将通过电子邮件和仪表板收到通知。 +- 如需帮助,请联系[support@dodopayments.com](mailto:support@dodopayments.com) + +## 文件重新提交 + +如果在入职过程中提交的文件存在问题,Dodo Payments验证团队可能会要求您重新提交特定文件。 + +您可以使用仪表板中的**重新提交**选项重新提交文件。 + +### 何时可以重新提交文件? + +- **信息缺失或不完整**:如果缺少必要的详细信息,如身份证号码、企业名称或其他关键数据。 +- **文件不匹配**:当提交的文件与提供的企业或个人信息不匹配时。 +- **文件不可读或已过期**:如果上传的文件不清晰、难以辨认或已过期。 +- **需要额外说明**:如果验证团队需要进一步的文件来澄清您的身份或企业信息。 + +### 如何重新提交文件 + + +检查您的 Dodo Payments 仪表板是否有重新提交请求(如果需要重新提交,您也会收到电子邮件通知)。 + + + +验证团队将启用**重新提交**选项,允许您上传新文件。 + + + +导航到仪表板中的**验证部分**,并上传正确的文件。 + + + +点击**提交审核**按钮提交文件以供审核。 + + + + 查看我们全面的接受标准,包括支持和禁止的产品,确保您的业务符合入驻资格。 + + + 了解如何监控持续的合规性,学习触发文件审核的条件,并主动维护您的账户状态。 + \ No newline at end of file diff --git a/zh/quickstart.mdx b/zh/quickstart.mdx new file mode 100644 index 0000000..c4617ab --- /dev/null +++ b/zh/quickstart.mdx @@ -0,0 +1,9 @@ +--- +title: 快速入门 +description: 在本节中,我们将引导您完成开始使用我们Web应用程序的初始步骤。在深入了解具体内容之前,请确保您满足系统要求并已准备好一切。 +icon: bolt +--- + +```markdown +快速入门封面图 +``` \ No newline at end of file diff --git a/zh/snippets/snippet-intro.mdx b/zh/snippets/snippet-intro.mdx new file mode 100644 index 0000000..c6741e6 --- /dev/null +++ b/zh/snippets/snippet-intro.mdx @@ -0,0 +1,3 @@ + + +软件开发的核心原则之一是 DRY(Don't Repeat Yourself)。这一原则同样适用于文档编写。如果您发现自己在多个地方重复相同的内容,您应该考虑创建一个自定义代码片段以保持内容同步。 \ No newline at end of file diff --git a/zh/welcome.mdx b/zh/welcome.mdx new file mode 100644 index 0000000..93d9039 --- /dev/null +++ b/zh/welcome.mdx @@ -0,0 +1,32 @@ +--- +title: 欢迎 +description: 欢迎使用 Dodo Payments 文档。这是一份指南,帮助您理解和浏览 Dodo Payments 仪表板。 +icon: globe +mode: custom +--- + +
```markdown +

快速增长企业的支付基础设施

+

Dodo Payments 处理全球支付收款、合规、税务和风险管理,让您专注于发展业务。

+```
+ +
+ + 在10分钟内开始使用 Dodo Payments。 + + + 探索我们的集成指南、教程等内容! + + + 探索 Dodo Payments 的 API。 + + + 将 Dodo Payments 连接到您喜爱的平台和工具。 + + + 了解我们推出的所有最新功能和改进。 + + + 了解 Dodo 的定价、交易费用和收入分成。 + +
\ No newline at end of file