diff --git a/.changeset/all-ghosts-worry.md b/.changeset/all-ghosts-worry.md
new file mode 100644
index 000000000..06c8008d5
--- /dev/null
+++ b/.changeset/all-ghosts-worry.md
@@ -0,0 +1,11 @@
+---
+"arkenv": patch
+---
+
+Export `ArkEnvError`
+
+You can now import `ArkEnvError` from `arkenv`:
+
+```ts
+import { ArkEnvError } from "arkenv";
+```
diff --git a/.changeset/some-bikes-film.md b/.changeset/some-bikes-film.md
new file mode 100644
index 000000000..9e0c9dac2
--- /dev/null
+++ b/.changeset/some-bikes-film.md
@@ -0,0 +1,8 @@
+---
+"arkenv": patch
+---
+
+Improve JSDoc
+
+The JSDoc for `arkenv` and `createEnv` is now more descriptive.
+
diff --git a/apps/playgrounds/node/index.ts b/apps/playgrounds/node/index.ts
index 9ff1723a5..8f3581ffa 100644
--- a/apps/playgrounds/node/index.ts
+++ b/apps/playgrounds/node/index.ts
@@ -1,9 +1,9 @@
import arkenv from "arkenv";
const env = arkenv({
+ NODE_ENV: "'development' | 'production' | 'test' = 'development'",
HOST: "string.host",
PORT: "number.port",
- NODE_ENV: "'development' | 'production' | 'test' = 'development'",
});
// Automatically validate and parse process.env
diff --git a/apps/www/app/docs/[[...slug]]/page.tsx b/apps/www/app/docs/[[...slug]]/page.tsx
index ac9cbac32..4faca04a1 100644
--- a/apps/www/app/docs/[[...slug]]/page.tsx
+++ b/apps/www/app/docs/[[...slug]]/page.tsx
@@ -1,3 +1,4 @@
+import * as Twoslash from "fumadocs-twoslash/ui";
import { Accordion, Accordions } from "fumadocs-ui/components/accordion";
import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock";
import { Step, Steps } from "fumadocs-ui/components/steps";
@@ -55,6 +56,7 @@ export default async function Page(props: {
{props.children}
),
+ ...Twoslash,
}}
/>
diff --git a/apps/www/app/globals.css b/apps/www/app/globals.css
index f02b4e4df..96ad85d05 100644
--- a/apps/www/app/globals.css
+++ b/apps/www/app/globals.css
@@ -6,6 +6,7 @@
@import "./styles/theme/inline.css";
@import "./styles/components/github-alerts.css";
@import "./styles/base.css";
+@import "fumadocs-twoslash/twoslash.css";
@plugin "tailwindcss-animate";
@source '../node_modules/fumadocs-ui/dist/**/*.js';
diff --git a/apps/www/app/layout.tsx b/apps/www/app/layout.tsx
index ca60a5dc9..d6cc863b4 100644
--- a/apps/www/app/layout.tsx
+++ b/apps/www/app/layout.tsx
@@ -32,6 +32,7 @@ export default function Layout({ children }: { children: ReactNode }) {
lang="en"
className={`${inter.className} ${jetbrainsMono.variable}`}
suppressHydrationWarning
+ data-scroll-behavior="smooth"
>
-
\ No newline at end of file
+
diff --git a/apps/www/content/docs/guides/environment-configuration.mdx b/apps/www/content/docs/guides/environment-configuration.mdx
index 997e30af6..b2065fa5d 100644
--- a/apps/www/content/docs/guides/environment-configuration.mdx
+++ b/apps/www/content/docs/guides/environment-configuration.mdx
@@ -3,9 +3,9 @@ title: Loading environment variables
description: Learn how to manage environment variables across different environments and deployment scenarios
---
-## Local Development
+## Local development
-### Using `.env` Files
+### Using `.env` files
The most common way to manage environment variables during development is using `.env` files:
@@ -17,9 +17,9 @@ API_KEY=your-secret-key
LOG_LEVEL=debug
```
-### Best Practices for `.env` Files
+### Best practices for `.env` files
-1. **Document Required Variables**
+1. **Document required variables**
Create a `.env.example` file to document required variables:
```dotenv title=".env.example"
DATABASE_HOST=localhost
@@ -29,7 +29,7 @@ LOG_LEVEL=debug
LOG_LEVEL=info
```
-2. **Gitignore Configuration**
+2. **Gitignore configuration**
Add these patterns to your `.gitignore`:
```dotenv title=".gitignore"
.env
@@ -37,7 +37,7 @@ LOG_LEVEL=debug
!.env.example
```
-3. **Environment-Specific Files**
+3. **Environment-specific files**
Use different files for different environments:
- `.env.development` - Development settings
- `.env.test` - Test environment settings
@@ -56,7 +56,7 @@ import * as dotenv from 'dotenv';
dotenv.config();
```
-### Framework-Specific Solutions
+### Framework-specific solutions
Many frameworks have built-in support for environment variables:
@@ -92,7 +92,7 @@ import { ConfigModule } from '@nestjs/config';
})
```
-### Runtime Arguments
+### Runtime arguments
You can also supply variables when running your application:
@@ -100,9 +100,9 @@ You can also supply variables when running your application:
DATABASE_HOST=localhost DATABASE_PORT=5432 npm start
```
-## Production Deployment
+## Production deployment
-### Cloud Platforms
+### Cloud platforms
#### AWS
- Use AWS Systems Manager Parameter Store for non-sensitive values
@@ -117,7 +117,7 @@ DATABASE_HOST=localhost DATABASE_PORT=5432 npm start
- Use Azure Key Vault for sensitive values
- Configure App Settings in Azure App Service
-### Container Environments
+### Container environments
#### Docker
@@ -148,13 +148,13 @@ spec:
key: database-host
```
-### Traditional Hosting
+### Traditional hosting
- Set environment variables through the hosting platform's dashboard
- Use deployment scripts to configure environment variables
- Consider using configuration management tools
-## Security Best Practices
+## Security best practices
1. **Never commit sensitive values**
- Keep `.env` files out of version control
@@ -164,7 +164,7 @@ spec:
- Don't share sensitive credentials between environments
- Use environment-specific configurations
-3. **Access Control**
+3. **Access control**
- Limit access to production environment variables
- Use role-based access control for secrets management
@@ -172,11 +172,11 @@ spec:
- Encrypt sensitive values at rest
- Use secure channels for transmitting secrets
-## Validation and Typesafety
+## Validation and typesafety
ArkEnv helps ensure your environment variables are valid:
-```typescript title="src/config/env.ts"
+```typescript title="src/config/env.ts" twoslash
import arkenv from 'arkenv';
export const env = arkenv({
@@ -188,27 +188,17 @@ export const env = arkenv({
LOG_LEVEL: "'debug' | 'info' | 'warn' | 'error' = 'info'",
// Optional variables
- "FEATURE_FLAGS?": 'string[]',
-
- // Custom validation
- API_URL: (value: string) => {
- try {
- new URL(value);
- return true;
- } catch {
- return false;
- }
- }
+ "FEATURE_FLAGS?": 'string[]'
});
```
-## Common Patterns
+## Common patterns
-### Configuration Factory
+### Configuration factory
Create a configuration factory to handle different environments:
-```typescript title="src/config/index.ts"
+```typescript title="src/config/index.ts" twoslash
import arkenv from 'arkenv';
const createConfig = () => {
@@ -230,35 +220,35 @@ const createConfig = () => {
export const config = createConfig();
```
-### Feature Flags
+### Feature flags
Use environment variables for feature flags:
-```typescript title="src/config/features.ts"
+```typescript title="src/config/features.ts" twoslash
import arkenv from 'arkenv';
export const env = arkenv({
- "ENABLE_BETA_FEATURES?": 'boolean = false',
- "MAINTENANCE_MODE?": 'boolean = false',
- "ALLOWED_ORIGINS?": 'string[] = []'
+ "ENABLE_BETA_FEATURES": 'boolean = false',
+ "MAINTENANCE_MODE": 'boolean = false',
+ "ALLOWED_ORIGINS": 'string[]'
});
```
## Troubleshooting
-### Common Issues
+### Common issues
-1. **Missing Variables**
+1. **Missing variables**
- Check if `.env` file exists
- Verify variable names match exactly
- Ensure variables are loaded before use
-2. **Type Errors**
+2. **Type errors**
- Verify variable types match schema
- Check for typos in variable names
- Ensure all required variables are provided
-3. **Loading Order**
+3. **Loading order**
- Load environment variables before importing config
- Consider using a bootstrap file
- Check framework-specific loading behavior
diff --git a/apps/www/content/docs/guides/type-function.mdx b/apps/www/content/docs/guides/type-function.mdx
deleted file mode 100644
index b90ff2e1f..000000000
--- a/apps/www/content/docs/guides/type-function.mdx
+++ /dev/null
@@ -1,273 +0,0 @@
----
-title: "type function"
-description: "Learn about ArkEnv's advanced type function for runtime validation with built-in environment-specific types."
----
-
-> [!NOTE]
-> **For most use cases, you should use the default `arkenv` export (which uses `createEnv` under the hood).** The `type` function is useful when you want to separate schema definition from validation.
-
-> [!TIP]
-> **New to ArkEnv?** Start with the [Quickstart guide](/docs/quickstart) to learn the basics with the default `arkenv` export. This guide is for when you need to separate schema definition from validation.
-
-ArkEnv exposes a `type` function that extends ArkType's type system with environment-specific validations. This function is useful when you want to define your schema in one place and validate environment variables at a different time or location.
-
-## Basic Usage
-
-```ts
-import { type } from "arkenv";
-
-const env = type({
- NODE_ENV: "string",
- HOST: "string.host",
- PORT: "number.port",
-});
-
-// Validate and transform environment variables
-const result = env.assert({
- NODE_ENV: "development",
- HOST: "localhost",
- PORT: "3000", // String input, number output
-});
-
-console.log(result);
-// { NODE_ENV: "development", HOST: "localhost", PORT: 3000 }
-```
-
-## Separation of Schema Definition and Validation
-
-The main benefit of the `type` function is that you can define your schema in one place and validate environment variables elsewhere:
-
-```ts
-// config/env-schema.ts
-import { type } from "arkenv";
-
-export const envSchema = type({
- NODE_ENV: "string",
- HOST: "string.host",
- PORT: "number.port",
- API_KEY: "string?",
-});
-```
-
-```ts
-// config/env.ts
-import { envSchema } from "./env-schema";
-
-// Validate environment variables using the schema
-export const env = envSchema.assert(process.env);
-```
-
-```ts
-// vite.config.ts
-import { defineConfig } from "vite";
-import arkenv from "@arkenv/vite-plugin";
-import { envSchema } from "./config/env-schema";
-
-export default defineConfig({
- plugins: [arkenv(envSchema)],
-});
-```
-
-This approach allows you to:
-- **Reuse the same schema** across different parts of your application
-- **Define schema once** and validate in multiple places
-- **Keep configuration modular** and organized
-
-## Built-in Environment Types
-
-### `string.host`
-
-Validates hostnames and IP addresses:
-
-```ts
-const env = type({
- API_HOST: "string.host",
- DB_HOST: "string.host",
-});
-
-// Valid inputs
-env.assert({ API_HOST: "localhost" });
-env.assert({ API_HOST: "127.0.0.1" });
-env.assert({ API_HOST: "api.example.com" });
-
-// Invalid inputs
-env.assert({ API_HOST: "invalid-host" }); // ❌ Throws error
-```
-
-### `number.port`
-
-Validates and converts port numbers:
-
-```ts
-const env = type({
- PORT: "number.port",
- API_PORT: "number.port",
-});
-
-// Valid inputs (strings from environment variables)
-const result = env.assert({ PORT: "3000" });
-console.log(result.PORT); // 3000 (number)
-
-// Valid port range: 1-65535
-env.assert({ PORT: "8080" }); // ✅ Valid
-env.assert({ PORT: "65535" }); // ✅ Valid
-
-// Invalid inputs
-env.assert({ PORT: "0" }); // ❌ Too low
-env.assert({ PORT: "65536" }); // ❌ Too high
-env.assert({ PORT: "invalid" }); // ❌ Not a number
-```
-
-## Advanced Usage
-
-### Optional Fields
-
-```ts
-const env = type({
- REQUIRED: "string",
- OPTIONAL: "string?",
- PORT: "number.port?",
-});
-
-// Works with all fields
-env.assert({
- REQUIRED: "value",
- OPTIONAL: "optional",
- PORT: "3000",
-});
-
-// Works with only required fields
-env.assert({
- REQUIRED: "value",
- // OPTIONAL and PORT are omitted
-});
-```
-
-### Nested Objects
-
-```ts
-const env = type({
- DATABASE: {
- HOST: "string.host",
- PORT: "number.port",
- NAME: "string",
- },
- API: {
- HOST: "string.host",
- PORT: "number.port",
- },
-});
-
-const result = env.assert({
- DATABASE: {
- HOST: "localhost",
- PORT: "5432",
- NAME: "myapp",
- },
- API: {
- HOST: "api.example.com",
- PORT: "443",
- },
-});
-```
-
-### Arrays
-
-```ts
-const env = type({
- ALLOWED_ORIGINS: "string[]",
- PORTS: "number[]",
-});
-
-const result = env.assert({
- ALLOWED_ORIGINS: ["localhost", "127.0.0.1"],
- PORTS: [3000, 8080, 9000],
-});
-```
-
-## Error Handling
-
-The `type` function provides detailed error messages for validation failures:
-
-```ts
-const env = type({
- HOST: "string.host",
- PORT: "number.port",
-});
-
-try {
- env.assert({
- HOST: "invalid-host",
- PORT: "99999",
- });
-} catch (error) {
- console.error(error.message);
- // HOST must be a valid hostname or IP address (was "invalid-host")
- // PORT must be a valid port number (was "99999")
-}
-```
-
-## When to Use `type` vs `arkenv` (default export)
-
-> [!IMPORTANT]
-> **Most users should use the default `arkenv` export for environment variables.** Only use `type` when you need to separate schema definition from validation.
-
-| Feature | `type` | `arkenv` (default) |
-|---------|--------|-------------------|
-| **Primary Use Case** | Schema definition separate from validation | Environment variable handling with immediate validation |
-| **Input** | Any object (usually environment variables) | `process.env` or custom object |
-| **Output** | Validated object | Parsed environment variables |
-| **When to Use** | When you want to define schema in one file and validate in another | Environment variables (most common) |
-| **Recommended for** | Advanced users, modular architecture | **Most users** |
-
-```ts
-// ✅ RECOMMENDED: Using arkenv for immediate validation
-import arkenv from "arkenv";
-
-const env = arkenv({
- HOST: "string.host",
- PORT: "number.port",
-});
-
-// ✅ ADVANCED: Using type to separate schema definition from validation
-import { type } from "arkenv";
-
-// Define schema in one file
-const envSchema = type({
- HOST: "string.host",
- PORT: "number.port",
-});
-
-// Validate in another file or at a later time
-const validated = envSchema.assert(process.env);
-```
-
-### Common Use Cases for `type`:
-
-- **Modular Architecture**: Define schema in a shared config file, validate in different modules
-- **Delayed Validation**: Define schema early but validate environment variables later in your application lifecycle
-- **Schema Reuse**: Use the same schema definition for different validation scenarios
-- **Testing**: Define schema once and use it for testing different environment configurations
-
-## Integration with Vite
-
-The `type` function works seamlessly with the Vite plugin:
-
-```ts
-// vite.config.ts
-import { defineConfig } from "vite";
-import arkenv from "@arkenv/vite-plugin";
-import { type } from "arkenv";
-
-const envSchema = type({
- VITE_API_URL: "string",
- VITE_HOST: "string.host",
- VITE_PORT: "number.port",
-});
-
-export default defineConfig({
- plugins: [arkenv(envSchema)],
-});
-```
-
-This ensures your environment variables are validated at build time with the same type definitions you use for runtime validation.
diff --git a/apps/www/content/docs/integrations/import-guide.mdx b/apps/www/content/docs/integrations/import-guide.mdx
index c149f9104..6ae4a71ba 100644
--- a/apps/www/content/docs/integrations/import-guide.mdx
+++ b/apps/www/content/docs/integrations/import-guide.mdx
@@ -4,7 +4,7 @@ title: How to import ArkEnv to enable syntax highlighting
To integrate ArkEnv, use the **default import** and name it `arkenv`:
-```typescript
+```ts twoslash
import arkenv from 'arkenv';
const env = arkenv({
diff --git a/apps/www/content/docs/quickstart.mdx b/apps/www/content/docs/quickstart.mdx
index 34308eaa7..2c8084e76 100644
--- a/apps/www/content/docs/quickstart.mdx
+++ b/apps/www/content/docs/quickstart.mdx
@@ -34,7 +34,7 @@ description: Let's get you started with a few simple steps
Add a schema to make your environment variables **validated** and **typesafe**:
- ```typescript title="config/env.ts"
+ ```ts title="config/env.ts" twoslash
import arkenv from 'arkenv';
export const env = arkenv({
@@ -98,7 +98,18 @@ description: Let's get you started with a few simple steps
Import and use your **validated** and **typed** environment variables. For example, you might have a file like `database.ts`:
- ```typescript title="database.ts"
+ ```typescript title="database.ts" twoslash
+ // @filename: config/env.ts
+ import arkenv from 'arkenv';
+ export const env = arkenv({
+ DATABASE_HOST: "string.host",
+ DATABASE_PORT: "number.port",
+ NODE_ENV: "'development' | 'production' | 'test'",
+ LOG_LEVEL: "'debug' | 'info' | 'warn' | 'error' = 'info'",
+ "API_KEY?": 'string'
+ });
+ // @filename: database.ts
+ // ---cut---
import { env } from './config/env';
// TypeScript knows the ✨exact✨ types!
diff --git a/apps/www/middleware.ts b/apps/www/middleware.ts
index a6809c629..63ec4e893 100644
--- a/apps/www/middleware.ts
+++ b/apps/www/middleware.ts
@@ -15,5 +15,5 @@ export function middleware(_request: NextRequest) {
}
export const config = {
- matcher: "/:path*",
+ matcher: "/((?!monitoring).*)",
};
diff --git a/apps/www/next.config.ts b/apps/www/next.config.ts
index ac293012b..0ace5ed77 100644
--- a/apps/www/next.config.ts
+++ b/apps/www/next.config.ts
@@ -1,52 +1,56 @@
import path from "node:path";
-import { withSentryConfig } from "@sentry/nextjs";
+import { type SentryBuildOptions, withSentryConfig } from "@sentry/nextjs";
import { createMDX } from "fumadocs-mdx/next";
+import type { NextConfig } from "next";
-export default withSentryConfig(
- createMDX()({
- reactStrictMode: true,
- outputFileTracingRoot: path.join(__dirname, "../../"),
- }),
- {
- // For all available options, see:
- // https://github.com/getsentry/sentry-webpack-plugin#options
+const config = {
+ reactStrictMode: true,
+ cleanDistDir: true,
+ outputFileTracingRoot: path.join(__dirname, "../../"),
+ serverExternalPackages: ["typescript", "twoslash", "ts-morph"],
+} as const satisfies NextConfig;
- org: process.env.SENTRY_ORG,
- project: process.env.SENTRY_PROJECT,
+const sentryConfig = {
+ // For all available options, see:
+ // https://github.com/getsentry/sentry-webpack-plugin#options
- // Only print logs for uploading source maps in CI
- silent: !process.env.CI,
+ org: process.env.SENTRY_ORG,
+ project: process.env.SENTRY_PROJECT,
- // For all available options, see:
- // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
+ // Only print logs for uploading source maps in CI
+ silent: !process.env.CI,
- // Upload a larger set of source maps for prettier stack traces (increases build time)
- widenClientFileUpload: true,
+ // For all available options, see:
+ // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
- // Automatically annotate React components to show their full name in breadcrumbs and session replay
- reactComponentAnnotation: {
- enabled: true,
- },
+ // Upload a larger set of source maps for prettier stack traces (increases build time)
+ widenClientFileUpload: true,
- // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
- // This can increase your server load as well as your hosting bill.
- // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
- // side errors will fail.
- tunnelRoute: "/monitoring",
+ // Automatically annotate React components to show their full name in breadcrumbs and session replay
+ reactComponentAnnotation: {
+ enabled: true,
+ },
- // Automatically tree-shake Sentry logger statements to reduce bundle size
- disableLogger: true,
+ // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
+ // This can increase your server load as well as your hosting bill.
+ // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
+ // side errors will fail.
+ tunnelRoute: "/monitoring",
- // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
- // See the following for more information:
- // https://docs.sentry.io/product/crons/
- // https://vercel.com/docs/cron-jobs
- automaticVercelMonitors: true,
+ // Automatically tree-shake Sentry logger statements to reduce bundle size
+ disableLogger: true,
- sourcemaps: {
- deleteSourcemapsAfterUpload: true,
- },
+ // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
+ // See the following for more information:
+ // https://docs.sentry.io/product/crons/
+ // https://vercel.com/docs/cron-jobs
+ automaticVercelMonitors: true,
- authToken: process.env.SENTRY_AUTH_TOKEN,
+ sourcemaps: {
+ deleteSourcemapsAfterUpload: true,
},
-);
+
+ authToken: process.env.SENTRY_AUTH_TOKEN,
+} as const satisfies SentryBuildOptions;
+
+export default withSentryConfig(createMDX()(config), sentryConfig);
diff --git a/apps/www/package.json b/apps/www/package.json
index 6918a6fd6..ef6079486 100644
--- a/apps/www/package.json
+++ b/apps/www/package.json
@@ -11,26 +11,34 @@
"fix": "pnpm -w run fix"
},
"dependencies": {
+ "@ark/util": "^0.49.0",
+ "@fumadocs/mdx-remote": "^1.4.0",
"@icons-pack/react-simple-icons": "^13.7.0",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-toast": "^1.2.15",
"@sentry/nextjs": "^10.10.0",
"@stackblitz/sdk": "^1.11.0",
+ "arkdark": "^5.4.2",
+ "arkenv": "workspace:*",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fumadocs-core": "15.7.10",
"fumadocs-mdx": "11.9.0",
+ "fumadocs-twoslash": "^3.1.7",
"fumadocs-ui": "15.7.10",
+ "import-in-the-middle": "^1.14.2",
"lucide-react": "^0.542.0",
"next": "15.5.2",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"rehype-github-alerts": "^4.1.1",
"remark-gemoji": "^8.0.0",
+ "require-in-the-middle": "^7.5.2",
+ "shiki": "^3.12.2",
"tailwind-merge": "^3.3.1",
- "@ark/util": "^0.49.0",
- "tailwindcss-animate": "^1.0.7"
+ "tailwindcss-animate": "^1.0.7",
+ "twoslash": "^0.3.4"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.13",
diff --git a/apps/www/source.config.ts b/apps/www/source.config.ts
index e078b3b9d..8825667f9 100644
--- a/apps/www/source.config.ts
+++ b/apps/www/source.config.ts
@@ -1,8 +1,28 @@
-import { remarkNpm } from "fumadocs-core/mdx-plugins";
+import { createRequire } from "node:module";
+import { rehypeCodeDefaultOptions, remarkNpm } from "fumadocs-core/mdx-plugins";
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
+import {
+ type TransformerTwoslashOptions,
+ transformerTwoslash,
+} from "fumadocs-twoslash";
+import { createFileSystemTypesCache } from "fumadocs-twoslash/cache-fs";
import { rehypeGithubAlerts } from "rehype-github-alerts";
import remarkGemoji from "remark-gemoji";
+const require = createRequire(import.meta.url);
+
+/**
+ * Next.js apparently strips away the "with { type: 'json' }" option, so we need to use the `require` function to import the package.json file.
+ *
+ *
+ * If it weren't for this issue, we'd be able to use:
+ *
+ * ```ts
+ * import arkTypePackageJson from "arkdark/package.json" with { type: "json" };
+ * ```
+ */
+const arkTypePackageJson = require("arkdark/package.json");
+
export const docs = defineDocs({
dir: "content/docs",
docs: {
@@ -10,9 +30,150 @@ export const docs = defineDocs({
},
});
+/** biome-ignore-start lint/style/useTemplate: Copied from ArkType */
+/**
+ * Twoslash property prefix {@link https://github.com/arktypeio/arktype/blob/ff7db8b61004f8de82089a22f4cb4ab5938c2a97/ark/docs/lib/shiki.ts#L37 | ripped from ArkType}
+ */
+const twoslashPropertyPrefix = "(property) ";
+/**
+ * Twoslash options {@link https://github.com/arktypeio/arktype/blob/ff7db8b61004f8de82089a22f4cb4ab5938c2a97/ark/docs/lib/shiki.ts#L38 | ripped from ArkType}
+ */
+const arktypeTwoslashOptions = {
+ explicitTrigger: false,
+ langs: ["ts", "js"],
+ twoslashOptions: {
+ compilerOptions: {
+ // avoid ... in certain longer types on hover
+ noErrorTruncation: true,
+ },
+ extraFiles: {
+ "global.d.ts": `import type * as a from "arktype"
+
+declare global {
+ const type: typeof a.type
+ namespace type {
+ export type cast = {
+ [a.inferred]?: t
+ }
+
+ export type errors = a.ArkErrors
+
+ export type validate> = a.validateDefinition<
+ def,
+ $,
+ args
+ >
+
+ export type instantiate> = type<
+ a.inferDefinition,
+ $
+ >
+
+ export type infer> = a.inferDefinition<
+ def,
+ $,
+ args
+ >
+
+ /** @ts-ignore cast variance */
+ export interface Any extends a.BaseType {}
+ }
+
+ type type = a.Type
+ const scope: typeof a.scope
+ const match: typeof a.match
+}`,
+ },
+ filterNode: (node) => {
+ switch (node.type) {
+ case "hover":
+ if (node.text.endsWith(", {}>"))
+ // omit default scope param from type display
+ node.text = node.text.slice(0, -5) + ">";
+ if (node.text.startsWith("type")) return true;
+
+ // when `noErrorTruncation` is enabled, TS displays the type
+ // of an anonymous cyclic type as `any` instead of using
+ // `...`, so replace it to clarify the type is accurately inferred
+ node.text = node.text.replaceAll(" any", " ...");
+ if (node.text.startsWith("const")) {
+ // show type with completions populated for known examples
+ node.text = node.text.replace(
+ "version?: undefined",
+ "version?: number | string",
+ );
+ node.text = node.text.replace(
+ "versions?: undefined",
+ "versions?: (number | string)[]",
+ );
+ // filter out the type of Type's invocation
+ // as opposed to the Type itself
+ return !node.text.includes("(data: unknown)");
+ }
+ if (node.text.startsWith(twoslashPropertyPrefix)) {
+ const expression = node.text.slice(twoslashPropertyPrefix.length);
+ if (expression.startsWith("RuntimeErrors.summary") && node.docs) {
+ // this shows error summary in JSDoc
+ // re-add spaces stripped out during processing
+ node.docs = node.docs.replaceAll("•", " •");
+ return true;
+ }
+ if (expression === `platform: "android" | "ios"`) {
+ // this helps demonstrate narrowing on discrimination
+ return true;
+ }
+ return false;
+ }
+ return false;
+ case "error":
+ // adapted from my ErrorLens implementation at
+ // https://github.com/usernamehw/vscode-error-lens/blob/d1786ddeedee23d70f5f75b16415a6579b554b59/src/utils/extUtils.ts#L127
+ for (const transformation of arkTypePackageJson.contributes
+ .configurationDefaults["errorLens.replace"]) {
+ const regex = new RegExp(transformation.matcher);
+ const matchResult = regex.exec(node.text);
+ if (matchResult) {
+ node.text = transformation.message;
+ // Replace groups like $0 and $1 with groups from the match
+ for (
+ let groupIndex = 0;
+ groupIndex < matchResult.length;
+ groupIndex++
+ ) {
+ node.text = node.text.replaceAll(
+ new RegExp(`\\$${groupIndex}`, "gu"),
+ matchResult[Number(groupIndex)],
+ );
+ }
+ node.text = `TypeScript: ${node.text}`;
+ }
+ }
+ return true;
+ default:
+ return true;
+ }
+ },
+ },
+} satisfies TransformerTwoslashOptions;
+/** biome-ignore-end lint/style/useTemplate: Copied from ArkType */
+
export default defineConfig({
mdxOptions: {
rehypePlugins: [rehypeGithubAlerts],
remarkPlugins: [remarkGemoji, remarkNpm],
+ rehypeCodeOptions: {
+ themes: {
+ light: "github-light",
+ dark: "github-dark",
+ },
+ transformers: [
+ ...(rehypeCodeDefaultOptions.transformers ?? []),
+ transformerTwoslash({
+ ...arktypeTwoslashOptions,
+ typesCache: createFileSystemTypesCache(),
+ explicitTrigger: true,
+ }),
+ ],
+ },
},
});
diff --git a/packages/arkenv/README.md b/packages/arkenv/README.md
index c229e1e38..b7881e62e 100644
--- a/packages/arkenv/README.md
+++ b/packages/arkenv/README.md
@@ -29,7 +29,7 @@
ArkEnv is an environment variable parser powered by [ArkType](https://arktype.io/), TypeScript's 1:1 validator. ArkEnv lets you use familiar TypeScript-like syntax to create a ready to use, typesafe environment variable object:
-```ts
+```ts twoslash
import arkenv from 'arkenv';
const env = arkenv({
diff --git a/packages/arkenv/src/create-env.ts b/packages/arkenv/src/create-env.ts
index 4bc729960..431962967 100644
--- a/packages/arkenv/src/create-env.ts
+++ b/packages/arkenv/src/create-env.ts
@@ -11,7 +11,7 @@ export type EnvSchema = type.validate;
* @param def - The environment variable schema
* @param env - The environment variables to validate, defaults to `process.env`
* @returns The validated environment variable schema
- * @throws An error if the environment variables are invalid. See {@link ArkEnvError}
+ * @throws An {@link ArkEnvError | error} if the environment variables are invalid.
*/
export function createEnv>(
def: EnvSchema,
diff --git a/packages/arkenv/src/index.ts b/packages/arkenv/src/index.ts
index 437c32c60..5aae01874 100644
--- a/packages/arkenv/src/index.ts
+++ b/packages/arkenv/src/index.ts
@@ -2,7 +2,13 @@ export type { EnvSchema } from "./create-env";
import { createEnv } from "./create-env";
+/**
+ * `arkenv`'s main export, an alias for {@link createEnv}
+ *
+ * {@link https://arkenv.js.org | ArkEnv} is a typesafe environment variables parser powered by {@link https://arktype.io | ArkType}, TypeScript's 1:1 validator.
+ */
const arkenv = createEnv;
export default arkenv;
export { type } from "./type";
export { createEnv };
+export { ArkEnvError } from "./errors";
diff --git a/packages/vite-plugin/src/index.test.ts b/packages/vite-plugin/src/index.test.ts
index c42cd1864..4a8f324b2 100644
--- a/packages/vite-plugin/src/index.test.ts
+++ b/packages/vite-plugin/src/index.test.ts
@@ -18,7 +18,9 @@ const ORIGINAL_ENV = { ...process.env };
const fixturesDir = join(__dirname, "__fixtures__");
// Get the mocked functions
-const { createEnv: mockCreateEnv } = await vi.importMock("arkenv");
+const { createEnv: mockCreateEnv } = (await vi.importMock("arkenv")) as {
+ createEnv: ReturnType;
+};
// Run fixture-based tests
for (const name of readdirSync(fixturesDir)) {
@@ -98,9 +100,25 @@ describe("Plugin Unit Tests", () => {
it("should call createEnv during config hook", () => {
const pluginInstance = arkenvPlugin({ VITE_TEST: "string" });
- // Mock the config hook
- if (pluginInstance.config) {
- pluginInstance.config({}, { mode: "test", command: "build" });
+ // Mock the config hook with proper context
+ if (pluginInstance.config && typeof pluginInstance.config === "function") {
+ const mockContext = {
+ meta: {
+ framework: "vite",
+ version: "1.0.0",
+ rollupVersion: "4.0.0",
+ viteVersion: "5.0.0",
+ },
+ error: vi.fn(),
+ warn: vi.fn(),
+ info: vi.fn(),
+ debug: vi.fn(),
+ } as any;
+ pluginInstance.config.call(
+ mockContext,
+ {},
+ { mode: "test", command: "build" },
+ );
}
expect(mockCreateEnv).toHaveBeenCalledWith(
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f66097bbc..ce398cf0a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -100,6 +100,9 @@ importers:
'@ark/util':
specifier: ^0.49.0
version: 0.49.0
+ '@fumadocs/mdx-remote':
+ specifier: ^1.4.0
+ version: 1.4.0(@types/react@19.1.12)(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)
'@icons-pack/react-simple-icons':
specifier: ^13.7.0
version: 13.7.0(react@19.1.1)
@@ -118,6 +121,12 @@ importers:
'@stackblitz/sdk':
specifier: ^1.11.0
version: 1.11.0
+ arkdark:
+ specifier: ^5.4.2
+ version: 5.4.2
+ arkenv:
+ specifier: workspace:*
+ version: link:../../packages/arkenv
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -129,10 +138,16 @@ importers:
version: 15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
fumadocs-mdx:
specifier: 11.9.0
- version: 11.9.0(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5))
+ version: 11.9.0(@fumadocs/mdx-remote@1.4.0(@types/react@19.1.12)(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1))(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5))
+ fumadocs-twoslash:
+ specifier: ^3.1.7
+ version: 3.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(fumadocs-ui@15.7.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
fumadocs-ui:
specifier: 15.7.10
version: 15.7.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13)
+ import-in-the-middle:
+ specifier: ^1.14.2
+ version: 1.14.2
lucide-react:
specifier: ^0.542.0
version: 0.542.0(react@19.1.1)
@@ -151,12 +166,21 @@ importers:
remark-gemoji:
specifier: ^8.0.0
version: 8.0.0
+ require-in-the-middle:
+ specifier: ^7.5.2
+ version: 7.5.2
+ shiki:
+ specifier: ^3.12.2
+ version: 3.12.2
tailwind-merge:
specifier: ^3.3.1
version: 3.3.1
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@4.1.13)
+ twoslash:
+ specifier: ^0.3.4
+ version: 0.3.4(typescript@5.9.2)
devDependencies:
'@tailwindcss/postcss':
specifier: ^4.1.13
@@ -723,6 +747,16 @@ packages:
'@formatjs/intl-localematcher@0.6.1':
resolution: {integrity: sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==}
+ '@fumadocs/mdx-remote@1.4.0':
+ resolution: {integrity: sha512-0aECFvjlpCMeDopjXKBndP/7FbzchNOJu0m3qPsKFtZl+/1QvGsrKPYVVnIY5lwvHL7+E9wGhl6MUHrvcqvWCw==}
+ peerDependencies:
+ '@types/react': '*'
+ fumadocs-core: ^14.0.0 || ^15.0.0
+ react: 18.x.x || 19.x.x
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -1951,6 +1985,11 @@ packages:
'@shikijs/transformers@3.12.2':
resolution: {integrity: sha512-+z1aMq4N5RoNGY8i7qnTYmG2MBYzFmwkm/yOd6cjEI7OVzcldVvzQCfxU1YbIVgsyB0xHVc2jFe1JhgoXyUoSQ==}
+ '@shikijs/twoslash@3.12.2':
+ resolution: {integrity: sha512-JthKvEvyE/gbu3u693mhNhEO6GYP1vetrwgEfqTAsT/G9AJ6nf7g7JVqdTSs+axdfilGWzZKeYdjfyanu/v5AA==}
+ peerDependencies:
+ typescript: '>=5.5.0'
+
'@shikijs/types@3.12.2':
resolution: {integrity: sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q==}
@@ -2199,6 +2238,11 @@ packages:
resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript/vfs@1.6.1':
+ resolution: {integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==}
+ peerDependencies:
+ typescript: '*'
+
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
@@ -2367,6 +2411,10 @@ packages:
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'}
+ arkdark@5.4.2:
+ resolution: {integrity: sha512-AMk8Jmrgo4X9TJtjwIa7K1zQqHh1OBzSU129IhB5jetFh6mMAhqT0QqyYQshB+4XEvtDeNjtfry+1XiXAoLYNg==}
+ engines: {vscode: ^1.0.0}
+
arktype@2.1.22:
resolution: {integrity: sha512-xdzl6WcAhrdahvRRnXaNwsipCgHuNoLobRqhiP8RjnfL9Gp947abGlo68GAIyLtxbD+MLzNyH2YR4kEqioMmYQ==}
@@ -2772,6 +2820,10 @@ packages:
resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==}
engines: {node: '>=12.0.0'}
+ extend-shallow@2.0.1:
+ resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
+ engines: {node: '>=0.10.0'}
+
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@@ -2913,6 +2965,16 @@ packages:
vite:
optional: true
+ fumadocs-twoslash@3.1.7:
+ resolution: {integrity: sha512-RHO1K6Sh8O8eS9TCQRv9C3ek/TZuUrUqMNtoKBx7D/D5L6OB3Skol+PTltHDzyIrmrHVRkO20tBlqyRxD3awUA==}
+ peerDependencies:
+ '@types/react': '*'
+ fumadocs-ui: ^15.0.0
+ react: 18.x.x || 19.x.x
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
fumadocs-ui@15.7.10:
resolution: {integrity: sha512-yGSCuRwFSiHFbVperUzSM+8aP7LbOzI3HoiX1ORDPI1DsuUE1nCyxHjnKsczZImhjEwOqJPf/gywZHAbiPTJkA==}
peerDependencies:
@@ -2991,6 +3053,10 @@ packages:
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ gray-matter@4.0.3:
+ resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
+ engines: {node: '>=6.0'}
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -3106,6 +3172,10 @@ packages:
is-decimal@2.0.1:
resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
+ is-extendable@0.1.1:
+ resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
+ engines: {node: '>=0.10.0'}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -3219,6 +3289,10 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+
levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
@@ -4023,6 +4097,10 @@ packages:
scroll-into-view-if-needed@3.1.0:
resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
+ section-matter@1.0.0:
+ resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
+ engines: {node: '>=4'}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -4125,6 +4203,10 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
+ strip-bom-string@1.0.0:
+ resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
+ engines: {node: '>=0.10.0'}
+
strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -4360,6 +4442,14 @@ packages:
resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==}
hasBin: true
+ twoslash-protocol@0.3.4:
+ resolution: {integrity: sha512-HHd7lzZNLUvjPzG/IE6js502gEzLC1x7HaO1up/f72d8G8ScWAs9Yfa97igelQRDl5h9tGcdFsRp+lNVre1EeQ==}
+
+ twoslash@0.3.4:
+ resolution: {integrity: sha512-RtJURJlGRxrkJmTcZMjpr7jdYly1rfgpujJr1sBM9ch7SKVht/SjFk23IOAyvwT1NLCk+SJiMrvW4rIAUM2Wug==}
+ peerDependencies:
+ typescript: ^5.5.0
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -5201,6 +5291,18 @@ snapshots:
dependencies:
tslib: 2.8.1
+ '@fumadocs/mdx-remote@1.4.0(@types/react@19.1.12)(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)':
+ dependencies:
+ '@mdx-js/mdx': 3.1.1
+ fumadocs-core: 15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ gray-matter: 4.0.3
+ react: 19.1.1
+ zod: 4.1.5
+ optionalDependencies:
+ '@types/react': 19.1.12
+ transitivePeerDependencies:
+ - supports-color
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -6466,6 +6568,15 @@ snapshots:
'@shikijs/core': 3.12.2
'@shikijs/types': 3.12.2
+ '@shikijs/twoslash@3.12.2(typescript@5.9.2)':
+ dependencies:
+ '@shikijs/core': 3.12.2
+ '@shikijs/types': 3.12.2
+ twoslash: 0.3.4(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
'@shikijs/types@3.12.2':
dependencies:
'@shikijs/vscode-textmate': 10.0.2
@@ -6749,6 +6860,13 @@ snapshots:
'@typescript-eslint/types': 8.43.0
eslint-visitor-keys: 4.2.1
+ '@typescript/vfs@1.6.1(typescript@5.9.2)':
+ dependencies:
+ debug: 4.4.1
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
'@ungap/structured-clone@1.3.0': {}
'@vitejs/plugin-react@5.0.2(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5))':
@@ -6955,6 +7073,8 @@ snapshots:
dependencies:
tslib: 2.8.1
+ arkdark@5.4.2: {}
+
arktype@2.1.22:
dependencies:
'@ark/schema': 0.49.0
@@ -7376,6 +7496,10 @@ snapshots:
expect-type@1.2.2: {}
+ extend-shallow@2.0.1:
+ dependencies:
+ is-extendable: 0.1.1
+
extend@3.0.2: {}
extendable-error@0.1.7: {}
@@ -7491,7 +7615,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- fumadocs-mdx@11.9.0(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5)):
+ fumadocs-mdx@11.9.0(@fumadocs/mdx-remote@1.4.0(@types/react@19.1.12)(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1))(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5)):
dependencies:
'@mdx-js/mdx': 3.1.1
'@standard-schema/spec': 1.0.0
@@ -7510,12 +7634,33 @@ snapshots:
unist-util-visit: 5.0.0
zod: 4.1.5
optionalDependencies:
+ '@fumadocs/mdx-remote': 1.4.0(@types/react@19.1.12)(fumadocs-core@15.7.10(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)
next: 15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
vite: 7.1.5(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.5)
transitivePeerDependencies:
- supports-color
+ fumadocs-twoslash@3.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(fumadocs-ui@15.7.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2):
+ dependencies:
+ '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@shikijs/twoslash': 3.12.2(typescript@5.9.2)
+ fumadocs-ui: 15.7.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13)
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-gfm: 3.1.0
+ mdast-util-to-hast: 13.2.0
+ react: 19.1.1
+ shiki: 3.12.2
+ tailwind-merge: 3.3.1
+ twoslash: 0.3.4(typescript@5.9.2)
+ optionalDependencies:
+ '@types/react': 19.1.12
+ transitivePeerDependencies:
+ - '@types/react-dom'
+ - react-dom
+ - supports-color
+ - typescript
+
fumadocs-ui@15.7.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(next@15.5.2(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tailwindcss@4.1.13):
dependencies:
'@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -7618,6 +7763,13 @@ snapshots:
graphemer@1.4.0: {}
+ gray-matter@4.0.3:
+ dependencies:
+ js-yaml: 3.14.1
+ kind-of: 6.0.3
+ section-matter: 1.0.0
+ strip-bom-string: 1.0.0
+
has-flag@4.0.0: {}
hasown@2.0.2:
@@ -7802,6 +7954,8 @@ snapshots:
is-decimal@2.0.1: {}
+ is-extendable@0.1.1: {}
+
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
@@ -7912,6 +8066,8 @@ snapshots:
dependencies:
json-buffer: 3.0.1
+ kind-of@6.0.3: {}
+
levn@0.4.1:
dependencies:
prelude-ls: 1.2.1
@@ -8997,6 +9153,11 @@ snapshots:
dependencies:
compute-scroll-into-view: 3.1.1
+ section-matter@1.0.0:
+ dependencies:
+ extend-shallow: 2.0.1
+ kind-of: 6.0.3
+
semver@6.3.1: {}
semver@7.7.2: {}
@@ -9122,6 +9283,8 @@ snapshots:
dependencies:
ansi-regex: 6.2.0
+ strip-bom-string@1.0.0: {}
+
strip-bom@3.0.0: {}
strip-json-comments@3.1.1: {}
@@ -9334,6 +9497,16 @@ snapshots:
turbo-windows-64: 2.5.6
turbo-windows-arm64: 2.5.6
+ twoslash-protocol@0.3.4: {}
+
+ twoslash@0.3.4(typescript@5.9.2):
+ dependencies:
+ '@typescript/vfs': 1.6.1(typescript@5.9.2)
+ twoslash-protocol: 0.3.4
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1